Debugger Client API: Difference between revisions

From MozillaWiki
Jump to navigation Jump to search
(Debugger Client API)
 
No edit summary
Line 188: Line 188:
</pre>  
</pre>  
<br>
<br>
See [http://past.pastebin.mozilla.org/1376464 here] for the full example program.

Revision as of 16:00, 14 November 2011

/*
 * 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.
 */
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");
    }
  });
}

/**
 * Generic event listener.
 */
function fooListener(aEvent)
{
  dump(aEvent + "\n");
}

// Run the program.
startDebugger();
// Execute the following line to stop the program.
//shutdownDebugger();



See here for the full example program.