diff --git a/src/debug/org/luaj/debug/AbortException.java b/src/debug/org/luaj/debug/AbortException.java index 2e26ded2..5cbc9eab 100644 --- a/src/debug/org/luaj/debug/AbortException.java +++ b/src/debug/org/luaj/debug/AbortException.java @@ -21,6 +21,10 @@ ******************************************************************************/ package org.luaj.debug; +/** + * AbortException is thrown by DebugLuaState to abort the VM execution on request + * of the debugger client. + */ public class AbortException extends RuntimeException { private static final long serialVersionUID = 8043724992294286647L; diff --git a/src/debug/org/luaj/debug/DebugLuaState.java b/src/debug/org/luaj/debug/DebugLuaState.java index 4d7f2510..73511ed1 100644 --- a/src/debug/org/luaj/debug/DebugLuaState.java +++ b/src/debug/org/luaj/debug/DebugLuaState.java @@ -43,11 +43,11 @@ import org.luaj.debug.response.DebugResponseSimple; import org.luaj.debug.response.DebugResponseVariables; import org.luaj.vm.CallInfo; import org.luaj.vm.LClosure; +import org.luaj.vm.LPrototype; import org.luaj.vm.LTable; import org.luaj.vm.LValue; import org.luaj.vm.LocVars; import org.luaj.vm.Lua; -import org.luaj.vm.LPrototype; import org.luaj.vm.LuaState; @@ -66,13 +66,12 @@ public class DebugLuaState extends LuaState implements DebugRequestListener { protected Hashtable breakpoints = new Hashtable(); protected boolean exiting = false; protected boolean suspended = false; - protected boolean bSuspendAtStart = false; + protected boolean bSuspendOnStart = false; protected int lastline = -1; protected String lastSource; protected DebugSupport debugSupport; - public DebugLuaState() { - } + public DebugLuaState() {} public void setDebugSupport(DebugSupport debugSupport) throws IOException { @@ -86,7 +85,7 @@ public class DebugLuaState extends LuaState implements DebugRequestListener { } public void setSuspendAtStart(boolean bSuspendAtStart) { - this.bSuspendAtStart = bSuspendAtStart; + this.bSuspendOnStart = bSuspendAtStart; } protected void debugAssert(boolean b) { @@ -172,7 +171,7 @@ public class DebugLuaState extends LuaState implements DebugRequestListener { } synchronized (this) { - while (bSuspendAtStart) { + while (bSuspendOnStart) { try { this.wait(); } catch (InterruptedException e) { @@ -287,6 +286,11 @@ public class DebugLuaState extends LuaState implements DebugRequestListener { return line; } + /** + * Returns the current program counter for the given call frame. + * @param ci -- A call frame + * @return the current program counter for the given call frame. + */ private int getCurrentPc(CallInfo ci) { int pc = (ci != calls[cc] ? ci.pc - 1 : ci.pc); return pc; @@ -308,7 +312,7 @@ public class DebugLuaState extends LuaState implements DebugRequestListener { if (DebugRequestType.start == requestType) { DebugEvent event = new DebugEvent(DebugEventType.started); debugSupport.notifyDebugEvent(event); - setStarted(); + cancelSuspendOnStart(); return DebugResponseSimple.SUCCESS; } else if (DebugRequestType.exit == requestType) { stop(); @@ -377,10 +381,15 @@ public class DebugLuaState extends LuaState implements DebugRequestListener { } } - protected void setStarted() { + /** + * If the VM is suspended on start, this method resumes the execution. + */ + protected void cancelSuspendOnStart() { synchronized (this) { - bSuspendAtStart = false; - this.notify(); + if (bSuspendOnStart) { + bSuspendOnStart = false; + this.notify(); + } } } @@ -395,6 +404,10 @@ public class DebugLuaState extends LuaState implements DebugRequestListener { } } + /** + * Stops the debugging communication with the debug client and terminate the + * VM execution. + */ public void stop() { if (this.debugSupport == null) { throw new IllegalStateException( @@ -427,8 +440,7 @@ public class DebugLuaState extends LuaState implements DebugRequestListener { /** * set breakpoint at line N * - * @param N - * the line to set the breakpoint at + * @param N -- the line to set the breakpoint at */ public void setBreakpoint(String source, int lineNumber) { String fileName = DebugUtils.getSourceFileName(source); @@ -501,6 +513,13 @@ public class DebugLuaState extends LuaState implements DebugRequestListener { return result; } + /** + * Check if the current LPrototype is lexically defined in the caller scope. + * @param p -- current LPrototype + * @param ci -- caller info + * @return true if the current LPrototype is lexically defined in the + * caller scope; false, otherwise. + */ protected boolean isInScope(LPrototype p, CallInfo ci) { LPrototype[] enclosingProtos = ci.closure.p.p; boolean bFound = false; @@ -534,9 +553,18 @@ public class DebugLuaState extends LuaState implements DebugRequestListener { return result; } + /** + * Debugging Utility. Dumps the variables for a given call frame. + * @param index Index of the call frame + */ private void dumpStack(int index) { + if (index < 0 || index > cc) return; + CallInfo callInfo = calls[index]; - LocVars[] localVariables = callInfo.closure.p.locvars; + LPrototype prototype = callInfo.closure.p; + LocVars[] localVariables = prototype.locvars; + DebugUtils.println("Stack Frame: " + index + " [" + base + "," + top + "], # of localvars: " + localVariables.length + ", pc=" + callInfo.pc); + int pc = getCurrentPc(callInfo); for (int i = 0; i < localVariables.length; i++) { if (!isActiveVariable(pc, localVariables[i])) { @@ -545,8 +573,21 @@ public class DebugLuaState extends LuaState implements DebugRequestListener { DebugUtils.println("localvars["+i+"]=" + localVariables[i].varname.toJavaString()); } } + + int base = callInfo.base; + int top = callInfo.top < callInfo.base ? callInfo.base+1 : callInfo.top; + for (int i = base; i < top; i++){ + DebugUtils.println("stack[" + i + "]=" + stack[i]); + } } + /** + * Returns the name of the Nth variable in scope of the call info. + * @param callInfo Call info + * @param index Index of the variable + * @return the name of the Nth variable in scope of the call info. If the + * variable for the given index is not found, null is returned. + */ private String getVariable(CallInfo callInfo, int index) { int count = -1; LocVars[] localVariables = callInfo.closure.p.locvars; @@ -565,24 +606,30 @@ public class DebugLuaState extends LuaState implements DebugRequestListener { return null; } + /** + * Check if a variable is in scope. + * @param pc -- Current program counter. + * @param localVariable -- A local variable. + * @return true if the variable is active under the given program counter; + * false, otherwise. + */ private boolean isActiveVariable(int pc, LocVars localVariable) { return pc >= localVariable.startpc && pc <= localVariable.endpc; } + /** + * Adds the active variables for the given call frame to the list of variables. + * @param variables -- the list of active variables. + * @param variablesSeen -- variables already seen so far + * @param index -- index of the call frame + */ private void addVariables(Vector variables, Hashtable variablesSeen, int index) { CallInfo callInfo = calls[index]; - LPrototype prototype = callInfo.closure.p; int base = callInfo.base; int top = callInfo.top < callInfo.base ? callInfo.base+1 : callInfo.top; if (DebugUtils.IS_DEBUG) { - DebugUtils.println("Stack Frame: " + index + " [" + base + "," + top + "], # of localvars: " + prototype.locvars.length + ", pc=" + callInfo.pc); - for (int i = 0; i < prototype.locvars.length; i++) { - DebugUtils.println("localvars[" + i + "]: " + prototype.locvars[i].varname + "(" + prototype.locvars[i].startpc + "," + prototype.locvars[i].endpc + ")"); - } - for (int i = base; i < top; i++){ - DebugUtils.println("stack[" + i + "]=" + stack[i]); - } + dumpStack(index); } int selectedVariableCount = 0; @@ -649,7 +696,7 @@ public class DebugLuaState extends LuaState implements DebugRequestListener { } /** - * step a single statement + * step to the next statement */ public void stepInto() { synchronized (this) { @@ -660,7 +707,7 @@ public class DebugLuaState extends LuaState implements DebugRequestListener { } /** - * return from the method call + * return from the current method call */ public void stepReturn() { synchronized (this) { diff --git a/src/debug/org/luaj/debug/DebugSupport.java b/src/debug/org/luaj/debug/DebugSupport.java index 0c1917c3..75a775d6 100644 --- a/src/debug/org/luaj/debug/DebugSupport.java +++ b/src/debug/org/luaj/debug/DebugSupport.java @@ -11,50 +11,52 @@ import org.luaj.debug.request.DebugRequest; import org.luaj.debug.request.DebugRequestListener; import org.luaj.debug.response.DebugResponse; - +/** + * DebugSupport provides the network communication support for the debugger and + * debugee. + */ public class DebugSupport implements DebugRequestListener, DebugEventListener { - protected static final int UNKNOWN = 0; - protected static final int RUNNING = 1; - protected static final int STOPPED = 2; + protected static final int UNKNOWN = 0; + protected static final int RUNNING = 1; + protected static final int STOPPED = 2; protected DebugLuaState vm; protected int requestPort; protected int eventPort; protected Thread requestWatcherThread; protected int state = UNKNOWN; - protected DataInputStream requestReader; protected DataOutputStream requestWriter; protected DataOutputStream eventWriter; - - public DebugSupport(int requestPort, - int eventPort) { - if (requestPort == -1) { - throw new IllegalArgumentException("requestPort is invalid"); - } - - if (eventPort == -1) { - throw new IllegalArgumentException("eventPort is invalid"); - } - + + public DebugSupport(int requestPort, int eventPort) { + if (requestPort == -1) { + throw new IllegalArgumentException("requestPort is invalid"); + } + + if (eventPort == -1) { + throw new IllegalArgumentException("eventPort is invalid"); + } + this.requestPort = requestPort; this.eventPort = eventPort; } - + public void setDebugStackState(DebugLuaState vm) { this.vm = vm; } - + protected void dispose() { - if (DebugUtils.IS_DEBUG) - DebugUtils.println("releasing the networkig resources..."); - + if (DebugUtils.IS_DEBUG) + DebugUtils.println("releasing the networkig resources..."); + if (requestReader != null) { try { requestReader.close(); - } catch (IOException e) {} + } catch (IOException e) { + } } - + if (requestWriter != null) { try { requestWriter.close(); @@ -62,28 +64,26 @@ public class DebugSupport implements DebugRequestListener, DebugEventListener { e.printStackTrace(); } } - + if (eventWriter != null) { try { eventWriter.close(); } catch (IOException e) { e.printStackTrace(); } - } + } } public synchronized boolean isStarted() { - return (state == RUNNING || state == STOPPED); + return (state == RUNNING || state == STOPPED); } - - /* (non-Javadoc) - * @see lua.debug.j2se.DebugSupport#start() - */ + public synchronized void start() throws IOException { - if (this.vm == null) { - throw new IllegalStateException("DebugStackState is not set. Please call setDebugStackState first."); - } - + if (this.vm == null) { + throw new IllegalStateException( + "DebugStackState is not set. Please call setDebugStackState first."); + } + this.requestWatcherThread = new Thread(new Runnable() { public void run() { loopForRequests(); @@ -92,53 +92,52 @@ public class DebugSupport implements DebugRequestListener, DebugEventListener { }); this.requestWatcherThread.start(); this.state = RUNNING; - - System.out.println("LuaJ debug server is started on ports: " + requestPort + ", " + eventPort); + + System.out.println("LuaJ debug server is started on ports: " + + requestPort + ", " + eventPort); } - + protected synchronized int getState() { return this.state; } - - /* (non-Javadoc) - * @see lua.debug.j2se.DebugSupport#stop() - */ + public synchronized void stop() { - if (DebugUtils.IS_DEBUG) - DebugUtils.println("stopping the debug support..."); + if (DebugUtils.IS_DEBUG) + DebugUtils.println("stopping the debug support..."); this.state = STOPPED; } - - protected void loopForRequests() { + + protected void loopForRequests() { try { while (getState() != STOPPED) { - int size = requestReader.readInt(); - byte[] data = new byte[size]; - requestReader.readFully(data); - DebugRequest request - = (DebugRequest) SerializationHelper.deserialize(data); - if (DebugUtils.IS_DEBUG) - DebugUtils.println("SERVER receives request: " + request.toString()); - + int size = requestReader.readInt(); + byte[] data = new byte[size]; + requestReader.readFully(data); + DebugRequest request = (DebugRequest) SerializationHelper + .deserialize(data); + if (DebugUtils.IS_DEBUG) + DebugUtils.println("SERVER receives request: " + + request.toString()); + DebugResponse response = handleRequest(request); data = SerializationHelper.serialize(response); requestWriter.writeInt(data.length); requestWriter.write(data); requestWriter.flush(); - if (DebugUtils.IS_DEBUG) - DebugUtils.println("SERVER sends response: " + response); - } + if (DebugUtils.IS_DEBUG) + DebugUtils.println("SERVER sends response: " + response); + } } catch (EOFException e) { - // expected during shutdown + // expected during shutdown } catch (Exception e) { e.printStackTrace(); } } private void cleanup() { - if (DebugUtils.IS_DEBUG) - DebugUtils.println("SERVER terminated..."); - + if (DebugUtils.IS_DEBUG) + DebugUtils.println("SERVER terminated..."); + dispose(); System.exit(0); } @@ -148,54 +147,49 @@ public class DebugSupport implements DebugRequestListener, DebugEventListener { * client. The server can send events via this channel to notify the client * about debug events (see below) asynchronously. * - * The following events can be fired: - * 1. started -- the vm is started and ready to receive debugging requests - * (guaranteed to be the first event sent) - * 2. terminated -- the vm is terminated (guaranteed to be the last event sent) - * 3. suspended client|step|breakpoint N - * -- the vm is suspended by client, due to a stepping request or - * the breakpoint at line N is hit - * 4. resumed client|step - * -- the vm resumes execution by client or step - * + * The following events can be fired: 1. started -- the vm is started and + * ready to receive debugging requests (guaranteed to be the first event + * sent) 2. terminated -- the vm is terminated (guaranteed to be the last + * event sent) 3. suspended client|step|breakpoint N -- the vm is suspended + * by client, due to a stepping request or the breakpoint at line N is hit + * 4. resumed client|step -- the vm resumes execution by client or step + * * @param event */ protected void sendEvent(DebugEvent event) { - if (DebugUtils.IS_DEBUG) - DebugUtils.println("SERVER sending event: " + event.toString()); - + if (DebugUtils.IS_DEBUG) + DebugUtils.println("SERVER sending event: " + event.toString()); + try { - byte[] data = SerializationHelper.serialize(event); + byte[] data = SerializationHelper.serialize(event); eventWriter.writeInt(data.length); eventWriter.write(data); eventWriter.flush(); } catch (IOException e) { e.printStackTrace(); - } + } } - /* (non-Javadoc) - * @see lua.debug.DebugEventListener#notifyDebugEvent(lua.debug.DebugEvent) + /* + * (non-Javadoc) + * + * @see org.luaj.debug.event.DebugEventListener#notifyDebugEvent(org.luaj.debug.event.DebugEvent) */ - /* (non-Javadoc) - * @see lua.debug.j2se.DebugSupport#notifyDebugEvent(lua.debug.event.DebugEvent) - */ public void notifyDebugEvent(DebugEvent event) { - sendEvent(event); + sendEvent(event); } - /* (non-Javadoc) - * @see lua.debug.DebugRequestListener#handleRequest(java.lang.String) + /* + * (non-Javadoc) + * + * @see org.luaj.debug.request.DebugRequestListener#handleRequest(org.luaj.debug.request.DebugRequest) */ - /* (non-Javadoc) - * @see lua.debug.j2se.DebugSupport#handleRequest(lua.debug.request.DebugRequest) - */ - public DebugResponse handleRequest(DebugRequest request) { - if (DebugUtils.IS_DEBUG) { - DebugUtils.println("handling request: " + request.toString()); - } - - DebugResponse response = vm.handleRequest(request); - return response; + public DebugResponse handleRequest(DebugRequest request) { + if (DebugUtils.IS_DEBUG) { + DebugUtils.println("handling request: " + request.toString()); + } + + DebugResponse response = vm.handleRequest(request); + return response; } } \ No newline at end of file diff --git a/src/debug/org/luaj/debug/DebugUtils.java b/src/debug/org/luaj/debug/DebugUtils.java index bacce020..0e9f9cee 100644 --- a/src/debug/org/luaj/debug/DebugUtils.java +++ b/src/debug/org/luaj/debug/DebugUtils.java @@ -26,7 +26,7 @@ import org.luaj.vm.LoadState; public class DebugUtils { - public static final boolean IS_DEBUG = false; + public static final boolean IS_DEBUG = (null != System.getProperty("TRACE")); public static void println(String message) { if (IS_DEBUG) {