Debugger is quite general, and can be used to implement other kinds of tools like tracers, coverage analysis, patch-and-continue, and so on.
Debugger has three essential qualities:
Debuggersuccessfully, even if you have never looked into the language’s implementation.
Debuggeris a sound interface: using (or even misusing)
- It is an intra-thread debugging API. Both the debuggee and the code using
Debuggerto observe it must run in the same thread. Cross-thread, cross-process, and cross-device tools must use
Debuggerto observe the debuggee from within the same thread, and then handle any needed communication themselves. (Firefox’s builtin tools have a protocol defined for this purpose.)
In Gecko, the
Debugger API is available to chrome code only. By design, it ought not to introduce security holes, so in principle it could be made available to content as well; but it is hard to justify the security risks of the additional attack surface.
Debugger Instances and Shadow Objects
This diagram shows the various types of shadow objects that make up the Debugger API (which all follow some general conventions):
Debugger.Objectrepresents a debuggee object, offering a reflection-oriented API that protects the debugger from accidentally invoking getters, setters, proxy traps, and so on.
Debugger.Script, one can set breakpoints, translate between source positions and bytecode offsets (a deviation from the “source level” design principle), and find other static characteristics of the code.
Debugger.Framerepresents a running stack frame. You can use these to walk the stack and find each frame’s script and environment. You can also set
onPophandlers on frames.
Debugger.Environmentrepresents an environment, associating variable names with storage locations. Environments may belong to a running stack frame, captured by a function closure, or reflect some global object’s properties as variables.
Debugger instance itself is not really a shadow of anything in the debuggee; rather, it maintains the set of global objects which are to be considered debuggees. A
Debugger observes only execution taking place in the scope of these global objects. You can set functions to be called when new stack frames are pushed; when new code is loaded; and so on.
Omitted from this picture are
Debugger.Source can furnish a full copy of its source code, and explain how the code entered the system, whether via a call to
<script> element, or otherwise. A
Debugger.Script points to the
Debugger.Source from which it is derived.
Also omitted is the
Debugger.Memory instance, which holds methods and accessors for observing the debuggee’s memory use.
All these types follow some general conventions, which you should look through before drilling down into any particular type’s specification.
All shadow objects are unique per
Debugger and per referent. For a given
Debugger, there is exactly one
Debugger.Object that refers to a particular debuggee object; exactly one
Debugger.Frame for a particular stack frame; and so on. Thus, a tool can store metadata about a shadow’s referent as a property on the shadow itself, and count on finding that metadata again if it comes across the same referent. And since shadows are per-
Debugger, tools can do so without worrying about interfering with other tools that use their own
Here are some things you can try out yourself that show off some of
- Evaluating an expression in a web page’s stack frame when it executes a
- Showing how many objects different call paths allocate.
- [Global tracking][global] supports debugging all the code running in a Gecko instance at once—the ‘chrome debugging’ model.
- [Object wrapper][wrapper] functions help manipulate object references that cross privilege boundaries.
- Generated from file: