js/src/doc/Debugger/Debugger-API.md

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 # The `Debugger` Interface
michael@0 2
michael@0 3 Mozilla's JavaScript engine, SpiderMonkey, provides a debugging interface
michael@0 4 named `Debugger` which lets JavaScript code observe and manipulate the
michael@0 5 execution of other JavaScript code. Both Firefox's built-in developer tools
michael@0 6 and the Firebug add-on use `Debugger` to implement their JavaScript
michael@0 7 debuggers. However, `Debugger` is quite general, and can be used to
michael@0 8 implement other kinds of tools like tracers, coverage analysis,
michael@0 9 patch-and-continue, and so on.
michael@0 10
michael@0 11 `Debugger` has three essential qualities:
michael@0 12
michael@0 13 - It is a *source level* interface: it operates in terms of the JavaScript
michael@0 14 language, not machine language. It operates on JavaScript objects, stack
michael@0 15 frames, environments, and code, and presents a consistent interface
michael@0 16 regardless of whether the debuggee is interpreted, compiled, or
michael@0 17 optimized. If you have a strong command of the JavaScript language, you
michael@0 18 should have all the background you need to use `Debugger` successfully,
michael@0 19 even if you have never looked into the language's implementation.
michael@0 20
michael@0 21 - It is for use *by JavaScript code*. JavaScript is both the debuggee
michael@0 22 language and the tool implementation language, so the qualities that make
michael@0 23 JavaScript effective on the web can be brought to bear in crafting tools
michael@0 24 for developers. As is expected of JavaScript APIs, `Debugger` is a
michael@0 25 *sound* interface: using (or even misusing) `Debugger` should never cause
michael@0 26 Gecko to crash. Errors throw proper JavaScript exceptions.
michael@0 27
michael@0 28 - It is an *intra-thread* debugging API. Both the debuggee and the code
michael@0 29 using `Debugger` to observe it must run in the same thread. Cross-thread,
michael@0 30 cross-process, and cross-device tools must use `Debugger` to observe the
michael@0 31 debuggee from within the same thread, and then handle any needed
michael@0 32 communication themselves. (Firefox's builtin tools have a
michael@0 33 [protocol][protocol] defined for this purpose.)
michael@0 34
michael@0 35 In Gecko, the `Debugger` API is available to chrome code only. By design,
michael@0 36 it ought not to introduce security holes, so in principle it could be made
michael@0 37 available to content as well; but it is hard to justify the security risks
michael@0 38 of the additional attack surface.
michael@0 39
michael@0 40
michael@0 41 ## Debugger Instances and Shadow Objects
michael@0 42
michael@0 43 `Debugger` reflects every aspect of the debuggee's state as a JavaScript
michael@0 44 value&mdash;not just actual JavaScript values like objects and primitives,
michael@0 45 but also stack frames, environments, scripts, and compilation units, which
michael@0 46 are not normally accessible as objects in their own right.
michael@0 47
michael@0 48 Here is a JavaScript program in the process of running a timer callback function:
michael@0 49
michael@0 50 ![A running JavaScript program and its Debugger shadows][img-shadows]
michael@0 51
michael@0 52 This diagram shows the various types of shadow objects that make up the
michael@0 53 Debugger API (which all follow some [general conventions][conventions]):
michael@0 54
michael@0 55 - A [`Debugger.Object`][object] represents a debuggee object, offering a
michael@0 56 reflection-oriented API that protects the debugger from accidentally
michael@0 57 invoking getters, setters, proxy traps, and so on.
michael@0 58
michael@0 59 - A [`Debugger.Script`][script] represents a block of JavaScript
michael@0 60 code&mdash;either a function body or a top-level script. Given a
michael@0 61 `Debugger.Script`, one can set breakpoints, translate between source
michael@0 62 positions and bytecode offsets (a deviation from the "source level"
michael@0 63 design principle), and find other static characteristics of the code.
michael@0 64
michael@0 65 - A [`Debugger.Frame`][frame] represents a running stack frame. You can use
michael@0 66 these to walk the stack and find each frame's script and environment. You
michael@0 67 can also set `onStep` and `onPop` handlers on frames.
michael@0 68
michael@0 69 - A [`Debugger.Environment`][environment] represents an environment,
michael@0 70 associating variable names with storage locations. Environments may
michael@0 71 belong to a running stack frame, captured by a function closure, or
michael@0 72 reflect some global object's properties as variables.
michael@0 73
michael@0 74 The [`Debugger`][debugger-object] instance itself is not really a shadow of
michael@0 75 anything in the debuggee; rather, it maintains the set of global objects
michael@0 76 which are to be considered debuggees. A `Debugger` observes only execution
michael@0 77 taking place in the scope of these global objects. You can set functions to
michael@0 78 be called when new stack frames are pushed; when new code is loaded; and so
michael@0 79 on.
michael@0 80
michael@0 81 Omitted from this picture are [`Debugger.Source`][source] instances, which
michael@0 82 represent JavaScript compilation units. A `Debugger.Source` can furnish a
michael@0 83 full copy of its source code, and explain how the code entered the system,
michael@0 84 whether via a call to `eval`, a `<script>` element, or otherwise. A
michael@0 85 `Debugger.Script` points to the `Debugger.Source` from which it is derived.
michael@0 86
michael@0 87 All these types follow some [general conventions][conventions], which you
michael@0 88 should look through before drilling down into any particular type's
michael@0 89 specification.
michael@0 90
michael@0 91 All shadow objects are unique per `Debugger` and per referent. For a given
michael@0 92 `Debugger`, there is exactly one `Debugger.Object` that refers to a
michael@0 93 particular debuggee object; exactly one `Debugger.Frame` for a particular
michael@0 94 stack frame; and so on. Thus, a tool can store metadata about a shadow's
michael@0 95 referent as a property on the shadow itself, and count on finding that
michael@0 96 metadata again if it comes across the same referent. And since shadows are
michael@0 97 per-`Debugger`, tools can do so without worrying about interfering with
michael@0 98 other tools that use their own `Debugger` instances.
michael@0 99
michael@0 100
michael@0 101 ## Example
michael@0 102
michael@0 103 You can try out `Debugger` yourself in Firefox's Scratchpad.
michael@0 104
michael@0 105 1) Visit the URL `about:config`, and set the `devtools.chrome.enabled`
michael@0 106 preference to `true`:
michael@0 107
michael@0 108 ![Setting the 'devtools.chrome.enabled' preference][img-chrome-pref]
michael@0 109
michael@0 110 2) Save the following HTML text to a file, and visit the file in your
michael@0 111 browser:
michael@0 112
michael@0 113 <div onclick="var x = 'snoo'; debugger;">Click me!</div>
michael@0 114
michael@0 115 3) Open a developer Scratchpad (Menu button > Developer > Scratchpad), and
michael@0 116 select "Browser" from the "Environment" menu. (This menu will not be
michael@0 117 present unless you have changed the preference as explained above.)
michael@0 118
michael@0 119 ![Selecting the 'browser' context in the Scratchpad][img-scratchpad-browser]
michael@0 120
michael@0 121 4) Enter the following code in the Scratchpad:
michael@0 122
michael@0 123 // This simply defines 'Debugger' in this Scratchpad;
michael@0 124 // it doesn't actually start debugging anything.
michael@0 125 Cu.import("resource://gre/modules/jsdebugger.jsm");
michael@0 126 addDebuggerToGlobal(window);
michael@0 127
michael@0 128 // Create a 'Debugger' instance.
michael@0 129 var dbg = new Debugger;
michael@0 130
michael@0 131 // Get the current tab's content window, and make it a debuggee.
michael@0 132 var w = gBrowser.selectedBrowser.contentWindow.wrappedJSObject;
michael@0 133 dbg.addDebuggee(w);
michael@0 134
michael@0 135 // When the debuggee executes a 'debugger' statement, evaluate
michael@0 136 // the expression 'x' in that stack frame, and show its value.
michael@0 137 dbg.onDebuggerStatement = function (frame) {
michael@0 138 alert('hit debugger statement; x = ' + frame.eval('x').return);
michael@0 139 }
michael@0 140
michael@0 141 5) In the Scratchpad, ensure that no text is selected, and press the "Run"
michael@0 142 button.
michael@0 143
michael@0 144 6) Now, click on the text that says "Click me!" in the web page. This runs
michael@0 145 the `div` element's `onclick` handler. When control reaches the
michael@0 146 `debugger;` statement, `Debugger` calls your callback function, passing
michael@0 147 a `Debugger.Frame` instance. Your callback function evaluates the
michael@0 148 expression `x` in the given stack frame, and displays the alert:
michael@0 149
michael@0 150 ![The Debugger callback displaying an alert][img-example-alert]
michael@0 151
michael@0 152 7) Press "Run" in the Scratchpad again. Now, clicking on the "Click me!"
michael@0 153 text causes *two* alerts to show&mdash;one for each `Debugger`
michael@0 154 instance.
michael@0 155
michael@0 156 Multiple `Debugger` instances can observe the same debuggee. Re-running
michael@0 157 the code in the Scratchpad created a fresh `Debugger` instance, added
michael@0 158 the same web page as its debuggee, and then registered a fresh
michael@0 159 `debugger;` statement handler with the new instance. When you clicked
michael@0 160 on the `div` element, both of them ran. This shows how any number of
michael@0 161 `Debugger`-based tools can observe a single web page
michael@0 162 simultaneously&mdash;although, since the order in which their handlers
michael@0 163 run is not specified, such tools should probably only observe, and not
michael@0 164 influence, the debuggee's behavior.
michael@0 165
michael@0 166 8) Close the web page and the Scratchpad.
michael@0 167
michael@0 168 Since both the Scratchpad's global object and the debuggee window are
michael@0 169 now gone, the `Debugger` instances will be garbage collected, since
michael@0 170 they can no longer have any visible effect on Firefox's behavior. The
michael@0 171 `Debugger` API tries to interact with garbage collection as
michael@0 172 transparently as possible; for example, if both a `Debugger.Object`
michael@0 173 instance and its referent are not reachable, they will both be
michael@0 174 collected, even while the `Debugger` instance to which the shadow
michael@0 175 belonged continues to exist.
michael@0 176
michael@0 177
michael@0 178 ## Gecko-specific features
michael@0 179
michael@0 180 While the `Debugger` core API deals only with concepts common to any
michael@0 181 JavaScript implementation, it also includes some Gecko-specific features:
michael@0 182
michael@0 183 - [Global tracking][global] supports debugging all the code running in a
michael@0 184 Gecko instance at once&mdash;the 'chrome debugging' model.
michael@0 185 - [Object wrapper][wrapper] functions help manipulate object references
michael@0 186 that cross privilege boundaries.

mercurial