Remote Debugging Protocol: Difference between revisions

Add object property access requests.
(Describe lexical environments.)
(Add object property access requests.)
Line 50: Line 50:


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.
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.
Any actor can send reply to a request it is unable to carry out with an <b>error reply</b> of the form:
  { "from":<i>actor</i>, "error":<i>name</i>, "message":<i>message</i> }
where <i>name</i> is a JSON string naming what went wrong, and <i>message</i> is an English error message. Error <i>name</i>s are specified by the protocol; the client can use the name to identify which error condition arose. The <i>message</i> may vary from implementation to implementation, and should only be displayed to the user as a last resort, as the server lacks enough information about the user interface context to provide appropriate messages.


Packets not described as requests or replies are part of some more complicated interaction, which should be spelled out in more detail.
Packets not described as requests or replies are part of some more complicated interaction, which should be spelled out in more detail.
Line 80: Line 86:


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.
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.
For example, the following table shows some JavaScript expressions and the grips that would represent them in the protocol:
{| frame="box" rules="all" cellpadding="8"
! JavaScript Expression
! Grip
|-
| 42
| 42
|-
| true
| true
|-
| "nasu"
| "nasu"
|-
| (void 0)
| { "type":"undefined" }
|-
| ({x:1})
| { "type":"object", "class":"Object", "actor":24 }
|}


Garbage collection will never free objects visible to the client via the protocol. Thus, actors representing JavaScript objects are effectively garbage collection roots.
Garbage collection will never free objects visible to the client via the protocol. Thus, actors representing JavaScript objects are effectively garbage collection roots.
Line 85: Line 113:
== Objects ==
== Objects ==


<i>TODO: can only be manipulated while paused</i>
While a thread is paused, the client can send requests to the actors appearing in object grips to examine the objects they represent in more detail.


<i>TODO: requests modeled after ES5 object inspection API</i>
=== Property Descriptors ===
 
Protocol requests that describe objects' properties to the client often use <b>descriptors</b>, JSON values modeled after ECMAScript 5's property descriptors, to describe individual properties.
 
A descriptor has the form:
 
  { "enumerable":<i>enumerable</i>, "configurable":<i>configurable</i>, ... }
 
where <i>enumerable</i> and <i>configurable</i> are boolean values indicating whether the property is enumerable and configurable, and additional properties are present depending on what sort of property it is.
 
A descriptor for a data property has the form:
 
  { "enumerable":<i>enumerable</i>, "configurable":<i>configurable</i>,
    "value":<i>value</i>, "writeable":<i>writeable</i> }
 
where <i>value</i> is a grip on the property's value, and <i>writeable</i> is a boolean value indicating whether the property is writeable.
 
A descriptor for an accessor property has the form:
 
  { "enumerable":<i>enumerable</i>, "configurable":<i>configurable</i>,
    "get":<i>getter</i>, "set":<i>setter</i> }
 
where <i>getter</i> and <i>setter</i> are grips on the property's getter and setter functions. These may be <tt>{ "type":"undefined" }</tt> if the property lacks the given accessor function.
 
For example, if the JavaScript program being debugged evaluates the expression:
 
  ({x:10, y:"kaiju", get a() { return 42; }})
 
then a grip on this value would have the form:
 
  { "type":"object", "class":"Object", "actor":<i>actor</i> }
 
and sending a [[#Finding_An_Object's_Prototype_And_Properties|"prototype-and-properties"]] request to <i>actor</i> would produce the following reply:
 
  { "from":<i>actor</i>, "prototype": { "type":"object", "class":"Object", "actor":<i>objproto-actor</i> },
    "own-properties": { "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-actor</i> }
                            }
                      }
  }
 
=== Finding An Object's Prototype And Properties ===
 
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-actor</i>, "type":"prototype-and-properties" }
 
to which the grip actor replies:
 
  { "from":<i>grip-actor</i>, "prototype":<i>prototype</i>,
    "own-properties":<i>own-properties</i> }
 
where <i>prototype</i> is a grip on the object's prototype (possibly <tt>{ "type":"null" }</tt>), and <i>own-properties</i> has the form:
 
  { <i>name</i>:<i>descriptor</i>, ... }
 
with a <i>name</i>:<i>descriptor</i> pair for each of the object's own properties.
 
=== Finding an Object's Prototype ===
 
To find an object's prototype, a client can send the object's grip's actor a request of the form:
 
  { "to":<i>grip-actor</i>, "type":"prototype" }
 
to which the grip actor replies:
 
  { "from":<i>grip-actor</i>, "prototype":<i>prototype</i> }
 
where <i>prototype</i> is a grip on the object's prototype (possibly <tt>{ "type":"null" }</tt>).
 
=== Listing an Object's Own Properties' Names ===
 
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-actor</i>, "type":"own-property-names" }
 
to which the grip actor replies:
 
  { "from":<i>grip-actor</i>, "own-property-names": [ <i>name<i>, ... ] }
 
where each <i>name</i> is a string naming an own property of the object.
 
=== Finding Descriptors For Single Properties ===
 
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-actor</i>, "type":"property" }
 
to which the grip actor replies:
 
  { "from":<i>grip-actor</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.


<i>TODO: special stuff for arrays</i>
<i>TODO: special stuff for arrays</i>
Line 94: Line 216:


<i>TODO: find function's source position</i>
<i>TODO: find function's source position</i>
<i>TODO: descriptors for Harmony proxies</i>


== Long Strings ==
== Long Strings ==
Line 204: Line 328:


Note that the rules here apply to the client's interactions with each thread agent separately. A client may send an "interrupt" to one thread agent while awaiting a reply to a request sent to a different thread agent.
Note that the rules here apply to the client's interactions with each thread agent separately. A client may send an "interrupt" to one thread agent while awaiting a reply to a request sent to a different thread agent.
<i>TODO: What about user selecting nodes in displayed content? Should those be eventy things the client can receive in the "paused" state? What does that mean for the "request"/"reply" pattern?</i>


== Attaching To a Thread ==
== Attaching To a Thread ==
Line 398: Line 524:
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:


   { "to":<i>thread</i>, "type":"frames", "limit":<i>limit</i> }
   { "to":<i>thread</i>, "type":"frames", "start":<i>start</i>, "count":<i>count</i> }


The <tt>limit</tt> property is optional. If present, the reply contains at most <i>limit</i> frames from the young end of the stack; if absent, the reply describes the entire stack.
The <tt>start</tt> and <tt>count</tt> properties are optional. If present, <i>start</i> gives the number of the youngest stack frame the reply should describe, where the youngest frame on the stack is frame number zero; if absent, <i>start</i> is taken to be zero. If present, <i>count</i> specifies the maximum number of frames the reply should describe; if absent, it is taken to be infinity. (Clients should probably avoid sending <tt>frames</tt> requests with no <i>count</i>, to avoid being flooded by frames from unbounded recursion.)


The thread replies as follows:
The thread replies as follows:
Line 414: Line 540:


* <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 on the stack;
* <i>id</i> is a unique number assigned to this stack frame, to help the client identify frames across pauses; and
* <i>id</i> is a unique number assigned to this stack frame, to help the client identify frames across pauses; and
* <i>type</i> is a string indicating what sort of frame this is.
* <i>type</i> is a string indicating what sort of frame this is.
Line 498: Line 624:


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 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.
<i>TODO: specify the error to return if the frame cannot be popped --- can host (C++) function frames be popped?</i>


== Source Locations ==
== Source Locations ==
Line 505: Line 633:
   { "url":<i>url</i>, "line":<i>line</i>, "column":<i>column</i> }
   { "url":<i>url</i>, "line":<i>line</i>, "column":<i>column</i> }


This refers to line <i>line</i>, column <i>column</i> of the source code loaded from <i>url</i>. If column information i
This refers to line <i>line</i>, column <i>column</i> of the source code loaded from <i>url</i>. Line and column numbers start with 1. If <i>column</i> or <i>line</i> are omitted, they default to 1.


   { "eval":<i>location</i>, "line":<i>line</i>, "column":<i>column</i> }
   { "eval":<i>location</i>, "id":<i>id</i>, "line":<i>line</i>, "column":<i>column</i> }


This refers to line <i>line</i>, column <i>column</i> of the source code passed to the call to eval at <i>location</i>.
This refers to line <i>line</i>, column <i>column</i> of the source code passed to the call to eval at <i>location</i>. To distinguish the different texts passed to eval, each is assigned a unique integer, <i>id</i>.


   { "function":<i>location</i>, "line":<i>line</i>, "column":<i>column</i> }
   { "function":<i>location</i>, "id":<i>id</i>, "line":<i>line</i>, "column":<i>column</i> }


This refers to line <i>line</i>, column <i>column</i> of the source code passed to the call to the <tt>Function</tt> constructor at <i>location</i>.
This refers to line <i>line</i>, column <i>column</i> of the source code passed to the call to the <tt>Function</tt> constructor at <i>location</i>. To distinguish the different texts passed to eval, each is assigned a unique integer, <i>id</i>.


As indicated, locations can be nested: a location like this one:
As indicated, locations can be nested: a location like this one:
Line 569: Line 697:
   { "to":<i>env-actor</i>, "type":"assign", "name":<i>name</i>, "value":<i>value</i> }
   { "to":<i>env-actor</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).
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-actor</i> }
 
If the named identifier is immutable, the actor will send an error reply of the form:
 
  { "from":<i>env-actor</i>, "error":"immutable-binding", "message":<i>message</i> }


== Evaluating Source-Language Expressions ==
== Evaluating Source-Language Expressions ==


To evaluate a source-language expression in a thread, the client sends a specialized <tt>resume</tt> request of the form:
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>, "client-evaluate":<i>expr</i>, "frame":<i>frame</i>, "pause-for":<i>pause-types</i> }
   { "to":<i>thread</i>, "client-evaluate":<i>expr</i>, "frame":<i>frame</i>, "pause-for":<i>pause-types</i> }
Line 582: Line 716:


== Breakpoints ==
== Breakpoints ==
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-breakpoint", "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-location":<i>actual-location</i> }
where <i>actor</i> is an actor representing the breakpoint, and <i>actual-location</i> is the location at which the breakpoint was really set. If <i>location</i> and <i>actual-location</i> are the same, then the <tt>actual-location</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-script" }
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-column" }


== Watchpoints ==
== Watchpoints ==


== Frame Pop Watches ==
== Frame Pop Watches ==
<i>TODO: DOM node inspection, highlighting</i>
Confirmed users
496

edits