Changes

Jump to: navigation, search

Remote Debugging Protocol

154 bytes removed, 18:45, 14 June 2011
Use StudlyCaps for literal string values and metavariables; this isn't emacs-lisp, you know.
If a packet is directed to an actor that no longer exists, the server sends a packet to the client of the following form:
{ "from":<i>actor</i>, "error":"no-such-actornoSuchActor" }
where <i>actor</i> is the name of the non-existent actor. (It is strange to receive messages from actors that do not exist, but the client evidently believes that actor exists, and this reply allows the client to pair up the error report with the source of the problem.)
If an actor receives a packet whose type it does not recognize, it sends an error reply of the form:
{ "from":<i>actor</i>, "error":"unrecognized-packet-typeunrecognizedPacketType", "message":<i>message</i> }
where <i>message</i> provides details to help debugger developers understand what went wrong: what kind of actor <i>actor</i> is; the packet received; and so on.
This represents the JavaScript <tt>undefined</tt> value. (<tt>undefined</tt> has no direct representation in JSON.)
{ "type":"object", "class":<i>class-nameclassName</i>, "actor":<i>actor</i> }
This represents a JavaScript object whose class is <i>class-nameclassName</i>. (Arrays and functions are treated as objects for the sake of forming grips.) <i>Actor</i> can be consulted for the object's contents, as explained below.
{ "type":"long-stringlongString", "initial":<i>initial</i>, "length":<i>length</i>, "actor":<i>actor</i> }
This represents a very long string, where "very long" is defined at the server's discretion. <i>Initial</i> is some initial portion of the string, <i>length</i> is the string's full length, and <i>actor</i> can be consulted for the rest of the string, as explained below.
{ "type":"object", "class":"Object", "actor":<i>actor</i> }
and sending a [[#Finding_An_Object's_Prototype_And_Properties|"prototype-and-propertiesprototypeAndProperties"]] request to <i>actor</i> would produce the following reply:
{ "from":<i>actor</i>, "prototype":{ "type":"object", "class":"Object", "actor":<i>objproto-actorobjprotoActor</i> }, "own-propertiesownProperties":{ "x":{ "enumerable":true, "configurable":true, "writeable":true, "value":10 },
"y":{ "enumerable":true, "configurable":true, "writeable":true, "value":"kaiju" },
"a":{ "enumerable":true, "configurable":true,
"get":{ "type":"object", "class":"Function", "actor":<i>getter-actorgetterActor</i> },
"set":{ "type":"undefined" }
}
To examine an object's prototype and properties, a client can send the object's grip's actor a request of the form:
{ "to":<i>grip-actorgripActor</i>, "type":"prototype-and-propertiesprototypeAndProperties" }
to which the grip actor replies:
{ "from":<i>grip-actorgripActor</i>, "prototype":<i>prototype</i>, "own-propertiesownProperties":<i>own-propertiesownProperties</i> }
where <i>prototype</i> is a grip on the object's prototype (possibly <tt>{&nbsp;"type":"null"&nbsp;}</tt>), and <i>own-propertiesownProperties</i> has the form:
{ <i>name</i>:<i>descriptor</i>, ... }
To find an object's prototype, a client can send the object's grip's actor a request of the form:
{ "to":<i>grip-actorgripActor</i>, "type":"prototype" }
to which the grip actor replies:
{ "from":<i>grip-actorgripActor</i>, "prototype":<i>prototype</i> }
where <i>prototype</i> is a grip on the object's prototype (possibly <tt>{ "type":"null" }</tt>).
To list an object's own properties' names, a client can send the object's grip's actor a request of the form:
{ "to":<i>grip-actorgripActor</i>, "type":"own-property-namesownPropertyNames" }
to which the grip actor replies:
{ "from":<i>grip-actorgripActor</i>, "own-property-namesownPropertyNames":[ <i>name</i>, ... ] }
where each <i>name</i> is a string naming an own property of the object.
To obtain a descriptor for a particular property of an object, a client can send the object's grip's actor a request of the form:
{ "to":<i>grip-actorgripActor</i>, "type":"property" }
to which the grip actor replies:
{ "from":<i>grip-actorgripActor</i>, "descriptor":<i>descriptor</i> }
where <i>descriptor</i> is a descriptor for the given property, or <tt>null</tt> if there is no such property on the object.
If an object's class as given in the grip is <code>"Function"</code>, then the grip's actor responds to the messages given here.
{ "to":<i>function-grip-actorfunctionGripActor</i>, "type":"name-and-parametersnameAndParameters" }
This requests the name of the function represented by <i>function-grip-actorfunctionGripActor</i>, and the names of its parameters. The reply has the form:
{ "from":<i>function-grip-actorfunctionGripActor</i>, "name":<i>name</i>, "parameters":[ <i>parameter</i>, ... ] }
where <i>name</i> is the name of the function, or <code>null</code> if the function is anonymous, and each <i>parameter</i> is the name of a formal parameter to the function as a string. If the function takes destructuring arguments, the <i>parameter</i> is a structure of JSON array and object forms matching the form of the destructuring arguments.
{ "to":<i>function-grip-actorfunctionGripActor</i>, "type":"scope" }
Return the lexical environment over which the function has closed. The reply has the form:
{ "from":<i>function-grip-actorfunctionGripActor</i>, "scope":<i>environment</i> }
where <i>environment</i> is a [[#Lexical_Environments|lexical environment]].
{ "to":<i>function-grip-actorfunctionGripActor</i>, "type":"decompile", "pretty":<i>pretty</i> }
Return JavaScript source code for a function equivalent to the one represented by <i>function-grip-actorfunctionGripActor</i>. If the optional <code>pretty</code> parameter is present and <i>pretty</i> is <code>true</code>, then produce indented source code with line breaks. The reply has the form:
{ "from":<i>function-grip-actorfunctionGripActor</i>, "decompiled-codedecompiledCode":<i>code</i> }
where <i>code</i> is a string.
The client can find the full contents of a long string by sending a request to the long string grip actor of the form:
{ "to":<i>grip-actorgripActor</i>, "type":"substring", "start":<i>start</i>, "length":<i>length</i> }
where <i>start</i> and <i>length</i> are integers. This requests the substring <i>length</i> characters long, starting at the <i>start</i>'th character. The actor replies as follows:
{ "from":<i>grip-actorgripActor</i>, "substring":<i>string</i> }
where <i>string</i> is the requested portion of the string the actor represents.
== Grip Lifetimes ==
Most grips are <b>pause-lifetimepauseLifetime</b> grips: they last only while the JavaScript thread is paused, and become invalid as soon as the debugger allows the thread to resume execution. (The actors in pause-lifetime grips are children of an actor that is closed when the thread resumes, or is detached from.) This arrangement allows the protocol to use grips freely in responses without requiring the client to remember and close them all.
However, in some cases the client may wish to retain a reference to an object while the debuggee runs. For example, a panel displaying objects selected by the user must update its view of the objects each time the debuggee pauses. To carry this out, the client can promote a pause-lifetime grip to a <b>thread-lifetimethreadLifetime</b> grip, which lasts until the thread is detached from or exits. Actors in thread-lifetime grips are children of the thread actor. When the client no longer needs a thread-lifetime grip, it can explicitly release it.
Both pause-lifetime and thread-lifetime grips are garbage collection roots.
To promote a pause-lifetime grip to a thread-lifetime grip, the client sends a packet of the form:
{ "to":<i>grip-actorgripActor</i>, "type":"thread-gripthreadGrip" }
where <i>grip-actorgripActor</i> is the actor from the existing pause-lifetime grip. The grip actor will reply:
{ "from":<i>grip-actorgripActor</i>, "thread-gripthreadGrip":<i>thread-gripthreadGrip</i> }
where <i>thread-gripthreadGrip</i> is a new grip on the same object, but whose actor is parented by the thread actor, not the pause actor.
The client can release a thread-lifetime grip by sending the grip actor a request of the form:
{ "to":<i>grip-actorgripActor</i>, "type":"release" }
The grip actor will reply, simply:
{ "from":<i>grip-actorgripActor</i> }
This closes the grip actor.
The client can release many thread-lifetime grips in a single operation by sending the thread actor a request of the form:
{ "to":<i>thread</i>, "type":"release-manyreleaseMany", "actors":[ <i>grip-actorgripActor</i>, ... ] }
where each <i>grip-actorgripActor</i> is the name of a child of <i>thread</i> that should be freed. The thread actor will reply, simply:
{ "from":<i>thread</i> }
When the connection to the server is opened, the root actor opens the conversation with the following packet:
{ "from":"root", "application-typeapplicationType":<i>app-typeappType</i>, "traits":<i>traits</i>, ...}
The root actor's name is always zero. <i>app-typeappType</i> is a string indicating what sort of program the server represents. There may be more properties present, depending on <i>app-typeappType</i>.
<i>traits</i> is an object describing protocol variants this server supports that are not convenient for the client to detect otherwise. The property names present indicate what traits the server has; the properties' values depend on their names. This version of the protocol defines no traits, so <i>traits</i> must be an object with no properties, <tt>{}</tt>.
For web browsers, the introductory packet should have the following form:
{ "from":"root", "application-typeapplicationType":"browser", "traits":<i>traits</i> }
== Listing Top-Level Browsing Contexts ==
To get a list of the top-level browsing contexts (tabs) present in a browser, a client should send a request like the following to the root actor:
{ "to":"root", "type":"list-contextslistContexts" }
The reply should have the form:
<i>actor</i> is the actor representing that top-level browsing context; <i>title</i> is the context's document's title, and <i>url</i> is the context's document's URL.
Clients should send "list-contextslistContexts" requests only to root actors that have identified themselves as browsers.
Actor names given in a list-contexts reply are children of the root actor. They remain valid at least until the next list-contexts request is received. If the client attaches to a context actor, its name is valid at least until the client detaches from the context and receives a "detached" packet from the context, or until the client sends a "release" packet to the context. (These packets are described in detail in [[#Interacting_with_Thread-Like_Actors|Interacting with Thread-Like Actors]].)
For example, upon connection to a web browser visiting two pages at example.com, the root actor's introductory packet might look like this:
{ "from":"root", "application-typeapplicationType":"browser",
"contexts":[ { "actor":"context1", "title":"Fruits",
"url":"http://www.example.com/fruits/" },
{ "to":<i>thread</i>, "type":"attach" }
Here, <i>thread</i> is the actor representing the thread, perhaps a browsing context from a "list-contextslistContexts" reply. This packet causes the thread to pause its execution, if it does not exit of its own accord first. The thread responds in one of two ways:
{ "from":<i>thread</i>, "type":"paused", "why":{ "type":"attached" }, ... }
If the client sends an <code>"attach"</code> packet to a thread that is not in the <b>Detached</b> or <b>Exited</b> state, the actor sends an error reply of the form:
{ "from":<i>thread</i>, "error":"wrong-statewrongState", "message":<i>message</i> }
where <i>message</i> details which state the thread was in instead (to make debugging debuggers easier). In this case, the thread's state is unaffected.
If the client sends a <code>"detach"</code> packet to a thread that is not in the <b>Running</b>, <b>Paused</b>, or <b>Exited</b> state, the actor sends an error reply of the form:
{ "from":<i>thread</i>, "error":"wrong-statewrongState", "message":<i>message</i> }
where <i>message</i> details which state the thread was in instead (to make debugging debuggers easier). In this case, the thread's state is unaffected.
{ "from":<i>thread</i>, "type":"paused", "actor":<i>actor</i>, "why":<i>reason</i>,
"current-framecurrentFrame":<i>frame</i>, "popped-framespoppedFrames":[<i>popped-framepoppedFrame</i>...] }
This indicates that the thread has entered the <b>Paused</b> state, and explains where and why.
Since actors in value grips are parented by the pause actor, this means that those grips become invalid when the thread resumes, or is detached from; it is not possible to take a grip from one pause and use it in the next. To create a grip that remains valid between pauses, see [[#Holding_Values_Between_Pauses|Holding Values Between Pauses]].
The <i>current-framecurrentFrame</i> value describes the top frame on the JavaScript stack; see [[#Listing_Stack_Frames|Listing Stack Frames]], below.
The <code>"popped-framespoppedFrames"</code> property is an array of frame actor names, listing the actors for all frames that were live as of the last pause, but have since been popped. If no frames have been popped, or if this is the first pause for this thread, then this property's value is the empty array.
The <i>reason</i> value describes why the thread paused. It has one of the following forms:
The thread stopped because it received an "interrupt" packet from the client.
{ "type":"resume-limitresumeLimit" }
The client resumed the thread with a "resume" packet that included a <tt>resume-limitresumeLimit</tt> property, and the thread paused because the given <i>limit</i> was met.
{ "type":"debugger-statementdebuggerStatement" }
The thread stopped because it executed a JavaScript "debugger" statement.
<i>TODO: This should provide more details about the watchpoint in the packet, instead of incurring another round-trip before we can display anything helpful.</i>
{ "type":"client-evaluatedclientEvaluated", "value":<i>grip</i> }
The client's prior <tt>client-evaluateclientEvaluate</tt> command has completed normally; <i>grip</i> is a grip on the expression's value. See [[#Evaluating_Source-Language_Expressions|Evaluating Source-Language Expressions]] for details.
{ "type":"client-evaluatedclientEvaluated", "exception":<i>grip</i> }
The client's prior <tt>client-evaluateclientEvaluate</tt> command has completed abruptly; <i>grip</i> is the uncaught exception value. See [[#Evaluating_Source-Language_Expressions|Evaluating Source-Language Expressions]] for details.
== Resuming a Thread ==
If a thread is in the <b>Paused</b> state, the client can resume it by sending a packet of the following form:
{ "to":<i>thread</i>, "type":"resume", "resume-limitresumeLimit":<i>limit</i> }
This puts the thread in the <b>Running</b> state. The thread will pause again for breakpoint hits, watchpoint hits, throw watches, frame pop watches, and other standing pause requests.
In addition, if the optional <tt>resume-limitresumeLimit</tt> property is present, then the thread should also pause when <i>limit</i> is reached. <i>Limit</i> must have one of the following forms:
{ "type":"next" }
The thread should pause just before the current frame is popped, whether by throwing an exception or returning a value.
When a thread pauses because a limit was reached, the "paused" packet's <i>reason</i> will have a type of <tt>"resume-limitresumeLimit"</tt>.
A resume limit applies only to the current resumption; once the thread pauses, whether because the limit was reached or some other event occurred&mdash;a breakpoint hit, for example&mdash;the resume limit is no longer in effect.
If no <tt>"resume-limitresumeLimit"</tt> property appears in the "resume" packet, then the thread should run until some standing pause condition is met (a breakpoint is hit; a watchpoint triggers; or the like).
A "resume" packet closes the pause actor the client provided in the "paused" packet that began the pause.
If the client sends a <code>"resume"</code> packet to a thread that is not in the <b>Paused</b> state, the actor sends an error reply of the form:
{ "from":<i>thread</i>, "error":"wrong-statewrongState", "message":<i>message</i> }
where <i>message</i> details which state the thread was in instead (to make debugging debuggers easier). In this case, the thread's state is unaffected.
If the client sends an <code>"interrupt"</code> packet to a thread that is not in the <b>Running</b>, <b>Paused</b>, or <b>Exited</b> state, the actor sends an error reply of the form:
{ "from":<i>thread</i>, "error":"wrong-statewrongState", "message":<i>message</i> }
where <i>message</i> details which state the thread was in instead (to make debugging debuggers easier). In this case, the thread's state is unaffected.
{ "actor":<i>actor</i>, "depth":<i>depth</i>, "type":"call", "this":<i>this</i>,
"where":<i>location</i>, "environment",<i>environment</i>,
"callee":<i>callee</i>, "callee-namecalleeName":<i>callee-namecalleeName</i>, "arguments":<i>arguments</i> }
where:
* <i>callee</i> is a grip on the function value being called;
* <i>callee-namecalleeName</i> is the name of the callee, a string (this property is omitted for anonymous functions);
* <i>arguments</i> is an array of grips on the actual values passed to the function;
=== Client Evaluation Frames ===
When the client evaluates an expression with an <tt>client-evaluateclientEvaluate</tt> packet, the evaluation appears on the stack as a special kind of frame, of the form:
{ "actor":<i>actor</i>, "depth":<i>depth</i>, "type":"client-evaluateclientEvaluate", "this":<i>this</i>,
"where":<i>location</i>, "environment",<i>environment</i> }
The client can remove frames from the stack by sending a request of the form:
{ "to":<i>frame-actorframeActor</i>, "type":"pop", "value":<i>value</i> }
where <i>frame-actorframeActor</i> is the actor representing the stack frame to pop, and <i>value</i> is a grip on the value that should be returned as the value of the frame. All younger stack frames are also popped. The frame actor will reply:
{ "from":<i>frame-actorframeActor</i>, "watches":[<i>watch-actorwatchActor</i> ...] }
where each <i>watch-actorwatchActor</i> is the name of a frame pop watch actor that has been triggered in the process of popping the given frame. If no frame pop watches are triggered, the <tt>watches</tt> property may be omitted.
<i>TODO: specify the error to return if the frame cannot be popped --- can host (C++) function frames be popped?</i>
To evaluate a source-language expression in a thread, the client sends a specialized <tt>resume</tt> packet of the form:
{ "to":<i>thread</i>, "type":"client-evaluateclientEvaluate", "expression":<i>expr</i>, "frame":<i>frame</i> }
This resumes the thread just as an ordinary <tt>resume</tt> packet does, but rather than continuing execution where the pause took place, has the thread begin evaluation of the source-language expression given by <i>expr</i>, a string. The evaluation takes place in a new [[#Client_Evaluation_Frames|Client Evaluation Frame]], pushed on the stack. When evaluation of <i>expr</i> completes, the client will report a <tt>client-evaluateclientEvaluate</tt> pause containing the expression's value.
If evaluating <i>expr</i> completes abruptly, this outcome is still reported via an <tt>client-evaluatedclientEvaluated</tt> pause, so it is not necessary for the client to take explicit steps to catch exceptions thrown by the expression.
<i>TODO: evaluate with given grips bound to given identifiers</i>
A lexical environment (written as <i>environment</i> in packet descriptions) records the identifier bindings visible at a particular point in the program. An environment has one of the following forms:
{ "type":"object", "actor":<i>actor</i>, "object":<i>object</i>, "parent":<i>parent-environmentparentEnvironment</i> }
This represents a scope chain element whose identifier bindings reflect the properties of <i>object</i> (a grip). This could be the global object (<tt>window</tt> in a browser), or a DOM element (for event handler content attributes, which have the input element, form, and document on their scope chain along with the <tt>window</tt>).
<i>Actor</i> is the name of an actor representing this lexical environment. The requests it can answer are described below.
<i>Parent-environmentParentEnvironment</i> describes the next enclosing lexical environment; the <tt>parent</tt> property is omitted on the outermost environment.
{ "type":"function", "actor":<i>actor</i>, "function":<i>function</i>, "function-namefunctionName":<i>function-namefunctionName</i>, "bindings":<i>bindings</i>, "parent":<i>parent-environmentparentEnvironment</i> }
This represents the variable environment created by a call to <i>function</i> (a grip), whose name is <i>function-namefunctionName</i> (a string). <i>Bindings</i> describes the bindings in scope, including the function's arguments, the <tt>arguments</tt> object, and local <tt>var</tt> and function bindings; its form is described in detail below. The <tt>function-namefunctionName</tt> property is omitted if the function is anonymous. The other properties are as described above.
{ "type":"with", "actor":<i>actor</i>, "object":<i>object</i>, "parent":<i>parent-environmentparentEnvironment</i> }
This represents bindings introduced by a <tt>with</tt> statement whose operand is <i>object</i> (a grip). The other properties are as described above.
{ "type":"block", "actor":<i>actor</i>, "bindings":<i>bindings</i>, "parent":<i>parent-environmentparentEnvironment</i> }
This represents bindings introduced by a <tt>let</tt> block, <tt>for-inforIn</tt> statement, <tt>catch</tt> block, or the like. The properties are as described above.
A <i>bindings</i> value has the form:
To fully enumerate the bindings introduced by any lexical environment, the client can send a request of the following form to the environment's actor:
{ "to":<i>env-actorenvActor</i>, "type":"bindings" }
The actor will reply as follows:
{ "from":<i>env-actorenvActor</i>, "bindings":<i>bindings</i> }
To change the value of a variable bound in a particular lexical environment, the client can send a request to the environment's actor:
{ "to":<i>env-actorenvActor</i>, "type":"assign", "name":<i>name</i>, "value":<i>value</i> }
This changes the value of the identifier whose name is <i>name</i> (a string) to that represented by <i>value</i> (a grip). The actor will reply as follows, simply:
{ "from":<i>env-actorenvActor</i> }
If the named identifier is immutable, the actor will send an error reply of the form:
{ "from":<i>env-actorenvActor</i>, "error":"immutable-bindingimmutableBinding", "message":<i>message</i> }
== Lexical Environment Examples ==
then we would hit that breakpoint, eliciting a packet like the following:
{ "from":<i>thread</i>, "type":"paused", "actor":<i>pause-actorpauseActor</i>, "why":{ "type":"breakpoint", "actors":[<i>breakpoint-actorbreakpointActor</i>] }, "frame":{ "actor":<i>frame-actorframeActor</i>, "depth":1,
"type":"call", "where":{ "url":"sample.js", "line":3 },
"environment":{ "type":"function", "actor":<i>g-frame-actorgFrameActor</i>, "function":{ "type":"object", "class":"Function", "actor":<i>g-actorgActor</i> }, "function-namefunctionName":"g",
"bindings":{ "mutable":{ "y":"argument to g" } },
"parent":{ "type":"function", "actor":<i>f-frame-actorfFrameActor</i>, "function":{ "type":"object", "class":"Function", "actor":<i>f-actorfActor</i> }, "function-namefunctionName":"f",
"bindings":{ "mutable":{ "x":"argument to f" } },
"parent":{ "type":"object", "actor":<i>global-code-actorglobalCodeActor</i>,
"object":{ "type":"object", "class":"Global",
"actor":<i>global-object-actorglobalObjectActor</i> }
}
}
},
"callee":<i>g-actorgActor</i>, "callee-namecalleeName":"g", "this":{ "type":"object", "class":"Function", "actor":<i>g-actorgActor</i> },
"arguments":["argument to g"]
}
While a thread is paused, a client can set breakpoints in the thread's code by sending requests of the form:
{ "to":<i>thread</i>, "type":"set-breakpointsetBreakpoint", "location":<i>location</i> }
where <i>location</i> is a [[#Source_Locations|source location]]. If the thread is able to establish a breakpoint at the given location, it replies:
{ "from":<i>thread</i>, "actor":<i>actor</i>, "actual-locationactualLocation":<i>actual-locationactualLocation</i> }
where <i>actor</i> is an actor representing the breakpoint (a child of the thread actor), and <i>actual-locationactualLocation</i> is the location at which the breakpoint was really set. If <i>location</i> and <i>actual-locationactualLocation</i> are the same, then the <tt>actual-locationactualLocation</tt> property can be omitted.
If the thread cannot find the script referred to in <i>location</i>, it sends an error reply of the form:
{ "from":<i>thread</i>, "error":"no-scriptnoScript" }
If <i>location</i> refers to a line and column at which the given script has no program code, and no reasonable alternative location can be chosen (say, by skipping forward), then the thread sends an error reply of the form:
{ "from":<i>thread</i>, "error":"no-code-at-line-columnnoCodeAtLineColumn" }
To delete a breakpoint, the client can send the breakpoint's actor a message of the form:
{ "to":<i>breakpoint-actorbreakpointActor</i>, "type":"delete" }
to which the breakpoint actor will reply, simply:
{ "from":<i>breakpoint-actorbreakpointActor</i> }
This closes communications with <i>breakpoint-actorbreakpointActor</i>.
= Watchpoints =
Confirm
496
edits

Navigation menu