Remote Debugging Protocol: Difference between revisions

Jump to navigation Jump to search
Copy-edit; rearrange for clarity; split frame type descriptions.
(Copy-edit; rearrange for clarity; split frame type descriptions.)
Line 1: Line 1:
<i>(Note: this page is a draft design of work not yet completed. It is written in the present tense to be easily promoted to documentation when implemented, and also to simplify the grammar.)</i>
<i>(Note: this page is a draft design of work not yet completed. It is written in the present tense to be easily promoted to documentation when implemented, and also to simplify the grammar.)</i>


The Mozilla debugging protocol allows a debugger to connect to a browser, discover what sorts of things are present to debug or inspect, select JavaScript threads to watch, and observe and modify their execution. The protocol provides a unified view of JavaScript, DOM nodes, CSS rules, and the other technologies used in client-side web applications. The protocol is meant to be sufficiently general to be extended for use with other sorts of clients (profilers, say) and servers (mail readers; random XULrunner applications).
The Mozilla debugging protocol allows a debugger to connect to a browser, discover what sorts of things are present to debug or inspect, select JavaScript threads to watch, and observe and modify their execution. The protocol provides a unified view of JavaScript, DOM nodes, CSS rules, and the other technologies used in client-side web applications. The protocol ought to be sufficiently general to be extended for use with other sorts of clients (profilers, say) and servers (mail readers; random XULrunner applications).


All communication between debugger (client) and browser (server) is in the form of JSON objects. This makes the protocol directly readable by humans, capable of graceful evolution, and easy to implement using stock libraries. In particular, it should be easy to create mock implementations for testing and experimentation.
All communication between debugger (client) and browser (server) is in the form of JSON objects. This makes the protocol directly readable by humans, capable of graceful evolution, and easy to implement using stock libraries. In particular, it should be easy to create mock implementations for testing and experimentation.
Line 9: Line 9:
= Actors =
= Actors =


An "actor" is something on the server that receives and replies to JSON packets from the client. Every packet from the client specifies the actor to which it is directed, and every packet from the server indicates which actor sent it.
An <b>actor</b> is something on the server that can exchange JSON packets with the client. Every packet from the client specifies the actor to which it is directed, and every packet from the server indicates which actor sent it.


Each server has a root actor, with which the client first interacts. The root actor can explain what sort of thing the server represents (browser; mail reader; etc.), and enumerate things available to debug: tabs, chrome, and so on. Each of these, in turn, is an actor to which requests can be addressed.
Each server has a root actor, with which the client first interacts. The root actor can explain what sort of thing the server represents (browser; mail reader; etc.), and enumerate things available to debug: tabs, chrome, and so on. Each of these, in turn, is represented by an actor to which requests can be addressed. Both artifacts of the program being debugged, like JavaScript objects and stack frames, and artifacts of the debugging machinery, like breakpoints and watchpoints, are actors with whom packets can be exchanged.


For example, a debugger might connect to a browser, ask the root actor to list the browser's tabs, and present this list to the developer. If the developer chooses some tabs to debug, then the debugger sends "attach" requests to the actors representing those tabs, to begin debugging. Both artifacts of the program being debugged, like JavaScript objects and stack frames, and artifacts of the debugging machinery, like breakpoints and watchpoints, are actors to which packets can be addressed.
For example, a debugger might connect to a browser, ask the root actor to list the browser's tabs, and present this list to the developer. If the developer chooses some tabs to debug, then the debugger can send <tt>attach</tt> requests to the actors representing those tabs, to begin debugging.


All actors form a tree, with the root actor as the root. Closing communications with an actor closes communications with all its descendants. The root actor has no owner, and lives as long as the underlying connection to the client does; when the underlying connection is closed, all actor names are closed. These limits on the lifetimes of actor names allow the protocol to mention actors freely, without forcing the client to explicitly free every actor that has ever been mentioned.
To allow the server to reuse actor names and the resources they require, actors have limited lifetimes. All actors in a server form a tree, whose root is the root actor. Closing communications with an actor automatically closes communications with its descendants. For example, the actors representing a thread's stack frames are children of the actor representing the thread itself, so that when a debugger detaches from a thread, which closes the thread's actor, the frames' actors are automatically closed. This arrangement allows the protocol to mention actors liberally, without making the client responsible for explicitly closing every actor that has ever been mentioned.  


Note that the actor hierarchy does not, in general, correspond to any particular hierarchy appearing in the debuggee. For example, although web workers are arranged in a hierarchy, all actors representing web worker threads are direct children of the root actor: one might want to detach from a parent worker while continuing to debug one of its children, so it doesn't make sense to close communications with a child worker when one closes communicatinos with its parent.
The root actor has no parent, and lives as long as the underlying connection to the client does; when that connection is closed, all actors are closed.
 
Note that the actor hierarchy does not, in general, correspond to any particular hierarchy appearing in the debuggee. For example, although web workers are arranged in a hierarchy, the actors representing web worker threads are all direct children of the root actor: one might want to detach from a parent worker while continuing to debug one of its children, so it doesn't make sense to close communications with a child worker simply because one has closed communications with its parent.


<i>(We are stealing the "actor" terminology from Mozilla's [[IPDL]], to mean, roughly, "things participating in the protocol". However, IPDL does much more with the idea than we do: it treats both client and server as collections of actors, and uses that detail to statically verify properties of the protocol. In contrast, the debugging protocol simply wants a consistent way to indicate the entities to which packets are directed.)</i>
<i>(We are stealing the "actor" terminology from Mozilla's [[IPDL]], to mean, roughly, "things participating in the protocol". However, IPDL does much more with the idea than we do: it treats both client and server as collections of actors, and uses that detail to statically verify properties of the protocol. In contrast, the debugging protocol simply wants a consistent way to indicate the entities to which packets are directed.)</i>
Line 27: Line 29:
Every packet sent from the client has the form:
Every packet sent from the client has the form:


   { "to": <i>actor</i>, "type": <i>type</i>, ... }
   { "to":<i>actor</i>, "type": <i>type</i>, ... }


where <i>actor</i> is the actor to whom the packet is directed&mdash;actor names are always integers&mdash;and <i>type</i> is a string specifying what sort of packet it is. Additional properties may be present, depending on <i>type</i>.
where <i>actor</i> is the actor to whom the packet is directed&mdash;actor names are always natural numbers&mdash;and <i>type</i> is a string specifying what sort of packet it is. Additional properties may be present, depending on <i>type</i>.


Every packet sent from the server has the form:
Every packet sent from the server has the form:


   { "from": <i>actor</i>, ... }
   { "from":<i>actor</i>, ... }
 
where <i>actor</i> is the name of the actor that sent it. The packet may have additional properties, depending on the situation.
 
If a packet is directed to an actor that no longer exists, the server sends a packet to the client of the following form:


where <i>actor</i> is the name of the actor that sent it. Additional properties may be present, depending on the situation.
  { "from":null, "type":"no-such-actor" }


We expect that, as the protocol evolves, we will specify new properties that can appear in existing packets, and experimental implementations will do the same. Clients should be written to silently ignore properties they do not recognize.
Clients should silently ignore properties they do not recognize. We expect that, as the protocol evolves, we will specify new properties that can appear in existing packets, and experimental implementations will do the same.


= Requests and Replies =
= Requests and Replies =


In this protocol description, a "request" is a packet sent from the client which always elicits a single packet from the recipient, the "reply". These terms indicate a simple pattern of communication: at any given time, either the client or actor is permitted to send a packet, but never both.
In this protocol description, a <b>request</b> is a packet sent from the client which always elicits a single packet from the recipient, the <b>reply</b>. These terms indicate a simple pattern of communication: at any given time, either the client or actor is permitted to send a packet, but never both.
 
The client's communication with each actor is treated separately: the client may send a request to one actor, and then send a request to a different actor before receiving a reply from the first.
 
Packets not described as requests or replies are part of some more complicated interaction, which should be spelled out in more detail.
 
= Grips =
 
A grip is a JSON value that refers to a specific JavaScript value in the debuggee. Grips appear anywhere an arbitrary value from the debuggee needs to be conveyed to the client: stack frames, object property lists, scopes, <tt>paused</tt> packets, and so on.
 
For mutable values like objects and arrays, grips do not merely convey the value's current state to the client. They also act as references to the original value, by including an actor to which the client can send messages to modify the value in the debuggee.
 
A grip has one of the following forms:
 
  <i>value</i>
 
where <i>value</i> is a string, a number, or a boolean value. For these types of values, the grip is simply the JSON form of the value.
 
  { "type":"null" }
 
This represents the JavaScript <tt>null</tt> value. (The protocol does not represent JavaScript <tt>null</tt> simply by the JSON <tt>null</tt>, for the convenience of clients implemented in JavaScript: this representation allows such clients to use <tt>typeof(<i>grip</i>) == "object"</tt> to decide whether the grip is simple or not.)
 
  { "type":"undefined" }
 
This represents the JavaScript <tt>undefined</tt> value. (<tt>undefined</tt> has no direct representation in JSON.)
 
  { "type":"object", "class":<i>class-name</i>, "actor":<i>actor</i> }
 
This represents a JavaScript object whose class is <i>class-name</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-string", "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.
 
Garbage collection will never free objects visible to the client via the protocol. Thus, actors representing JavaScript objects are effectively garbage collection roots.
 
== Objects ==
 
<i>TODO: can only be manipulated while paused</i>
 
<i>TODO: requests modeled after ES5 object inspection API</i>
 
<i>TODO: special stuff for arrays</i>
 
<i>TODO: special stuff for functions</i>
 
== Long Strings ==
 
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-actor</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-actor</i>, "substring":<i>string</i> }
 
where <i>string</i> is the requested portion of the string the actor represents.
 
Like object grip actors, long string grip actors must only receive messages from the client while the thread is in the <b>Paused</b> state.
 
== Grip Lifetimes ==
 
Most grips are <b>pause-lifetime</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 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-lifetime</b> grip, which lasts until the thread is detached from or exits. Actors in thread-lifetime grips are direct children of the thread actor. When the client no longer needs a thread-lifetime grip, it can explicitly release it. Both kinds of 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-actor</i>, "type":"thread-grip" }
 
where <i>grip-actor</i> is the actor from the existing pause-lifetime grip. The grip actor will reply:
 
  { "from":<i>grip-actor</i>, "thread-grip":<i>thread-grip</i> }
 
where <i>thread-grip</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-actor</i>, "type":"release" }
 
The grip actor will reply, simply:
 
  { "from":<i>grip-actor</i> }


The client's communication with each actor is treated separately: a client may send a request to one actor, and then send a request to a different actor before receiving a reply from the first.
This closes the grip actor.


Packets not described as "requests" or "replies" are part of some more complicated interaction, which should be spelled out in more detail.
Regardless of the lifetime of a grip, the client may only send messages to grip actors while the thread to which they belong is paused; the client's interaction with values cannot take place concurrently with the thread.


= The Root Actor =
= The Root Actor =
Line 55: Line 143:
The root actor's name is always zero. <i>app-type</i> is a string indicating what sort of program the server represents. There may be more properties present, depending on <i>app-type</i>.
The root actor's name is always zero. <i>app-type</i> is a string indicating what sort of program the server represents. There may be more properties present, depending on <i>app-type</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, {}.
<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:
For web browsers, the introductory packet should have the following form:
Line 71: Line 159:
   { "from":0, "contexts":[<i>context</i>...], selected:<i>index</i> }
   { "from":0, "contexts":[<i>context</i>...], selected:<i>index</i> }


<tt>Contexts</tt> is a list with one element for each top-level browsing context present in the browser, and <i>index</i> is the index within that list of the browsing context the user is currently interacting with. Each <i>context</i> has the following form:
The <tt>contexts</tt> property's value is an array with one element for each top-level browsing context present in the browser, and <i>index</i> is the index within that list of the browsing context the user is currently interacting with. Each <i>context</i> has the following form:


   { "actor":<i>actor</i>, "title":<i>title</i>, "url":<i>url</i> }
   { "actor":<i>actor</i>, "title":<i>title</i>, "url":<i>url</i> }
Line 79: Line 167:
Clients should send "list-contexts" requests only to root actors that have identified themselves as browsers.
Clients should send "list-contexts" requests only to root actors that have identified themselves as browsers.


Actor names given in a list-contexts reply have the root actor as their parent. 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 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. See "Interacting with Thread-Like Actors" for details.  
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:
For example, upon connection to a web browser visiting two pages at example.com, the root actor's introductory packet might look like this:
Line 89: Line 177:
                     "url":"http://www.example.com/bats/" }]}
                     "url":"http://www.example.com/bats/" }]}


<i>(The point here is to give the debugger enough information to select which context it would like to debug without having to do too many round trips. Round trips are bad for UI responsiveness, but large packets are probably not a problem, so whatever would help to add, we should add.)</i>
<i>(This may not be the right information to provide in these packets; suggestions very welcome. The point here is to give the debugger enough information to select which context it would like to debug without having to do too many round trips. Round trips are bad for UI responsiveness, but large packets are probably not a problem, so whatever would help to add, we should add.)</i>


= Interacting with Thread-Like Actors =
= Interacting with Thread-Like Actors =
Line 99: Line 187:
* <b>Detached</b>: the thread is running freely, and not presently interacting with the debugger. Detached threads run, encounter errors, and exit without exchanging any sort of messages with the debugger. A debugger can attach to a thread, putting it in the <b>Running</b> state. Or, a detached thread may exit on its own, entering the <b>Exited</b> state.
* <b>Detached</b>: the thread is running freely, and not presently interacting with the debugger. Detached threads run, encounter errors, and exit without exchanging any sort of messages with the debugger. A debugger can attach to a thread, putting it in the <b>Running</b> state. Or, a detached thread may exit on its own, entering the <b>Exited</b> state.


* <b>Running</b>: the thread is running under the debugger's observation, executing JavaScript code or possibly blocked waiting for input. It will report exceptions, breakpoint hits, watchpoint hits, and other interesting events to the client, and enter the <b>Paused</b> state. The debugger can also interrupt a running thread; this elicits a response and puts the thread in the <b>Paused</b> state. A running thread may also exit, entering the "exited" state.
* <b>Running</b>: the thread is running under the debugger's observation, executing JavaScript code or possibly blocked waiting for input. It will report exceptions, breakpoint hits, watchpoint hits, and other interesting events to the client, and enter the <b>Paused</b> state. The debugger can also interrupt a running thread; this elicits a response and puts the thread in the <b>Paused</b> state. A running thread may also exit, entering the <b>Exited</b> state.


* <b>Paused</b>: the thread has reported a pause to the client and is awaiting further instructions. In this state, a thread can accept requests and send replies. If the client asks the thread to continue or step, it returns to the <b>Running</b> state.
* <b>Paused</b>: the thread has reported a pause to the client and is awaiting further instructions. In this state, a thread can accept requests and send replies. If the client asks the thread to continue or step, it returns to the <b>Running</b> state.
Line 121: Line 209:
   { "to":<i>thread</i>, "type":"attach", "pause-for":<i>pause-types</i> }
   { "to":<i>thread</i>, "type":"attach", "pause-for":<i>pause-types</i> }


Here, <i>thread</i> is the actor representing the thread, perhaps a browsing context from a "list-contexts" reply. This tells the thread to continue to run, but asks it to pause if any of the event described by <i>pause-types</i> occurs. The form of <i>pause-types</i> is described in [[#Pause_Types]].
Here, <i>thread</i> is the actor representing the thread, perhaps a browsing context from a "list-contexts" reply. This tells the thread to continue to run, but asks it to pause if any of the events described by <i>pause-types</i> occurs. The form of <i>pause-types</i> is described in [[#Pause_Types|Pause Types]].


The thread responds in one of two ways:
The thread responds in one of two ways:
Line 173: Line 261:
This indicates that the thread has entered the <b>Paused</b> state, and explains where and why.
This indicates that the thread has entered the <b>Paused</b> state, and explains where and why.


<i>Actor</i> is an actor representing this specific pause of the thread. The pause actor lives until the thread leaves the <b>Paused</b> state. Actors referring to stack frames, values, and other entities uncovered during this pause are all children of this actor; when the thread resumes, those actors are automatically freed. This relieves the client from the responsibility to explicitly close communications with every actor mentioned in a pause. If a client wishes to hold a reference to a JavaScript value across pauses, then it must create its own grip on the value, parented by the thread actor, using the [[#Keeping_Values|"keep-value"]] packet.
<i>Actor</i> is a "pause actor", representing this specific pause of the thread; it lives until the thread next leaves the <b>Paused</b> state. The pause actor parents actors actors referring to stack frames, values, and other entities uncovered during this pause; when the thread resumes, those actors are automatically closed. This relieves the client from the responsibility to explicitly close every actor mentioned during the pause.
 
Since actors in value grips are parented by the pause actor as well, this means that those grips become invalid when the thread resumes; 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]].
 
<i>Frame</i> describes the top frame on the JavaScript stack; see [[#Listing_Stack_Frames|Listing Stack Frames]], below.


<i>Frame</i> describes the top frame on the JavaScript stack; see [[#Inspecting_the_Stack|Inspecting The Stack]], below. The <i>reason</i> value describes why the thread paused. It has one of the following forms:
The <i>reason</i> value describes why the thread paused. It has one of the following forms:


   { "type":"breakpoint", "actor":<i>actor</i> }
   { "type":"breakpoint", "actors":[<i>actor</i>...] }


The thread stopped at the breakpoint represented by the actor named <i>actor</i>.
The thread stopped at the breakpoints represented by the given <i>actor</i>s.


   { "type":"watchpoint", "actor":<i>watchpoint</i> }
   { "type":"watchpoint", "actors":[<i>watchpoint</i>...] }


The thread stopped at the breakpoint represented by the actor named <i>actor</i>.
The thread stopped at the watchpoints represented by the given <i>actor</i>s.


<i>This should provide more details about the watchpoint in the packet, instead of incurring another round-trip before we can display anything helpful.</i>
<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":"stepped" }
   { "type":"stepped" }
Line 201: Line 293:
   { "type":"pre-throw", "exception":<i>grip</i> }
   { "type":"pre-throw", "exception":<i>grip</i> }


The client had asked the thread to pause before throwing an exception; <i>grip</i> is the name of an actor representing the exception value being thrown; its parent is the pause actor. Control is still at the point of the throw; it has not yet passed to a catch clause. Single-stepping this thread will report either a "caught" or "uncaught" pause.
The client had asked the thread to pause before throwing an exception; <i>grip</i> is a grip on the exception value being thrown. Control is still at the point of the throw; it has not yet passed to a catch clause. Single-stepping this thread will report either a "caught" or "uncaught" pause.


   { "type":"caught", "exception":<i>grip</i> }
   { "type":"caught", "exception":<i>grip</i> }


The client stepped the thread from a "pre-throw" pause, and a catch clause has been found for the exception referred to by <i>grip</i>, whose parent is the pause actor; control is stopped at the head of the catch clause, with catch variable bindings made. If the catch is conditional, control is at the beginning of the condition.
The client stepped the thread from a "pre-throw" pause, and a catch clause has been found for the exception referred to by <i>grip</i>; control is stopped at the head of the catch clause, with catch variable bindings made. If the catch is conditional, control is at the beginning of the condition.


   { "type":uncaught", "exception":<i>grip</i> }
   { "type":uncaught", "exception":<i>grip</i> }
Line 214: Line 306:


The thread had been stopped in a conditional guard, and the client asked the thread to continue but pause before throwing an exception. The guard condition evaluated to false, and the thread is about to re-throw the exception value, <i>grip</i>.
The thread had been stopped in a conditional guard, and the client asked the thread to continue but pause before throwing an exception. The guard condition evaluated to false, and the thread is about to re-throw the exception value, <i>grip</i>.
  { "type":"eval-result", "value":<i>grip</i> }
The client's prior <tt>resume-and-evaluate</tt> command has completed; <i>grip</i> is a grip on the expression's value. See [[#Evaluating_Source-Language_Expressions|Evaluating Source-Language Expressions]] for details.
=== Pause Types ===
The <tt>pause-for</tt> property of an <tt>attach</tt> or <tt>resume</tt> packet (written as <i>pause-types</i>) is an object whose properties' names indicate which events the client is interested in. The vocabulary of names is the same as that of pause <tt>reason</tt> types, listed [[#Thread_Pauses|above]]. If a property's value in a <i>pause-type</i> is <tt>true</tt>, then the event is of interest.
For example, the following <i>resume</i> packet would instruct <i>thread</i> to continue until the thread is about to return from a function or is about to throw an exception:
  { "to":<i>thread</i>, "type":"resume",
    "pause-for": { "pre-return":true, "pre-throw":true } }
Certain pause types cause other pause types to be included automatically, if those pause types are not mentioned explicitly in <i>pause-types</i>:
{| frame="box" rules="all" cellpadding="8"
! Pause type
! Also implies, if not mentioned explicitly
|-
| <tt>pre-throw</tt>
| <tt>pre-throw-by-guard</tt>
|}
For some pause types, the property's value can provide additional detail.
To request that the thread pause before returning from a specific frame, the <i>pause-types</i> object can include a property of the form:
  { ... "pre-return":<i>frame-actor</i> ... }
where <i>frame-actor</i> is the name of the actor representing a specific stack frame, as given in the reply to a <tt>frames</tt> request.
=== Extending The Protocol With New Pause Types ===
The format of <i>reason</i> values in <tt>paused</tt> packets should be treated as a point of extension, with application-specific pause types added as the need arises. DOM events, DOM mutation, and web worker message transmission might all be interesting pause types. Debuggers unprepared for a particular event type will simply not request that type in the <tt>pause-for</tt> properties of its <tt>attach</tt> and <tt>resume</tt> packets, so extending the events a server supports should not disturb existing clients.


== Resuming a Thread ==
== Resuming a Thread ==
Line 221: Line 348:
   { "to":<i>thread</i>, "type":"resume", "pause-for":<i>pause-types</i> }
   { "to":<i>thread</i>, "type":"resume", "pause-for":<i>pause-types</i> }


This puts the thread in the <b>Running</b> state, but asks it to pause if any of the event described by <i>pause-types</i> occurs. The form of <i>pause-types</i> is described in [[#Pause_Types]].
This puts the thread in the <b>Running</b> state, but asks it to pause if any of the event described by <i>pause-types</i> occurs. The form of <i>pause-types</i> is described in [[#Pause_Types|Pause Types]].
 
A "resume" packet closes the pause actor the client provided in the "paused" or "interrupted" packet that began the pause.


== Interrupting a Thread ==
== Interrupting a Thread ==
Line 254: Line 383:


This acknowledges the exit and allows the thread actor name, <i>thread</i>, to be reused for other actors.
This acknowledges the exit and allows the thread actor name, <i>thread</i>, to be reused for other actors.
== Pause Types ==
The <tt>pause-for</tt> property of a <tt>attach</tt> and <tt>resume</tt> packets specifies which kinds of events in the thread the client is interested in hearing about. The <i>pause-types</i> value is an object whose properties are named after pause reason types (<tt>pre-call</tt> or <tt>stepped</tt>, for example) and have the value <tt>true</tt> if such pauses are of interest to the client. The property names are the possible values of the "type" field of the <i>reason</i> in a "paused" packet.
For example, the following <i>resume</i> packet would instruct <i>thread</i> to continue until the current function call is about to return, or the thread is about to throw an exception:
  { "to":<i>thread</i>, "type":"resume", "pause-for": { "pre-return":true, "pre-throw":true } }
<i>Not correct: this pauses the first time anything returns. We need something equivalent to GDB's frame-id: an inter-pause name for a specific frame, and a way to say "run until this frame is about to be popped".</i>
Certain pause types cause other pause types to be included automatically, if those pause types are not mentioned explicitly:
{| border="1"
!Pause type
!Also implies, if not mentioned explicitly
|-
| <tt>pre-throw</tt>
| <tt>pre-throw-by-guard</tt>
|}


= Inspecting Paused Threads =
= Inspecting Paused Threads =
Line 279: Line 388:
When a thread is in the <b>Paused</b> state, the debugger can make requests to inspect its stack, scope, and values.
When a thread is in the <b>Paused</b> state, the debugger can make requests to inspect its stack, scope, and values.


== Inspecting the Stack ==
== Listing Stack Frames ==


To inspect the thread's JavaScript stack, the client can send the following request:
To inspect the thread's JavaScript stack, the client can send the following request:
Line 293: Line 402:
where each <i>frame</i> has the form:
where each <i>frame</i> has the form:


   { "actor":<i>actor</i>, "depth":<i>depth</i>, "where":<i>location</i>,
   { "actor":<i>actor</i>, "depth":<i>depth</i>, "id":<i>id</i>,
     "callee":<i>callee</i>, "callee-name":<i>callee-name</i>, "host":<i>host</i>,
     "type":<i>type</i>, ... }
    "this",<i>this</i>, "arguments":<i>arguments</i>,
    "scope",<i>scope</i> }


where:
where:
Line 302: Line 409:
* <i>actor</i> is the name of an actor representing this frame;
* <i>actor</i> is the name of an actor representing this frame;
* <i>depth</i> is the number of this frame, starting with zero for the youngest frame;
* <i>depth</i> is the number of this frame, starting with zero for the youngest frame;
* <i>location</i> is a source location (see [[#Source_Locations|Source Locations]]);
* <i>id</i> is a unique number assigned to this stack frame, to help the client identify frames across pauses; and
* <i>callee</i> is a grip on the function value being called, or <tt>null</tt> if we are in global code;
* <i>type</i> is a string indicating what sort of frame this is.
* <i>callee-name</i> is the name of the callee, a string;
* <i>host</i> is true if this frame represents a call to a host function (perhaps implemented in C++);
* <i>this</i> is a grip on the value of <tt>this</tt> for this call;
* <i>arguments</i> is an array of grips on the actual values passed to the function; and
* <i>scope</i> is an actor representing the innermost scope contour at the current point of execution.


The argument list may be incomplete or inaccurate, for various reasons. If the program has assigned to its formal parameters, the original values passed may have been lost, and compiler optimizations may drop some argument values.
The frame may have other properties, depending on <i>type</i>.


<i>Location</i> and <i>scope</i> may be omitted for host functions.
All actors mentioned in the frame or grips appearing in the frame (<i>actor</i>, <i>callee</i>, <i>scope</i>, and so on) are parented by the current pause actor, as given in the "paused" or "interrupted" packet.


All actors mentioned in the frame (<i>actor</i>, <i>depth</i>, <i>callee</i>, <i>this</i>, the elements of <i>arguments</i>, and <i>scope</i>) are parented by the current pause actor, as given in the "paused" or "interrupted" packet.
=== Global Code Frames ===


A "grip" is a value that represents a specific value in the debuggee; for some types of values, a grip is an actor. See [[#Grips|Grips]] for details.
A frame for global code has the form:


<i>eval-in-frame</i>
  { "actor":<i>actor</i>, "depth":<i>depth</i>, "id":<i>id</i>,
    "type":"global", "where":<i>location</i>, "scope",<i>scope</i> }


<i>scopes should provide more information up-front</i>
where:
   
* <i>location</i> is the source location of the current point of execution in the global code (see [[#Source_Locations|Source Locations]]);
* <i>scope</i> is an actor representing the innermost scope contour at the current point of execution;


== Source Locations ==
and other properties are as above.


<i>simple script + line</i>
=== Function Call Frames ===


<i>eval call number + location</i>
A frame for an ordinary JavaScript function call has the form:


<i>Function call number + location</i>
  { "actor":<i>actor</i>, "depth":<i>depth</i>, "id":<i>id</i>,
    "type":"call",
    "where":<i>location</i>, "scope",<i>scope</i>,
    "callee":<i>callee</i>, "callee-name":<i>callee-name</i>,
    "this",<i>this</i>, "arguments":<i>arguments</i> }


== Scope Contours ==
where:


<i>scopes should include an actor, but provide a lot of information up-front</i>
* <i>where</i> is the current point of execution within the callee;
* <i>callee</i> is a grip on the function value being called;
* <i>callee-name</i> is the name of the callee, a string;
* <i>this</i> is a grip on the value of <tt>this</tt> for this call;
* <i>arguments</i> is an array of grips on the actual values passed to the function;


<i>enumerate</i>
and other properties are as above.


<i>assign</i>
The argument list may be incomplete or inaccurate, for various reasons. If the program has assigned to its formal parameters, the original values passed may have been lost, and compiler optimizations may drop some argument values.


== Breakpoints ==
=== Host Function Call Frames ===


== Watchpoints ==
A frame for a call to a host function (a function provided by the JavaScript implementation, usually written in the same language as the implementation itself) has the form:


= Grips =
  { "actor":<i>actor</i>, "depth":<i>depth</i>, "id":<i>id</i>,
    "type":"host-call",
    "callee":<i>callee</i>, "callee-name":<i>callee-name</i>,
    "this",<i>this</i>, "arguments":<i>arguments</i> }


A grip is a value that represents a specific value in the debuggee. A grip has one of the following forms:
where the properties are as defined above. (Compared to an ordinary call, the <tt>where</tt> and <tt>scope</tt> properties are missing.)


  <i>value</i>
=== Eval Frames ===


where <i>value</i> is a string, a number, or a boolean value. For these types of values, the grip is simply the JSON form of the value.
A frame for a call to eval has the form:


   { "type":"null" }
   { "actor":<i>actor</i>, "depth":<i>depth</i>, "id":<i>id</i>,
    "type":"eval", "where":<i>location</i>, "scope",<i>scope</i> }


This represents the JavaScript <tt>null</tt> value. (This representation allows clients implemented in JavaScript to use <tt>typeof(<i>grip</i>) == "object"</tt> to decide whether the grip is simple or not, as <tt>typeof(null)</tt> is <tt>"object"</tt>.)
where the properties are as defined above.


  { "type":"undefined" }
=== Debugger Eval Frames ===


This represents the JavaScript <tt>undefined</tt> value, which has no representation in JSON.
When the debugger evaluates an expression, that appears on the stack as a special kind of frame, of the form:


   { "type":"long-string", "initial":<i>initial</i>, "length":<i>length</i>, "actor":<i>actor</i> }
   { "actor":<i>actor</i>, "depth":<i>depth</i>, "id":<i>id</i>,
    "type":"debugger-eval", "where":<i>location</i>, "scope",<i>scope</i> }


This represents a very long string (where "very long" is defined at the server's discretion). <i>Initial</i> is the initial portion of the string, <i>length</i> is its length, and <i>actor</i> can be consulted for the rest of the string, as explained below.
where the properties are as defined above. In this case, <i>where</i> will be a location inside the expression provided by the debugger.


  { "type":"object", "class":<i>class-name</i>, "actor":<i>actor</i> }
== Popping Stack Frames ==


This represents a JavaScript object whose class is <i>class-name</i>. <i>Actor</i> can be consulted for its contents, as explained below.
The client can remove frames from the stack by sending a request of the form:


All actors appearing in grips are children of the pause actor; their names become invalid when the thread is resumed.
  { "to":<i>frame-actor</i>, "type":"pop", "value":<i>value</i> }


Garbage collection operates below the level of this protocol, and will never free objects visible to the client via the protocol. Thus, actors representing JavaScript objects are effectively garbage collection roots.
where <i>frame-actor</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:


If the client wishes to hold a reference to an object in the debuggee across pauses, it must send a request to the grip's actor of the form:
  { "from":<i>frame-actor</i>, "watches":[<i>watch-actor</i> ...] }


  { "to":<i>grip-actor</i>, "type":"thread-grip" }
where each <i>watch-actor</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.


where <i>grip-actor</i> is the pause-parented actor from the existing grip. The grip actor will reply:
== Source Locations ==


  { "from":<i>grip-actor</i>, "thread-grip":<i>thread-grip</i> }
<i>TODO: simple script + line</i>


where <i>thread-grip</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 this grip by sending the grip actor a request of the form:
<i>TODO: eval call number + location</i>


  { "to":<i>thread-grip-actor</i>, "type":"release-grip", "grip":<i>grip</i> }
<i>TODO: Function call number + location</i>


The thread grip actor will reply, simply:
== Scope Contours ==


  { "from":<i>thread-grip-actor</i> }
<i>TODO: scopes should include an actor, but provide a lot of information up-front</i>


The client may only send messages to grip actors while the thread is paused, even if the grip actors are children of the thread, not the pause.
<i>TODO: enumerate</i>


== Objects ==
<i>TODO: assign</i>


<i>can only be manipulated while paused</i>
== Evaluating Source-Language Expressions ==


<i>requests modeled after ES5 object inspection API</i>
To evaluate a source-language expression in a thread, the client sends a specialized <tt>resume</tt> request of the form:


<i>special stuff for arrays</i>
  { "to":<i>thread</i>, "resume-and-evaluate":<i>expr</i>, "frame":<i>frame</i>, "pause-for":<i>pause-types</i> }


<i>special stuff for functions</i>
This resumes the thread, but has it begin evaluation of <i>expr</i>, a string holding a source-language expression, instead of continuing execution where the pause took place. The evaluation takes place in a new [[#Debugger Eval Frames|Debugger Eval Frame]], pushed on the stack. When evaluation of <i>expr</i> completes, the client will report an <tt>eval-result</tt> pause containing the expression's value.


== Long Strings ==
== Breakpoints ==


The client can find the full contents of a long string by sending a request to the long string grip actor of the form:
== Watchpoints ==


  { "to":<i>grip-actor</i>, "type":"substring", "start":<i>start</i>, "length":<i>length</i> }
== Frame Pop Watches ==
 
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-actor</i>, "substring":<i>string</i> }
 
where <i>string</i> is the requested portion of the string the actor represents.
Confirmed users
497

edits

Navigation menu