1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/doc/Debugger/Debugger-API.md Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,186 @@ 1.4 +# The `Debugger` Interface 1.5 + 1.6 +Mozilla's JavaScript engine, SpiderMonkey, provides a debugging interface 1.7 +named `Debugger` which lets JavaScript code observe and manipulate the 1.8 +execution of other JavaScript code. Both Firefox's built-in developer tools 1.9 +and the Firebug add-on use `Debugger` to implement their JavaScript 1.10 +debuggers. However, `Debugger` is quite general, and can be used to 1.11 +implement other kinds of tools like tracers, coverage analysis, 1.12 +patch-and-continue, and so on. 1.13 + 1.14 +`Debugger` has three essential qualities: 1.15 + 1.16 +- It is a *source level* interface: it operates in terms of the JavaScript 1.17 + language, not machine language. It operates on JavaScript objects, stack 1.18 + frames, environments, and code, and presents a consistent interface 1.19 + regardless of whether the debuggee is interpreted, compiled, or 1.20 + optimized. If you have a strong command of the JavaScript language, you 1.21 + should have all the background you need to use `Debugger` successfully, 1.22 + even if you have never looked into the language's implementation. 1.23 + 1.24 +- It is for use *by JavaScript code*. JavaScript is both the debuggee 1.25 + language and the tool implementation language, so the qualities that make 1.26 + JavaScript effective on the web can be brought to bear in crafting tools 1.27 + for developers. As is expected of JavaScript APIs, `Debugger` is a 1.28 + *sound* interface: using (or even misusing) `Debugger` should never cause 1.29 + Gecko to crash. Errors throw proper JavaScript exceptions. 1.30 + 1.31 +- It is an *intra-thread* debugging API. Both the debuggee and the code 1.32 + using `Debugger` to observe it must run in the same thread. Cross-thread, 1.33 + cross-process, and cross-device tools must use `Debugger` to observe the 1.34 + debuggee from within the same thread, and then handle any needed 1.35 + communication themselves. (Firefox's builtin tools have a 1.36 + [protocol][protocol] defined for this purpose.) 1.37 + 1.38 +In Gecko, the `Debugger` API is available to chrome code only. By design, 1.39 +it ought not to introduce security holes, so in principle it could be made 1.40 +available to content as well; but it is hard to justify the security risks 1.41 +of the additional attack surface. 1.42 + 1.43 + 1.44 +## Debugger Instances and Shadow Objects 1.45 + 1.46 +`Debugger` reflects every aspect of the debuggee's state as a JavaScript 1.47 +value—not just actual JavaScript values like objects and primitives, 1.48 +but also stack frames, environments, scripts, and compilation units, which 1.49 +are not normally accessible as objects in their own right. 1.50 + 1.51 +Here is a JavaScript program in the process of running a timer callback function: 1.52 + 1.53 +![A running JavaScript program and its Debugger shadows][img-shadows] 1.54 + 1.55 +This diagram shows the various types of shadow objects that make up the 1.56 +Debugger API (which all follow some [general conventions][conventions]): 1.57 + 1.58 +- A [`Debugger.Object`][object] represents a debuggee object, offering a 1.59 + reflection-oriented API that protects the debugger from accidentally 1.60 + invoking getters, setters, proxy traps, and so on. 1.61 + 1.62 +- A [`Debugger.Script`][script] represents a block of JavaScript 1.63 + code—either a function body or a top-level script. Given a 1.64 + `Debugger.Script`, one can set breakpoints, translate between source 1.65 + positions and bytecode offsets (a deviation from the "source level" 1.66 + design principle), and find other static characteristics of the code. 1.67 + 1.68 +- A [`Debugger.Frame`][frame] represents a running stack frame. You can use 1.69 + these to walk the stack and find each frame's script and environment. You 1.70 + can also set `onStep` and `onPop` handlers on frames. 1.71 + 1.72 +- A [`Debugger.Environment`][environment] represents an environment, 1.73 + associating variable names with storage locations. Environments may 1.74 + belong to a running stack frame, captured by a function closure, or 1.75 + reflect some global object's properties as variables. 1.76 + 1.77 +The [`Debugger`][debugger-object] instance itself is not really a shadow of 1.78 +anything in the debuggee; rather, it maintains the set of global objects 1.79 +which are to be considered debuggees. A `Debugger` observes only execution 1.80 +taking place in the scope of these global objects. You can set functions to 1.81 +be called when new stack frames are pushed; when new code is loaded; and so 1.82 +on. 1.83 + 1.84 +Omitted from this picture are [`Debugger.Source`][source] instances, which 1.85 +represent JavaScript compilation units. A `Debugger.Source` can furnish a 1.86 +full copy of its source code, and explain how the code entered the system, 1.87 +whether via a call to `eval`, a `<script>` element, or otherwise. A 1.88 +`Debugger.Script` points to the `Debugger.Source` from which it is derived. 1.89 + 1.90 +All these types follow some [general conventions][conventions], which you 1.91 +should look through before drilling down into any particular type's 1.92 +specification. 1.93 + 1.94 +All shadow objects are unique per `Debugger` and per referent. For a given 1.95 +`Debugger`, there is exactly one `Debugger.Object` that refers to a 1.96 +particular debuggee object; exactly one `Debugger.Frame` for a particular 1.97 +stack frame; and so on. Thus, a tool can store metadata about a shadow's 1.98 +referent as a property on the shadow itself, and count on finding that 1.99 +metadata again if it comes across the same referent. And since shadows are 1.100 +per-`Debugger`, tools can do so without worrying about interfering with 1.101 +other tools that use their own `Debugger` instances. 1.102 + 1.103 + 1.104 +## Example 1.105 + 1.106 +You can try out `Debugger` yourself in Firefox's Scratchpad. 1.107 + 1.108 +1) Visit the URL `about:config`, and set the `devtools.chrome.enabled` 1.109 + preference to `true`: 1.110 + 1.111 + ![Setting the 'devtools.chrome.enabled' preference][img-chrome-pref] 1.112 + 1.113 +2) Save the following HTML text to a file, and visit the file in your 1.114 + browser: 1.115 + 1.116 + <div onclick="var x = 'snoo'; debugger;">Click me!</div> 1.117 + 1.118 +3) Open a developer Scratchpad (Menu button > Developer > Scratchpad), and 1.119 + select "Browser" from the "Environment" menu. (This menu will not be 1.120 + present unless you have changed the preference as explained above.) 1.121 + 1.122 + ![Selecting the 'browser' context in the Scratchpad][img-scratchpad-browser] 1.123 + 1.124 +4) Enter the following code in the Scratchpad: 1.125 + 1.126 + // This simply defines 'Debugger' in this Scratchpad; 1.127 + // it doesn't actually start debugging anything. 1.128 + Cu.import("resource://gre/modules/jsdebugger.jsm"); 1.129 + addDebuggerToGlobal(window); 1.130 + 1.131 + // Create a 'Debugger' instance. 1.132 + var dbg = new Debugger; 1.133 + 1.134 + // Get the current tab's content window, and make it a debuggee. 1.135 + var w = gBrowser.selectedBrowser.contentWindow.wrappedJSObject; 1.136 + dbg.addDebuggee(w); 1.137 + 1.138 + // When the debuggee executes a 'debugger' statement, evaluate 1.139 + // the expression 'x' in that stack frame, and show its value. 1.140 + dbg.onDebuggerStatement = function (frame) { 1.141 + alert('hit debugger statement; x = ' + frame.eval('x').return); 1.142 + } 1.143 + 1.144 +5) In the Scratchpad, ensure that no text is selected, and press the "Run" 1.145 + button. 1.146 + 1.147 +6) Now, click on the text that says "Click me!" in the web page. This runs 1.148 + the `div` element's `onclick` handler. When control reaches the 1.149 + `debugger;` statement, `Debugger` calls your callback function, passing 1.150 + a `Debugger.Frame` instance. Your callback function evaluates the 1.151 + expression `x` in the given stack frame, and displays the alert: 1.152 + 1.153 + ![The Debugger callback displaying an alert][img-example-alert] 1.154 + 1.155 +7) Press "Run" in the Scratchpad again. Now, clicking on the "Click me!" 1.156 + text causes *two* alerts to show—one for each `Debugger` 1.157 + instance. 1.158 + 1.159 + Multiple `Debugger` instances can observe the same debuggee. Re-running 1.160 + the code in the Scratchpad created a fresh `Debugger` instance, added 1.161 + the same web page as its debuggee, and then registered a fresh 1.162 + `debugger;` statement handler with the new instance. When you clicked 1.163 + on the `div` element, both of them ran. This shows how any number of 1.164 + `Debugger`-based tools can observe a single web page 1.165 + simultaneously—although, since the order in which their handlers 1.166 + run is not specified, such tools should probably only observe, and not 1.167 + influence, the debuggee's behavior. 1.168 + 1.169 +8) Close the web page and the Scratchpad. 1.170 + 1.171 + Since both the Scratchpad's global object and the debuggee window are 1.172 + now gone, the `Debugger` instances will be garbage collected, since 1.173 + they can no longer have any visible effect on Firefox's behavior. The 1.174 + `Debugger` API tries to interact with garbage collection as 1.175 + transparently as possible; for example, if both a `Debugger.Object` 1.176 + instance and its referent are not reachable, they will both be 1.177 + collected, even while the `Debugger` instance to which the shadow 1.178 + belonged continues to exist. 1.179 + 1.180 + 1.181 +## Gecko-specific features 1.182 + 1.183 +While the `Debugger` core API deals only with concepts common to any 1.184 +JavaScript implementation, it also includes some Gecko-specific features: 1.185 + 1.186 +- [Global tracking][global] supports debugging all the code running in a 1.187 + Gecko instance at once—the 'chrome debugging' model. 1.188 +- [Object wrapper][wrapper] functions help manipulate object references 1.189 + that cross privilege boundaries.