michael@0: # The `Debugger` Interface michael@0: michael@0: Mozilla's JavaScript engine, SpiderMonkey, provides a debugging interface michael@0: named `Debugger` which lets JavaScript code observe and manipulate the michael@0: execution of other JavaScript code. Both Firefox's built-in developer tools michael@0: and the Firebug add-on use `Debugger` to implement their JavaScript michael@0: debuggers. However, `Debugger` is quite general, and can be used to michael@0: implement other kinds of tools like tracers, coverage analysis, michael@0: patch-and-continue, and so on. michael@0: michael@0: `Debugger` has three essential qualities: michael@0: michael@0: - It is a *source level* interface: it operates in terms of the JavaScript michael@0: language, not machine language. It operates on JavaScript objects, stack michael@0: frames, environments, and code, and presents a consistent interface michael@0: regardless of whether the debuggee is interpreted, compiled, or michael@0: optimized. If you have a strong command of the JavaScript language, you michael@0: should have all the background you need to use `Debugger` successfully, michael@0: even if you have never looked into the language's implementation. michael@0: michael@0: - It is for use *by JavaScript code*. JavaScript is both the debuggee michael@0: language and the tool implementation language, so the qualities that make michael@0: JavaScript effective on the web can be brought to bear in crafting tools michael@0: for developers. As is expected of JavaScript APIs, `Debugger` is a michael@0: *sound* interface: using (or even misusing) `Debugger` should never cause michael@0: Gecko to crash. Errors throw proper JavaScript exceptions. michael@0: michael@0: - It is an *intra-thread* debugging API. Both the debuggee and the code michael@0: using `Debugger` to observe it must run in the same thread. Cross-thread, michael@0: cross-process, and cross-device tools must use `Debugger` to observe the michael@0: debuggee from within the same thread, and then handle any needed michael@0: communication themselves. (Firefox's builtin tools have a michael@0: [protocol][protocol] defined for this purpose.) michael@0: michael@0: In Gecko, the `Debugger` API is available to chrome code only. By design, michael@0: it ought not to introduce security holes, so in principle it could be made michael@0: available to content as well; but it is hard to justify the security risks michael@0: of the additional attack surface. michael@0: michael@0: michael@0: ## Debugger Instances and Shadow Objects michael@0: michael@0: `Debugger` reflects every aspect of the debuggee's state as a JavaScript michael@0: value—not just actual JavaScript values like objects and primitives, michael@0: but also stack frames, environments, scripts, and compilation units, which michael@0: are not normally accessible as objects in their own right. michael@0: michael@0: Here is a JavaScript program in the process of running a timer callback function: michael@0: michael@0: ![A running JavaScript program and its Debugger shadows][img-shadows] michael@0: michael@0: This diagram shows the various types of shadow objects that make up the michael@0: Debugger API (which all follow some [general conventions][conventions]): michael@0: michael@0: - A [`Debugger.Object`][object] represents a debuggee object, offering a michael@0: reflection-oriented API that protects the debugger from accidentally michael@0: invoking getters, setters, proxy traps, and so on. michael@0: michael@0: - A [`Debugger.Script`][script] represents a block of JavaScript michael@0: code—either a function body or a top-level script. Given a michael@0: `Debugger.Script`, one can set breakpoints, translate between source michael@0: positions and bytecode offsets (a deviation from the "source level" michael@0: design principle), and find other static characteristics of the code. michael@0: michael@0: - A [`Debugger.Frame`][frame] represents a running stack frame. You can use michael@0: these to walk the stack and find each frame's script and environment. You michael@0: can also set `onStep` and `onPop` handlers on frames. michael@0: michael@0: - A [`Debugger.Environment`][environment] represents an environment, michael@0: associating variable names with storage locations. Environments may michael@0: belong to a running stack frame, captured by a function closure, or michael@0: reflect some global object's properties as variables. michael@0: michael@0: The [`Debugger`][debugger-object] instance itself is not really a shadow of michael@0: anything in the debuggee; rather, it maintains the set of global objects michael@0: which are to be considered debuggees. A `Debugger` observes only execution michael@0: taking place in the scope of these global objects. You can set functions to michael@0: be called when new stack frames are pushed; when new code is loaded; and so michael@0: on. michael@0: michael@0: Omitted from this picture are [`Debugger.Source`][source] instances, which michael@0: represent JavaScript compilation units. A `Debugger.Source` can furnish a michael@0: full copy of its source code, and explain how the code entered the system, michael@0: whether via a call to `eval`, a `