Debugger.hx 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. /*
  2. * Copyright (C)2005-2019 Haxe Foundation
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20. * DEALINGS IN THE SOFTWARE.
  21. */
  22. package cpp.vm;
  23. /**
  24. Parameter describes a function parameter. Instances of this class are
  25. embedded in stack frame objects to describe the function parameters that
  26. were used in the invocation of the function that defines that stack frame.
  27. **/
  28. class Parameter {
  29. public var name(default, null):String;
  30. public var value(default, null):Dynamic;
  31. public function new(name:String, value:Dynamic) {
  32. this.name = name;
  33. this.value = value;
  34. }
  35. }
  36. /**
  37. `StackFrame` describes one call stack frame.
  38. **/
  39. class StackFrame {
  40. public var fileName(default, null):String;
  41. public var lineNumber(default, null):Int;
  42. public var className(default, null):String;
  43. public var functionName(default, null):String;
  44. public var parameters(default, null):Array<Parameter>;
  45. public function new(fileName:String, lineNumber:Int, className:String, functionName:String) {
  46. this.fileName = fileName;
  47. this.lineNumber = lineNumber;
  48. this.className = className;
  49. this.functionName = functionName;
  50. this.parameters = new Array<Parameter>();
  51. }
  52. }
  53. /**
  54. `ThreadInfo` describes the state of a single thread.
  55. **/
  56. class ThreadInfo {
  57. public static inline var STATUS_RUNNING = 1;
  58. public static inline var STATUS_STOPPED_BREAK_IMMEDIATE = 2;
  59. public static inline var STATUS_STOPPED_BREAKPOINT = 3;
  60. public static inline var STATUS_STOPPED_UNCAUGHT_EXCEPTION = 4;
  61. public static inline var STATUS_STOPPED_CRITICAL_ERROR = 5;
  62. /** 0 is never a valid thread number **/
  63. public var number(default, null):Int;
  64. public var status(default, null):Int;
  65. /** If status is "stopped breakpoint", this is the breakpoint number **/
  66. public var breakpoint(default, null):Int;
  67. /** If status is "critical error", this describes the error **/
  68. public var criticalErrorDescription(default, null):String;
  69. /** Stack will be listed with the lowest frame first **/
  70. public var stack(default, null):Array<StackFrame>;
  71. public function new(number:Int, status:Int, breakpoint:Int = -1, criticalErrorDescription:String = null) {
  72. this.number = number;
  73. this.status = status;
  74. this.breakpoint = breakpoint;
  75. this.criticalErrorDescription = criticalErrorDescription;
  76. this.stack = new Array<StackFrame>();
  77. }
  78. }
  79. /**
  80. This class wraps the hxcpp C++ implementation to provide a Haxe interface
  81. to the low level debugging features
  82. **/
  83. class Debugger {
  84. public static inline var THREAD_CREATED = 1;
  85. public static inline var THREAD_TERMINATED = 2;
  86. public static inline var THREAD_STARTED = 3;
  87. public static inline var THREAD_STOPPED = 4;
  88. public static inline var STEP_INTO = 1;
  89. public static inline var STEP_OVER = 2;
  90. public static inline var STEP_OUT = 3;
  91. /**
  92. This tagging value is returned by `getStackVariableValue()` and
  93. `setStackVariableValue()` if the requested value does not exist at the
  94. requested stack frame
  95. **/
  96. public static var NONEXISTENT_VALUE = "NONEXISTENT_VALUE";
  97. /**
  98. This tagging value is returned by `getStackVariableValue()` and
  99. `setStackVariableValue()` if the stack variable that is being set is on a
  100. thread that is running, in which case the set does not take place.
  101. **/
  102. public static var THREAD_NOT_STOPPED = "THREAD_NOT_STOPPED";
  103. /**
  104. Sets the handler callback to be made when asynchronous events occur,
  105. specifically, when threads are created, terminated, started, or
  106. stopped. The calling thread becomes the "debugger" thread, which means
  107. that it will be discluded from any breakpoints and will not be reported
  108. on by any thread reporting requests.
  109. Be aware that this callback is made asynchronously and possibly by
  110. multiple threads simultaneously.
  111. Setting this to `null` prevents further callbacks.
  112. Throws a string exception if the program does not support debugging
  113. because it was not compiled with the `HXCPP_DEBUGGER` flag set.
  114. @param handler is a function that will be called back by asynchronous
  115. thread events. Note that this function is called directly from
  116. the thread experiencing the event and the handler should return
  117. quickly to avoid blocking the calling thread unnecessarily.
  118. The parameters to handler are:
  119. - `threadNumber`, the thread number of the event
  120. - event, one of `THREAD_CREATED`, `THREAD_TERMINATED`,
  121. `THREAD_STARTED`, or `THREAD_STOPPED`
  122. - stackFrame, the stack frame number at which the thread is stopped,
  123. undefined if event is not `THREAD_STOPPED`
  124. - `className`, the class name at which the thread is stopped,
  125. undefined if event is not `THREAD_STOPPED`
  126. - `functionName`, the function name at which the thread is
  127. stopped, undefined if event is not `THREAD_STOPPED`
  128. - `fileName`, the file name at which the thread is stopped,
  129. undefined if event is not `THREAD_STOPPED`
  130. - `lineNumber`, the line number at which the thread is stopped,
  131. undefined if event is not `THREAD_STOPPED`
  132. **/
  133. public static function setEventNotificationHandler(handler:(threadNumber:Int, event:Int, stackFrame:Int, className:String, functionName:String,
  134. fileName:String, lineNumber:Int) -> Void) {
  135. untyped __global__.__hxcpp_dbg_setEventNotificationHandler(handler);
  136. }
  137. /**
  138. This can be called to turn off (and then back on) all stopping of
  139. debugged threads temporarily. It should only be used by classes that
  140. actually implement the debugger to hide themselves from the debugger as
  141. necessary.
  142. **/
  143. public static function enableCurrentThreadDebugging(enabled:Bool) {
  144. untyped __global__.__hxcpp_dbg_enableCurrentThreadDebugging(enabled);
  145. }
  146. /**
  147. Returns the thread number of the calling thread.
  148. @return the thread number of the calling thread.
  149. **/
  150. public static function getCurrentThreadNumber():Int {
  151. return untyped __global__.__hxcpp_dbg_getCurrentThreadNumber();
  152. }
  153. /**
  154. Returns the set of source files known to the debugger. This is a copy
  155. of the original array and could be quite large. The caller should
  156. cache this value to avoid multiple copies needing to be made.
  157. @return the set of source files known to the debugger.
  158. **/
  159. public static function getFiles():Array<String> {
  160. return untyped __global__.__hxcpp_dbg_getFiles();
  161. }
  162. /**
  163. Returns the full paths of the set of source files known to the debugger.
  164. This is a copy of the original array and could be quite large.
  165. It is possible that this set will be empty, in which case the full paths are not known.
  166. The index of these files matches the index from `getFiles()`, so the full path for
  167. a given short path can be calculated.
  168. @return the known full paths of the set of source files
  169. **/
  170. public static function getFilesFullPath():Array<String> {
  171. return untyped __global__.__hxcpp_dbg_getFilesFullPath();
  172. }
  173. /**
  174. Returns the set of class names of all classes known to the debugger.
  175. This is a copy of the original array and could be quite large. The
  176. caller should cache this value to avoid multiple copies needing to be
  177. made.
  178. @return the set of class names of all classes known to the debugger.
  179. **/
  180. public static function getClasses():Array<String> {
  181. return untyped __global__.__hxcpp_dbg_getClasses();
  182. }
  183. /**
  184. Returns a `ThreadInfo` object describing every thread that existed at the
  185. moment that the call was made, except for the debugger thread.
  186. **/
  187. public static function getThreadInfos():Array<ThreadInfo> {
  188. return untyped __global__.__hxcpp_dbg_getThreadInfos();
  189. }
  190. /**
  191. Returns a `ThreadInfo` object describing a single thread, or `null` if
  192. there is no such thread or the thread queried about was the debugger
  193. thread and `unsafe` was not `true`.
  194. **/
  195. public static function getThreadInfo(threadNumber:Int, unsafe:Bool):ThreadInfo {
  196. return untyped __global__.__hxcpp_dbg_getThreadInfo(threadNumber, unsafe);
  197. }
  198. /**
  199. Adds a new `file:line` breakpoint. The breakpoint number of the newly
  200. added breakpoint is returned.
  201. **/
  202. public static function addFileLineBreakpoint(file:String, line:Int):Int {
  203. return untyped __global__.__hxcpp_dbg_addFileLineBreakpoint(file, line);
  204. }
  205. /**
  206. Adds a new `class:function` breakpoint. The breakpoint number of the
  207. newly added breakpoint is returned.
  208. **/
  209. public static function addClassFunctionBreakpoint(className:String, functionName:String):Int {
  210. return untyped __global__.__hxcpp_dbg_addClassFunctionBreakpoint(className, functionName);
  211. }
  212. /**
  213. Deletes a breakpoint, or all breakpoints.
  214. **/
  215. public static function deleteBreakpoint(number:Null<Int>) {
  216. if (number == null) {
  217. untyped __global__.__hxcpp_dbg_deleteAllBreakpoints();
  218. } else {
  219. untyped __global__.__hxcpp_dbg_deleteBreakpoint(cast(number, Int));
  220. }
  221. }
  222. /**
  223. Breaks all threads except the debugger thread (which should be the same
  224. as the calling thread!).
  225. If `wait` is `true`, waits up to 2 seconds for all threads to be broken.
  226. Threads which are in blocking system calls and cannot break after 2
  227. seconds remain running when this function returns.
  228. **/
  229. public static function breakNow(wait:Bool = true) {
  230. untyped __global__.__hxcpp_dbg_breakNow(wait);
  231. }
  232. /**
  233. Continue execution of all stopped threads. If `specialThreadNumber`
  234. is a valid thread number, then it will be continued past
  235. `continueCount` breakpoints instead of just 1 like all of the other
  236. threads.
  237. **/
  238. public static function continueThreads(specialThreadNumber:Int, continueCount:Int) {
  239. untyped __global__.__hxcpp_dbg_continueThreads(specialThreadNumber, continueCount);
  240. }
  241. /**
  242. Single steps the given thread.
  243. **/
  244. public static function stepThread(threadNumber:Int, stepType:Int, stepCount:Int = 1) {
  245. untyped __global__.__hxcpp_dbg_stepThread(threadNumber, stepType, stepCount);
  246. }
  247. /**
  248. Returns the list of local variables (including `this`, function
  249. arguments, and local variables) visible to the given thread at the
  250. given stack frame.
  251. Returns a list with a single entry, `THREAD_NOT_STOPPED`, if the
  252. thread is not stopped and thus variables cannot be fetched and
  253. `unsafe` is not `true`.
  254. @return the list of local variables (including `this`, function
  255. arguments, and local variables) visible to the given thread at
  256. the given stack frame.
  257. **/
  258. public static function getStackVariables(threadNumber:Int, stackFrameNumber:Int, unsafe:Bool):Array<String> {
  259. return untyped __global__.__hxcpp_dbg_getStackVariables(threadNumber, stackFrameNumber, unsafe, THREAD_NOT_STOPPED);
  260. }
  261. /**
  262. Returns the value of a stack variable, or `NONEXISTENT_VALUE` if the
  263. requested value does not exist. If the thread is actively running
  264. and `unsafe` is not `true`, returns `THREAD_NOT_STOPPED`.
  265. **/
  266. public static function getStackVariableValue(threadNumber:Int, stackFrameNumber:Int, name:String, unsafe:Bool):Dynamic {
  267. return untyped __global__.__hxcpp_dbg_getStackVariableValue(threadNumber, stackFrameNumber, name, unsafe, NONEXISTENT_VALUE, THREAD_NOT_STOPPED);
  268. }
  269. /**
  270. Sets the value of a stack variable and returns that value. If the
  271. variable does not exist, on the stack, this function returns
  272. `NONEXISTENT_VALUE`. If the thread is actively running and `unsafe` is not
  273. `true`, returns `THREAD_NOT_STOPPED`, and the value is not set.
  274. **/
  275. public static function setStackVariableValue(threadNumber:Int, stackFrameNumber:Int, name:String, value:Dynamic, unsafe:Bool):Dynamic {
  276. return untyped __global__.__hxcpp_dbg_setStackVariableValue(threadNumber, stackFrameNumber, name, value, unsafe, NONEXISTENT_VALUE,
  277. THREAD_NOT_STOPPED);
  278. }
  279. // The hxcpp runtime calls back through these functions to create Haxe
  280. // objects as needed, which allows the C++ implementation code to create
  281. // Haxe objects without having to actually know the structure of those
  282. // objects
  283. private static function __init__() {
  284. untyped __global__.__hxcpp_dbg_setNewParameterFunction(function(name:String, value:Dynamic):Dynamic {
  285. return new Parameter(name, value);
  286. });
  287. untyped __global__.__hxcpp_dbg_setNewStackFrameFunction(function(fileName:String, lineNumber:Int, className:String, functionName:String) {
  288. return new StackFrame(fileName, lineNumber, className, functionName);
  289. });
  290. untyped __global__.__hxcpp_dbg_setNewThreadInfoFunction(function(number:Int, status:Int, breakpoint:Int, criticalErrorDescription:String):Dynamic {
  291. return new ThreadInfo(number, status, breakpoint, criticalErrorDescription);
  292. });
  293. untyped __global__.__hxcpp_dbg_setAddParameterToStackFrameFunction(function(inStackFrame:Dynamic, inParameter:Dynamic) {
  294. var stackFrame:StackFrame = cast inStackFrame;
  295. var parameter:Parameter = cast inParameter;
  296. stackFrame.parameters.push(parameter);
  297. });
  298. untyped __global__.__hxcpp_dbg_setAddStackFrameToThreadInfoFunction(function(inThreadInfo:Dynamic, inStackFrame:Dynamic) {
  299. var threadInfo:ThreadInfo = cast inThreadInfo;
  300. var stackFrame:StackFrame = cast inStackFrame;
  301. threadInfo.stack.push(stackFrame);
  302. });
  303. }
  304. }