|
@@ -21,90 +21,382 @@
|
|
|
*/
|
|
|
package cpp.vm;
|
|
|
|
|
|
-import haxe.CallStack;
|
|
|
|
|
|
-class Debugger
|
|
|
+/**
|
|
|
+ * Parameter describes a function parameter. Instances of this class are
|
|
|
+ * embedded in stack frame objects to describe the function parameters that
|
|
|
+ * were used in the invocation of the function that defines that stack frame.
|
|
|
+ **/
|
|
|
+class Parameter
|
|
|
{
|
|
|
- public static inline var BRK_THIS = -2;
|
|
|
- public static inline var BRK_TERMINATE = -1;
|
|
|
-
|
|
|
- public static inline var BRK_NONE = 0;
|
|
|
- public static inline var BRK_ASAP = 1;
|
|
|
- public static inline var BRK_STEP = 2;
|
|
|
- public static inline var BRK_ENTER = 3;
|
|
|
- public static inline var BRK_LEAVE = 4;
|
|
|
+ public var name(default, null) : String;
|
|
|
+ public var value(default, null) : Dynamic;
|
|
|
|
|
|
- public static function setHandler(inHandler:Void->Void)
|
|
|
+ public function new(name : String, value : Dynamic)
|
|
|
{
|
|
|
- untyped __global__.__hxcpp_dbg_set_handler(inHandler);
|
|
|
+ this.name = name;
|
|
|
+ this.value = value;
|
|
|
}
|
|
|
-
|
|
|
- public static function setThread(?inDebugThread:Thread)
|
|
|
- {
|
|
|
- untyped __global__.__hxcpp_dbg_set_thread(inDebugThread==null?Thread.current().handle:inDebugThread.handle);
|
|
|
}
|
|
|
|
|
|
-
|
|
|
- // Generate a handler callback ASAP
|
|
|
- public static function setBreak(inMode:Int)
|
|
|
+/**
|
|
|
+ * StackFrame describes one call stack frame.
|
|
|
+ **/
|
|
|
+class StackFrame
|
|
|
{
|
|
|
- untyped __global__.__hxcpp_dbg_set_break(inMode);
|
|
|
- }
|
|
|
+ public var fileName(default, null) : String;
|
|
|
+ public var lineNumber(default, null) : Int;
|
|
|
+ public var className(default, null) : String;
|
|
|
+ public var functionName(default, null) : String;
|
|
|
+ public var parameters(default, null) : Array<Parameter>;
|
|
|
|
|
|
- public static function exit()
|
|
|
+ public function new(fileName : String, lineNumber : Int,
|
|
|
+ className : String, functionName : String)
|
|
|
{
|
|
|
- untyped __global__.__hxcpp_dbg_set_break(BRK_TERMINATE);
|
|
|
+ this.fileName = fileName;
|
|
|
+ this.lineNumber = lineNumber;
|
|
|
+ this.className = className;
|
|
|
+ this.functionName = functionName;
|
|
|
+ this.parameters = new Array<Parameter>();
|
|
|
}
|
|
|
- public static function breakBad()
|
|
|
- {
|
|
|
- untyped __global__.__hxcpp_dbg_set_break(BRK_THIS);
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * ThreadInfo describes the state of a single thread.
|
|
|
+ **/
|
|
|
+class ThreadInfo
|
|
|
+ {
|
|
|
+ public static inline var STATUS_RUNNING = 1;
|
|
|
+ public static inline var STATUS_STOPPED_BREAK_IMMEDIATE = 2;
|
|
|
+ public static inline var STATUS_STOPPED_BREAKPOINT = 3;
|
|
|
+ public static inline var STATUS_STOPPED_UNCAUGHT_EXCEPTION = 4;
|
|
|
+ public static inline var STATUS_STOPPED_CRITICAL_ERROR = 5;
|
|
|
|
|
|
+ // 0 is never a valid thread number
|
|
|
+ public var number(default, null) : Int;
|
|
|
+ public var status(default, null) : Int;
|
|
|
+ // If status is "stopped breakpoint", this is the breakpoint number
|
|
|
+ public var breakpoint(default, null) : Int;
|
|
|
+ // If status is "critical error", this describes the error
|
|
|
+ public var criticalErrorDescription(default, null) : String;
|
|
|
+ // Stack will be listed with the lowest frame first
|
|
|
+ public var stack(default, null) : Array<StackFrame>;
|
|
|
|
|
|
- // Breakpoint
|
|
|
- public static function addBreakpoint(inFileId:Int, inLine:Int)
|
|
|
+ public function new(number : Int, status : Int, breakpoint : Int = -1,
|
|
|
+ criticalErrorDescription : String = null)
|
|
|
{
|
|
|
- untyped __global__.__hxcpp_breakpoints_add(inFileId, inLine);
|
|
|
+ this.number = number;
|
|
|
+ this.status = status;
|
|
|
+ this.breakpoint = breakpoint;
|
|
|
+ this.criticalErrorDescription = criticalErrorDescription;
|
|
|
+ this.stack = new Array<StackFrame>();
|
|
|
}
|
|
|
-
|
|
|
- public static function getBreakpoints() : Array<String>
|
|
|
- {
|
|
|
- return untyped __global__.__hxcpp_dbg_breakpoints_get();
|
|
|
}
|
|
|
|
|
|
- public static function deleteBreakpoint(inI:Int)
|
|
|
+/**
|
|
|
+ * This class wraps the hxcpp C++ implementation to provide a Haxe interface
|
|
|
+ * to the low level debugging features
|
|
|
+ **/
|
|
|
+class Debugger
|
|
|
{
|
|
|
- untyped __global__.__hxcpp_dbg_breakpoints_delete(inI);
|
|
|
- }
|
|
|
+ public static inline var THREAD_CREATED = 1;
|
|
|
+ public static inline var THREAD_TERMINATED = 2;
|
|
|
+ public static inline var THREAD_STARTED = 3;
|
|
|
+ public static inline var THREAD_STOPPED = 4;
|
|
|
|
|
|
- // Thread - todo
|
|
|
- // public static function suspendAll()
|
|
|
+ public static inline var STEP_INTO = 1;
|
|
|
+ public static inline var STEP_OVER = 2;
|
|
|
+ public static inline var STEP_OUT = 3;
|
|
|
|
|
|
- // Callstack
|
|
|
- public static function getStackFrames() : Array<haxe.StackItem>
|
|
|
- {
|
|
|
- return untyped __global__.__hxcpp_dbg_stack_frames_get();
|
|
|
- }
|
|
|
+ // This tagging value is returned by getStackVariableValue() and
|
|
|
+ // setStackVariableValue if the requested value does not exist at the
|
|
|
+ // requested stack frame
|
|
|
+ public static var NONEXISTENT_VALUE = new String("NONEXISTENT_VALUE");
|
|
|
+ // This tagging value is returned by getStackVariableValue and
|
|
|
+ // setStackVariableValue if the stack variable that is being set is on a
|
|
|
+ // thread that is running, in which case the set does not take place.
|
|
|
+ public static var THREAD_NOT_STOPPED = new String("THREAD_NOT_STOPPED");
|
|
|
|
|
|
- public static function getStackVars(inFrame:Int) : Array<String>
|
|
|
- {
|
|
|
- return untyped __global__.__hxcpp_dbg_get_stack_vars(inFrame);
|
|
|
- }
|
|
|
+ /**
|
|
|
+ * Sets the handler callback to be made when asynchronous events occur,
|
|
|
+ * specifically, when threads are created, terminated, started, or
|
|
|
+ * stopped. The calling thread becomes the "debugger" thread, which means
|
|
|
+ * that it will be discluded from any breakpoints and will not be reported
|
|
|
+ * on by any thread reporting requests.
|
|
|
+ *
|
|
|
+ * Be aware that this callback is made asynchronously and possibly by
|
|
|
+ * multiple threads simultaneously.
|
|
|
+ *
|
|
|
+ * Setting this to null prevents further callbacks.
|
|
|
+ *
|
|
|
+ * Throws a string exception if the program does not support debugging
|
|
|
+ * because it was not compiled with the HXCPP_DEBUGGER flag set.
|
|
|
+ *
|
|
|
+ * @param handler is a function that will be called back by asynchronous
|
|
|
+ * thread events. Note that this function is called directly from
|
|
|
+ * the thread experiencing the event and the handler should return
|
|
|
+ * quickly to avoid blocking the calling thread unnecessarily.
|
|
|
+ * The paramaters to handler are:
|
|
|
+ * - threadNumber, the thread number of the event
|
|
|
+ * - event, one of THREAD_CREATED, THREAD_TERMINATED,
|
|
|
+ * THREAD_STARTED, or THREAD_STOPPED
|
|
|
+ * - className, the class name at which the thread is stopped,
|
|
|
+ * undefined if event is not THREAD_STOPPED
|
|
|
+ * - functionName, the function name at which the thread is
|
|
|
+ * stopped, undefined if event is not THREAD_STOPPED
|
|
|
+ * - fileName, the file name at which the thread is stopped,
|
|
|
+ * undefined if event is not THREAD_STOPPED
|
|
|
+ * - lineNumber, the line number at which the thread is stopped,
|
|
|
+ * undefined if event is not THREAD_STOPPED
|
|
|
+ **/
|
|
|
+ public static function setEventNotificationHandler(
|
|
|
+ handler : Int -> Int -> String -> String -> String -> Int -> Void)
|
|
|
+ {
|
|
|
+ untyped __global__.__hxcpp_dbg_setEventNotificationHandler(handler);
|
|
|
+ }
|
|
|
|
|
|
- public static function getStackVar(inFrame:Int,inVar:String) : Dynamic
|
|
|
- {
|
|
|
- return untyped __global__.__hxcpp_dbg_get_stack_var(inFrame,inVar);
|
|
|
- }
|
|
|
+ /**
|
|
|
+ * This can be called to turn off (and then back on) all stopping of
|
|
|
+ * debugged threads temporarily. It should only be used by classes that
|
|
|
+ * actually implement the debugger to hide themselves from the debugger as
|
|
|
+ * necessary.
|
|
|
+ **/
|
|
|
+ public static function enableCurrentThreadDebugging(enabled : Bool)
|
|
|
+ {
|
|
|
+ untyped __global__.__hxcpp_dbg_enableCurrentThreadDebugging(enabled);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Returns the thread number of the calling thread.
|
|
|
+ *
|
|
|
+ * @return the thread number of the calling thread.
|
|
|
+ **/
|
|
|
+ public static function getCurrentThreadNumber() : Int
|
|
|
+ {
|
|
|
+ return untyped __global__.__hxcpp_dbg_getCurrentThreadNumber();
|
|
|
+ }
|
|
|
|
|
|
- public static function setStackVar(inFrame:Int,inVar:String, inValue:Dynamic)
|
|
|
+ /**
|
|
|
+ * Returns the set of source files known to the debugger. This is a copy
|
|
|
+ * of the original array and could be quite large. The caller should
|
|
|
+ * cache this value to avoid multiple copies needing to be made.
|
|
|
+ *
|
|
|
+ * @return the set of source files known to the debugger.
|
|
|
+ **/
|
|
|
+ public static function getFiles() : Array<String>
|
|
|
{
|
|
|
- untyped __global__.__hxcpp_dbg_set_stack_var(inFrame,inVar,inValue);
|
|
|
+ return untyped __global__.__hxcpp_dbg_getFiles();
|
|
|
}
|
|
|
|
|
|
- public static function getFiles() : Array<String>
|
|
|
- {
|
|
|
- return untyped __global__.__hxcpp_dbg_get_files();
|
|
|
+ /**
|
|
|
+ * Returns the set of class names of all classes known to the debugger.
|
|
|
+ * This is a copy of the original array and could be quite large. The
|
|
|
+ * caller should cache this value to avoid multiple copies needing to be
|
|
|
+ * made.
|
|
|
+ *
|
|
|
+ * @return the set of class names of all classes known to the debugger.
|
|
|
+ **/
|
|
|
+ public static function getClasses() : Array<String>
|
|
|
+ {
|
|
|
+ return untyped __global__.__hxcpp_dbg_getClasses();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Returns a ThreadInfo object describing every thread that existed at the
|
|
|
+ * moment that the call was made, except for the debugger thread.
|
|
|
+ **/
|
|
|
+ public static function getThreadInfos() : Array<ThreadInfo>
|
|
|
+ {
|
|
|
+ return untyped __global__.__hxcpp_dbg_getThreadInfos();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Returns a ThreadInfo object describing a single thread, or null if
|
|
|
+ * there is no such thread or the thread queried about was the debugger
|
|
|
+ * thread and unsafe was not true.
|
|
|
+ **/
|
|
|
+ public static function getThreadInfo(threadNumber : Int,
|
|
|
+ unsafe : Bool) : ThreadInfo
|
|
|
+ {
|
|
|
+ return untyped __global__.__hxcpp_dbg_getThreadInfo
|
|
|
+ (threadNumber, unsafe);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Adds a new file:line breakpoint. The breakpoint number of the newly
|
|
|
+ * added breakpoint is returned.
|
|
|
+ **/
|
|
|
+ public static function addFileLineBreakpoint(file : String,
|
|
|
+ line : Int) : Int
|
|
|
+ {
|
|
|
+ return untyped __global__.__hxcpp_dbg_addFileLineBreakpoint
|
|
|
+ (file, line);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Adds a new class:function breakpoint. The breakpoint number of the
|
|
|
+ * newly added breakpoint is returned.
|
|
|
+ **/
|
|
|
+ public static function addClassFunctionBreakpoint(className : String,
|
|
|
+ functionName : String) : Int
|
|
|
+ {
|
|
|
+ return untyped __global__.__hxcpp_dbg_addClassFunctionBreakpoint
|
|
|
+ (className, functionName);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Deletes a breakpoint, or all breakpoints.
|
|
|
+ **/
|
|
|
+ public static function deleteBreakpoint(number : Null<Int>)
|
|
|
+ {
|
|
|
+ if (number == null) {
|
|
|
+ untyped __global__.__hxcpp_dbg_deleteAllBreakpoints();
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ untyped __global__.__hxcpp_dbg_deleteBreakpoint
|
|
|
+ (cast (number, Int));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Breaks all threads except the debugger thread (which should be the same
|
|
|
+ * as the calling thread!).
|
|
|
+ *
|
|
|
+ * If [wait] is true, waits up to 2 seconds for all threads to be broken.
|
|
|
+ * Threads which are in blocking system calls and cannot break after 2
|
|
|
+ * seconds remain running when this function returns.
|
|
|
+ **/
|
|
|
+ public static function breakNow(wait : Bool = true)
|
|
|
+ {
|
|
|
+ untyped __global__.__hxcpp_dbg_breakNow(wait);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Continue execution of all stopped threads. If specialThreadNumber
|
|
|
+ * is a valid thread number, then it will be continued past
|
|
|
+ * [continueCount] breakpoints instead of just 1 like all of the other
|
|
|
+ * threads.
|
|
|
+ **/
|
|
|
+ public static function continueThreads(specialThreadNumber : Int,
|
|
|
+ continueCount : Int)
|
|
|
+ {
|
|
|
+ untyped __global__.__hxcpp_dbg_continueThreads
|
|
|
+ (specialThreadNumber, continueCount);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Single steps the given thread.
|
|
|
+ **/
|
|
|
+ public static function stepThread(threadNumber : Int,
|
|
|
+ stepType : Int,
|
|
|
+ stepCount : Int = 1)
|
|
|
+ {
|
|
|
+ untyped __global__.__hxcpp_dbg_stepThread
|
|
|
+ (threadNumber, stepType, stepCount);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Returns the list of local variables (including "this", function
|
|
|
+ * arguments, and local variables) visible to the given thread at the
|
|
|
+ * given stack frame.
|
|
|
+ *
|
|
|
+ * Returns a list with a single entry, THREAD_NOT_STOPPED, if the
|
|
|
+ * thread is not stopped and thus variables cannot be fetched and
|
|
|
+ * unsafe is not true.
|
|
|
+ *
|
|
|
+ * @return the list of local variables (including "this", function
|
|
|
+ * arguments, and local variables) visible to the given thread at
|
|
|
+ * the given stack frame.
|
|
|
+ **/
|
|
|
+ public static function getStackVariables(threadNumber : Int,
|
|
|
+ stackFrameNumber : Int,
|
|
|
+ unsafe : Bool) : Array<String>
|
|
|
+ {
|
|
|
+ return untyped __global__.__hxcpp_dbg_getStackVariables
|
|
|
+ (threadNumber, stackFrameNumber, unsafe, THREAD_NOT_STOPPED);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Returns the value of a stack variable, or NONEXISTENT_VALUE if the
|
|
|
+ * requested value does not exist. If the thread is actively running
|
|
|
+ * and unsafe is not true, returns THREAD_NOT_STOPPED.
|
|
|
+ **/
|
|
|
+ public static function getStackVariableValue(threadNumber : Int,
|
|
|
+ stackFrameNumber : Int,
|
|
|
+ name : String,
|
|
|
+ unsafe : Bool) : Dynamic
|
|
|
+ {
|
|
|
+ return untyped __global__.__hxcpp_dbg_getStackVariableValue
|
|
|
+ (threadNumber, stackFrameNumber, name, unsafe, NONEXISTENT_VALUE,
|
|
|
+ THREAD_NOT_STOPPED);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Sets the value of a stack variable and returns that value. If the
|
|
|
+ * variable does not exist, on the stack, this function returns
|
|
|
+ * NONEXISTENT_VALUE. If the thread is actively running and unsafe is not
|
|
|
+ * true, returns THREAD_NOT_STOPPED, and the value is not set.
|
|
|
+ **/
|
|
|
+ public static function setStackVariableValue(threadNumber : Int,
|
|
|
+ stackFrameNumber : Int,
|
|
|
+ name : String,
|
|
|
+ value : Dynamic,
|
|
|
+ unsafe : Bool) : Dynamic
|
|
|
+ {
|
|
|
+ return untyped __global__.__hxcpp_dbg_setStackVariableValue
|
|
|
+ (threadNumber, stackFrameNumber, name, value, unsafe,
|
|
|
+ NONEXISTENT_VALUE, THREAD_NOT_STOPPED);
|
|
|
+ }
|
|
|
+
|
|
|
+ // The hxcpp runtime calls back through these functions to create Haxe
|
|
|
+ // objects as needed, which allows the C++ implementation code to create
|
|
|
+ // Haxe objects without having to actually know the structure of those
|
|
|
+ // objects
|
|
|
+ private static function __init__()
|
|
|
+ {
|
|
|
+ untyped __global__.__hxcpp_dbg_setNewParameterFunction
|
|
|
+ (
|
|
|
+ function (name : String, value : Dynamic) : Dynamic {
|
|
|
+ return new Parameter(name, value);
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+ untyped __global__.__hxcpp_dbg_setNewStackFrameFunction
|
|
|
+ (
|
|
|
+ function (fileName : String, lineNumber : Int,
|
|
|
+ className : String, functionName : String)
|
|
|
+ {
|
|
|
+ return new StackFrame(fileName, lineNumber,
|
|
|
+ className, functionName);
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+ untyped __global__.__hxcpp_dbg_setNewThreadInfoFunction
|
|
|
+ (
|
|
|
+ function (number : Int, status : Int, breakpoint : Int,
|
|
|
+ criticalErrorDescription : String) : Dynamic {
|
|
|
+ return new ThreadInfo(number, status, breakpoint,
|
|
|
+ criticalErrorDescription);
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+ untyped __global__.__hxcpp_dbg_setAddParameterToStackFrameFunction
|
|
|
+ (
|
|
|
+ function(inStackFrame : Dynamic, inParameter : Dynamic) {
|
|
|
+ var stackFrame : StackFrame = cast inStackFrame;
|
|
|
+ var parameter : Parameter = cast inParameter;
|
|
|
+ stackFrame.parameters.push(parameter);
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+ untyped __global__.__hxcpp_dbg_setAddStackFrameToThreadInfoFunction
|
|
|
+ (
|
|
|
+ function(inThreadInfo : Dynamic, inStackFrame : Dynamic) {
|
|
|
+ var threadInfo : ThreadInfo = cast inThreadInfo;
|
|
|
+ var stackFrame : StackFrame = cast inStackFrame;
|
|
|
+ threadInfo.stack.push(stackFrame);
|
|
|
+ }
|
|
|
+ );
|
|
|
}
|
|
|
}
|
|
|
|