michael@0: # The Debugger Object michael@0: michael@0: When called as a constructor, the `Debugger` object creates a new michael@0: `Debugger` instance. michael@0: michael@0: new Debugger([global, ...]) michael@0: : Create a debugger object, and apply its [`addDebuggee`][add] method to michael@0: each of the given global objects to add them as the initial michael@0: debuggees. michael@0: michael@0: ## Accessor Properties of the Debugger Prototype Object michael@0: michael@0: A `Debugger` instance inherits the following accessor properties from michael@0: its prototype: michael@0: michael@0: `enabled` michael@0: : A boolean value indicating whether this `Debugger` instance's handlers, michael@0: breakpoints, watchpoints, and the like are currently enabled. It is an michael@0: accessor property with a getter and setter: assigning to it enables or michael@0: disables this `Debugger` instance; reading it produces true if the michael@0: instance is enabled, or false otherwise. This property is initially michael@0: `true` in a freshly created `Debugger` instance. michael@0: michael@0: This property gives debugger code a single point of control for michael@0: disentangling itself from the debuggee, regardless of what sort of michael@0: events or handlers or "points" we add to the interface. michael@0: michael@0: `uncaughtExceptionHook` michael@0: : Either `null` or a function that SpiderMonkey calls when a call to a michael@0: debug event handler, breakpoint handler, watchpoint handler, or similar michael@0: function throws some exception, which we refer to as michael@0: debugger-exception here. Exceptions thrown in the debugger are michael@0: not propagated to debuggee code; instead, SpiderMonkey calls this michael@0: function, passing debugger-exception as its sole argument and michael@0: the `Debugger` instance as the `this` value. This function should michael@0: return a [resumption value][rv], which determines how the debuggee michael@0: should continue. michael@0: michael@0: If the uncaught exception hook itself throws an exception, michael@0: uncaught-hook-exception, SpiderMonkey throws a new error object, michael@0: confess-to-debuggee-exception, to the debuggee whose message michael@0: blames the debugger, and includes textual descriptions of michael@0: uncaught-hook-exception and the original michael@0: debugger-exception. michael@0: michael@0: If `uncaughtExceptionHook`'s value is `null`, SpiderMonkey throws an michael@0: exception to the debuggee whose message blames the debugger, and michael@0: includes a textual description of debugger-exception. michael@0: michael@0: Assigning anything other than a callable value or `null` to this michael@0: property throws a `TypeError` exception. michael@0: michael@0: (This is not an ideal way to handle debugger bugs, but the hope here is michael@0: that some sort of backstop, even if imperfect, will make life easier for michael@0: debugger developers. For example, an uncaught exception hook may have michael@0: access to browser-level features like the `alert` function, which this michael@0: API's implementation does not, making it possible to present debugger michael@0: errors to the developer in a way suited to the context.) michael@0: michael@0: michael@0: ## Debugger Handler Functions michael@0: michael@0: Each `Debugger` instance inherits accessor properties with which you can michael@0: store handler functions for SpiderMonkey to call when given events occur michael@0: in debuggee code. michael@0: michael@0: When one of the events described below occurs in debuggee code, the engine michael@0: pauses the debuggee and calls the corresponding debugging handler on each michael@0: `Debugger` instance that is observing the debuggee. The handler functions michael@0: receive the `Debugger` instance as their `this` value. Most handler michael@0: functions can return a [resumption value][rv] indicating how the debuggee's michael@0: execution should proceed. michael@0: michael@0: On a new `Debugger` instance, each of these properties is initially michael@0: `undefined`. Any value assigned to a debugging handler must be either a michael@0: function or `undefined`; otherwise a `TypeError` is thrown. michael@0: michael@0: Handler functions run in the same thread in which the event occurred. michael@0: They run in the compartment to which they belong, not in a debuggee michael@0: compartment. michael@0: michael@0: onNewScript(script, global) michael@0: : New code, represented by the [`Debugger.Script`][script] instance michael@0: script, has been loaded in the scope of the debuggee global michael@0: object global. global is a [`Debugger.Object`][object] michael@0: instance whose referent is the global object. michael@0: michael@0: This method's return value is ignored. michael@0: michael@0: onDebuggerStatement(frame) michael@0: : Debuggee code has executed a debugger statement in frame. michael@0: This method should return a [resumption value][rv] specifying how the michael@0: debuggee's execution should proceed. michael@0: michael@0: onEnterFrame(frame) michael@0: : The stack frame frame is about to begin executing code. michael@0: (Naturally, frame is currently the youngest michael@0: [visible frame][vf].) This method should return michael@0: a [resumption value][rv] specifying how the debuggee's execution should michael@0: proceed. michael@0: michael@0: SpiderMonkey only calls `onEnterFrame` to report michael@0: [visible][vf], non-`"debugger"` frames. michael@0: michael@0: onThrow(frame, value) (future plan) michael@0: : The exception value is being thrown by frame, which is michael@0: running debuggee code. This method should return a michael@0: [resumption value][rv] specifying how the debuggee's execution should michael@0: proceed. If it returns `undefined`, the exception is thrown as normal. michael@0: michael@0: A call to the `onThrow` handler is typically followed by one or more michael@0: calls to the `onExceptionUnwind` handler. michael@0: michael@0: *(pending discussion)* If the debuggee executes michael@0: `try { throw 0; } finally { f(); }` and `f()` executes without error, michael@0: the `onThrow` handler is called only once. The debugger is not notified michael@0: when the exception is set aside in order to execute the `finally` block, michael@0: nor when it is restored after the `finally` block completes normally. michael@0: michael@0: *(An alternative design here would be: onException(status, frame, value) michael@0: where status is one of the strings "throw", "unwind", "catch", michael@0: "finally", "rethrow". JS\_SaveExceptionState would trigger a "finally" michael@0: event, JS\_RestoreExceptionState would trigger a "rethrow", michael@0: JS\_ClearPendingException would trigger a "catch"; not sure what michael@0: JS\_DropExceptionState or a return/throw from a finally block should michael@0: do.)* michael@0: michael@0: onExceptionUnwind(frame, value) michael@0: : The exception value has been thrown, and has propagated to michael@0: frame; frame is the youngest remaining stack frame, and is a michael@0: debuggee frame. This method should return a [resumption value][rv] michael@0: specifying how the debuggee's execution should proceed. If it returns michael@0: `undefined`, the exception continues to propagate as normal: if control in michael@0: `frame` is in a `try` block, control jumps to the corresponding `catch` or michael@0: `finally` block; otherwise, frame is popped, and the exception michael@0: propagates to frame's caller. michael@0: michael@0: When an exception's propagation causes control to enter a `finally` michael@0: block, the exception is temporarily set aside. If the `finally` block michael@0: finishes normally, the exception resumes propagation, and the debugger's michael@0: `onExceptionUnwind` handler is called again, in the same frame. (The michael@0: other possibility is for the `finally` block to exit due to a `return`, michael@0: `continue`, or `break` statement, or a new exception. In those cases the michael@0: old exception does not continue to propagate; it is discarded.) michael@0: michael@0: sourceHandler(ASuffusionOfYellow) michael@0: : This method is never called. If it is ever called, a contradiction has michael@0: been proven, and the debugger is free to assume that everything is true. michael@0: michael@0: onError(frame, report) michael@0: : SpiderMonkey is about to report an error in frame. Report michael@0: is an object describing the error, with the following properties: michael@0: michael@0: `message` michael@0: : The fully formatted error message. michael@0: michael@0: `file` michael@0: : If present, the source file name, URL, etc. (If this property is michael@0: present, the line property will be too, and vice versa.) michael@0: michael@0: `line` michael@0: : If present, the source line number at which the error occurred. michael@0: michael@0: `lineText` michael@0: : If present, this is the source code of the offending line. michael@0: michael@0: `offset` michael@0: : The index of the character within lineText at which the error occurred. michael@0: michael@0: `warning` michael@0: : Present and true if this is a warning; absent otherwise. michael@0: michael@0: `strict` michael@0: : Present and true if this error or warning is due to the strict option michael@0: (not to be confused with ES strict mode) michael@0: michael@0: `exception` michael@0: : Present and true if an exception will be thrown; absent otherwise. michael@0: michael@0: `arguments` michael@0: : An array of strings, representing the arguments substituted into the michael@0: error message. michael@0: michael@0: This method's return value is ignored. michael@0: michael@0: `onNewGlobalObject(global)` michael@0: : A new global object, global, has been created. The application michael@0: embedding the JavaScript implementation may provide details about what michael@0: kind of global it is via global.hostAnnotations. michael@0: michael@0: This handler method should return a [resumption value][rv] specifying how michael@0: the debuggee's execution should proceed. However, note that a { return: michael@0: value } resumption value is treated like `undefined` ("continue michael@0: normally"); value is ignored. (Allowing the handler to substitute michael@0: its own value for the new global object doesn't seem useful.) michael@0: michael@0: This handler method is only available to debuggers running in privileged michael@0: code ("chrome", in Firefox). Most functions provided by this `Debugger` michael@0: API observe activity in only those globals that are reachable by the michael@0: API's user, thus imposing capability-based restrictions on a michael@0: `Debugger`'s reach. However, the `onNewGlobalObject` method allows the michael@0: API user to monitor all global object creation that occurs anywhere michael@0: within the JavaScript system (the "JSRuntime", in SpiderMonkey terms), michael@0: thereby escaping the capability-based limits. For this reason, michael@0: `onNewGlobalObject` is only available to privileged code. michael@0: michael@0: michael@0: michael@0: ## Function Properties of the Debugger Prototype Object michael@0: michael@0: The functions described below may only be called with a `this` value michael@0: referring to a `Debugger` instance; they may not be used as methods of michael@0: other kinds of objects. michael@0: michael@0: addDebuggee(global) michael@0: : Add the global object designated by global to the set of global michael@0: objects this `Debugger` instance is debugging. If the designated global michael@0: is already a debuggee, this has no effect. Return this `Debugger`'s michael@0: [`Debugger.Object`][object] instance referring to the designated global. michael@0: michael@0: The value global may be any of the following: michael@0: michael@0: * A global object. michael@0: michael@0: * An HTML5 `WindowProxy` object (an "outer window", in Firefox michael@0: terminology), which is treated as if the `Window` object of the michael@0: browsing context's active document (the "inner window") were passed. michael@0: michael@0: * A cross-compartment wrapper of an object; we apply the prior rules to michael@0: the wrapped object. michael@0: michael@0: * A [`Debugger.Object`][object] instance belonging to this `Debugger` instance; michael@0: we apply the prior rules to the referent. michael@0: michael@0: * Any other sort of value is treated as a `TypeError`. (Note that each michael@0: rule is only applied once in the process of resolving a given michael@0: global argument. Thus, for example, a [`Debugger.Object`][object] michael@0: referring to a second [`Debugger.Object`][object] which refers to a global does michael@0: not designate that global for the purposes of this function.) michael@0: michael@0: The global designated by global must be in a different michael@0: compartment than this `Debugger` instance itself. If adding the michael@0: designated global's compartment would create a cycle of debugger and michael@0: debuggee compartments, this method throws an error. michael@0: michael@0: This method returns the [`Debugger.Object`][object] instance whose referent is michael@0: the designated global object. michael@0: michael@0: The `Debugger` instance does not hold a strong reference to its michael@0: debuggee globals: if a debuggee global is not otherwise reachable, then michael@0: it is dropped from the `Debugger`'s set of debuggees. (Naturally, the michael@0: [`Debugger.Object`][object] instance this method returns does hold a strong michael@0: reference to the added global.) michael@0: michael@0: removeDebuggee(global) michael@0: : Remove the global object designated by global from this michael@0: `Debugger` instance's set of debuggees. Return `undefined`. michael@0: michael@0: This method interprets global using the same rules that michael@0: [`addDebuggee`][add] does. michael@0: michael@0: hasDebuggee(global) michael@0: : Return `true` if the global object designated by global is a michael@0: debuggee of this `Debugger` instance. michael@0: michael@0: This method interprets global using the same rules that michael@0: [`addDebuggee`][add] does. michael@0: michael@0: `getDebuggees()` michael@0: : Return an array of distinct [`Debugger.Object`][object] instances whose referents michael@0: are all the global objects this `Debugger` instance is debugging. michael@0: michael@0: Since `Debugger` instances don't hold strong references to their michael@0: debuggee globals, if a debuggee global is otherwise unreachable, it may michael@0: be dropped at any moment from the array this method returns. michael@0: michael@0: `getNewestFrame()` michael@0: : Return a [`Debugger.Frame`][frame] instance referring to the youngest michael@0: [visible frame][vf] currently on the calling thread's stack, or `null` michael@0: if there are no visible frames on the stack. michael@0: michael@0: findSources([query]) (not yet implemented) michael@0: : Return an array of all [`Debugger.Source`][source] instances matching michael@0: query. Each source appears only once in the array. Query michael@0: is an object whose properties restrict which sources are returned; a michael@0: source must meet all the criteria given by query to be returned. michael@0: If query is omitted, we return all sources of all debuggee michael@0: scripts. michael@0: michael@0: Query may have the following properties: michael@0: michael@0: `url` michael@0: : The source's `url` property must be equal to this value. michael@0: michael@0: `global` michael@0: : The source must have been evaluated in the scope of the given global michael@0: object. If this property's value is a [`Debugger.Object`][object] instance michael@0: belonging to this `Debugger` instance, then its referent is used. If the michael@0: object is not a global object, then the global in whose scope it was michael@0: allocated is used. michael@0: michael@0: Note that the result may include sources that can no longer ever be michael@0: used by the debuggee: say, eval code that has finished running, or michael@0: source for unreachable functions. Whether such sources appear can be michael@0: affected by the garbage collector's behavior, so this function's result michael@0: is not entirely deterministic. michael@0: michael@0: findScripts([query]) michael@0: : Return an array of [`Debugger.Script`][script] instances for all debuggee scripts michael@0: matching query. Each instance appears only once in the array. michael@0: Query is an object whose properties restrict which scripts are michael@0: returned; a script must meet all the criteria given by query to michael@0: be returned. If query is omitted, we return the [`Debugger.Script`][script] michael@0: instances for all debuggee scripts. michael@0: michael@0: Query may have the following properties: michael@0: michael@0: `url` michael@0: : The script's `url` property must be equal to this value. michael@0: michael@0: `source` (not yet implemented) michael@0: : The script's `source` property must be equal to this value. michael@0: michael@0: `line` michael@0: : The script must at least partially cover the given source line. If this michael@0: property is present, the `url` property must be present as well. michael@0: michael@0: `column` michael@0: : The script must include given column on the line given by the `line` michael@0: property. If this property is present, the `url` and `line` properties michael@0: must both be present as well. michael@0: michael@0: `innermost` michael@0: : If this property is present and true, the script must be the innermost michael@0: script covering the given source location; scripts of enclosing code are michael@0: omitted. michael@0: michael@0: `global` michael@0: : The script must be in the scope of the given global object. If this michael@0: property's value is a [`Debugger.Object`][object] instance belonging to this michael@0: `Debugger` instance, then its referent is used. If the object is not a michael@0: global object, then the global in whose scope it was allocated is used. michael@0: michael@0: All properties of query are optional. Passing an empty object michael@0: returns all debuggee code scripts. michael@0: michael@0: Note that the result may include [`Debugger.Script`][script] instances for michael@0: scripts that can no longer ever be used by the debuggee, say, those for michael@0: eval code that has finished running, or unreachable functions. Whether michael@0: such scripts appear can be affected by the garbage collector's michael@0: behavior, so this function's behavior is not entirely deterministic. michael@0: michael@0: clearBreakpoint(handler) michael@0: : Remove all breakpoints set in this `Debugger` instance that use michael@0: handler as their handler. Note that, if breakpoints using other michael@0: handler objects are set at the same location(s) as handler, they michael@0: remain in place. michael@0: michael@0: `clearAllBreakpoints()` michael@0: : Remove all breakpoints set using this `Debugger` instance. michael@0: michael@0: `clearAllWatchpoints()` (future plan) michael@0: : Clear all watchpoints owned by this `Debugger` instance. michael@0: michael@0: `findAllGlobals()` michael@0: : Return an array of [`Debugger.Object`][object] instances referring to all the michael@0: global objects present in this JavaScript instance. The application may michael@0: provide details about what kind of globals they are via the michael@0: [`Debugger.Object`][object] instances' `hostAnnotations` accessors. michael@0: michael@0: The results of this call can be affected in non-deterministic ways by michael@0: the details of the JavaScript implementation. The array may include michael@0: [`Debugger.Object`][object] instances referring to global objects that are not michael@0: actually reachable by the debuggee or any other code in the system. michael@0: (Naturally, once the function has returned, the array's michael@0: [`Debugger.Object`][object] instances strongly reference the globals they refer michael@0: to.) michael@0: michael@0: This handler method is only available to debuggers running in privileged michael@0: code ("chrome", in Firefox). Most functions provided by this `Debugger` michael@0: API observe activity in only those globals that are reachable by the michael@0: API's user, thus imposing capability-based restrictions on a michael@0: `Debugger`'s reach. However, `findAllGlobals` allows the API user to michael@0: find all global objects anywhere within the JavaScript system (the michael@0: "JSRuntime", in SpiderMonkey terms), thereby escaping the michael@0: capability-based limits. For this reason, `findAllGlobals` is only michael@0: available to privileged code. michael@0: michael@0: makeGlobalObjectReference(global) michael@0: : Return the [`Debugger.Object`][object] whose referent is the global object michael@0: designated by global, without adding the designated global as a michael@0: debuggee. If global does not designate a global object, throw a michael@0: `TypeError`. Determine which global is designated by global michael@0: using the same rules as [`Debugger.prototype.addDebuggee`][add]. michael@0: