Confirmed users
231
edits
No edit summary |
No edit summary |
||
| Line 142: | Line 142: | ||
</pre> | </pre> | ||
== Inspecting a stack frame<br> == | == Inspecting a stack frame<br> == | ||
When enumerating the list of stack frames, the application can request more information about the frame, such as the function call parameter names and values, inspect the prototype chain, and more:<br> | When enumerating the list of stack frames, the application can request more information about the frame, such as the function call parameter names and values, inspect the prototype chain, and more:<br> | ||
<pre>/** | <pre>/** | ||
* Helper function to inspect the provided frame. | * Helper function to inspect the provided frame. | ||
| Line 171: | Line 171: | ||
} | } | ||
} | } | ||
/** | |||
* Helper function that retrieves the specified object's properties. | |||
*/ | |||
function getObjectProperties(aObject) | |||
{ | |||
let thisClient = client.activeThread.pauseGrip(aObject); | |||
thisClient.prototypeAndProperties(function(aResponse) { | |||
// Get prototype as a protocol-specified grip. | |||
if (aResponse.prototype.type != "null") { | |||
dump("__proto__: " + aResponse.prototype.toSource() + "\n"); | |||
} | |||
// Get the rest of the object's own properties as protocol-specified grips. | |||
for each (let prop in Object.keys(aResponse.ownProperties)) { | |||
dump(prop + ": " + aResponse.ownProperties[prop].toSource() + "\n"); | |||
} | |||
}); | |||
} | |||
</pre> | |||
= Example application<br> = | |||
The source code for a complete application program can be seen below:<br> | |||
<pre>/* | |||
* Debugger API demo. | |||
* Try it in Scratchpad with Environment -> Browser, using | |||
* http://htmlpad.org/debugger/ as the current page. | |||
*/ | |||
let client; | |||
let threadClient; | |||
function startDebugger() | |||
{ | |||
// Start the server. | |||
if (!DebuggerServer.initialized) { | |||
DebuggerServer.init(); | |||
DebuggerServer.addBrowserActors(); | |||
} | |||
// Listen to an nsIPipe | |||
let transport = DebuggerServer.connectPipe(); | |||
// For an nsIServerSocket we do this: | |||
// DebuggerServer.openListener(aPort, aLocalOnly); | |||
// ...and this at the client: | |||
// let transport = debuggerSocketConnect(aHost, aPort); | |||
// Start the client. | |||
client = new DebuggerClient(transport); | |||
// Attach listeners for client events. | |||
client.addListener("tabNavigated", onTab); | |||
client.addListener("newScript", fooListener); | |||
client.ready(function(aType, aTraits) { | |||
// Now the client is conected to the server. | |||
debugTab(); | |||
}); | |||
} | |||
function shutdownDebugger() | |||
{ | |||
client.close(); | |||
} | |||
/** | |||
* Start debugging the current tab. | |||
*/ | |||
function debugTab() | |||
{ | |||
// Get the list of tabs to find the one to attach to. | |||
client.listTabs(function(aResponse) { | |||
// Find the active tab. | |||
let tab = aResponse.tabs[aResponse.selected]; | |||
// Attach to the tab. | |||
client.attachTab(tab.actor, function(aResponse, aTabClient) { | |||
if (!aTabClient) return; | |||
// Attach to the thread (context). | |||
client.attachThread(aResponse.threadActor, function(aResponse, aThreadClient) { | |||
if (!aThreadClient) return; | |||
threadClient = aThreadClient; | |||
// Attach listeners for thread events. | |||
threadClient.addListener("paused", onPause); | |||
threadClient.addListener("resumed", fooListener); | |||
threadClient.addListener("detached", fooListener); | |||
threadClient.addListener("framesadded", onFrames); | |||
threadClient.addListener("framescleared", fooListener); | |||
threadClient.addListener("scriptsadded", onScripts); | |||
threadClient.addListener("scriptscleared", fooListener); | |||
// Resume the thread. | |||
threadClient.resume(); | |||
// Debugger is now ready and debuggee is running. | |||
}); | |||
}); | |||
}); | |||
} | |||
/** | |||
* Handler for location changes. | |||
*/ | |||
function onTab() | |||
{ | |||
// Detach from the previous thread. | |||
client.activeThread.detach(function() { | |||
// Detach from the previous tab. | |||
client.activeTab.detach(function() { | |||
// Start debugging the new tab. | |||
debugTab(); | |||
}); | |||
}); | |||
} | |||
/** | |||
* Handler for entering pause state. | |||
*/ | |||
function onPause() | |||
{ | |||
// Get the top 20 frames in the server's frame stack cache. | |||
client.activeThread.fillFrames(20); | |||
// Get the scripts loaded in the server's source script cache. | |||
client.activeThread.fillScripts(); | |||
} | |||
/** | |||
* Handler for framesadded events. | |||
*/ | |||
function onFrames() | |||
{ | |||
// Get the list of frames in the server. | |||
for each (let frame in client.activeThread.cachedFrames) { | |||
// frame is a Debugger.Frame grip. | |||
dump("frame: " + frame.toSource() + "\n"); | |||
inspectFrame(frame); | |||
} | |||
} | |||
/** | |||
* Handler for scriptsadded events. | |||
*/ | |||
function onScripts() | |||
{ | |||
// Get the list of scripts in the server. | |||
for each (let script in client.activeThread.cachedScripts) { | |||
// script is a Debugger.Script grip. | |||
dump("script: " + script.toSource() + "\n"); | |||
} | |||
// Resume execution, since this is the last thing going on in the paused | |||
// state and there is no UI in this program. Wait a bit so that object | |||
// inspection has a chance to finish. | |||
setTimeout(function() { | |||
threadClient.resume(); | |||
}, 1000); | |||
} | |||
/** | |||
* Helper function to inspect the provided frame. | |||
*/ | |||
function inspectFrame(aFrame) | |||
{ | |||
// Get the "this" object. | |||
if (aFrame["this"]) { | |||
getObjectProperties(aFrame["this"]); | |||
} | |||
// Add "arguments". | |||
if (aFrame.arguments && aFrame.arguments.length > 0) { | |||
// frame.arguments is a regular Array. | |||
dump("frame.arguments: " + aFrame.arguments.toSource() + "\n"); | |||
// Add variables for every argument. | |||
let objClient = client.activeThread.pauseGrip(aFrame.callee); | |||
objClient.nameAndParameters(function(aResponse) { | |||
for (let i = 0; i < aResponse.parameters.length; i++) { | |||
let name = aResponse.parameters[i]; | |||
let value = aFrame.arguments[i]; | |||
if (typeof value == "object" && value.type == "object") { | |||
getObjectProperties(value); | |||
} | |||
} | |||
}); | |||
} | |||
} | |||
/** | /** | ||
* Helper function that retrieves the specified object's properties. | * Helper function that retrieves the specified object's properties. | ||
| Line 188: | Line 364: | ||
}); | }); | ||
} | } | ||
/** | |||
* Generic event listener. | |||
*/ | |||
function fooListener(aEvent) | |||
{ | |||
dump(aEvent + "\n"); | |||
} | |||
// Run the program. | |||
startDebugger(); | |||
// Execute the following line to stop the program. | |||
//shutdownDebugger(); | |||
</pre> | </pre> | ||
You can try out this program using the Scratchpad. | |||