mozilla

Revision 85273 of JavaScript Debugger Service

  • Revision slug: Code_snippets/JavaScript_Debugger_Service
  • Revision title: JavaScript Debugger Service
  • Revision id: 85273
  • Created:
  • Creator: Mh512
  • Is current revision? No
  • Comment 21 words added
Tags: 

Revision Content

The JavaScript Debugger Service (or simply JSD) is an XPCOM Component that allows the tracking of JavaScript while it is being executed in the browser.

An Overview

Acquiring the Service

We acquire the service by calling the XPCOM object.

var jsd = Components.classes["@mozilla.org/js/jsd/debugger-service;1"]
          .getService(Components.interfaces.jsdIDebuggerService);
jsd.on(); // enables the service
if (jsd.isOn) jsd.off(); // disables the service

Hooks

JSD operates using the events hook mechanism. Next, we add code to the various hooks.

jsd.scriptHook = {
	onScriptCreated: function(script) {
		// your function here
	},
	onScriptDestroyed: function(script) {
		// your function here
	}
};
jsd.errorHook = {
	onError: function(message, fileName, lineNo, colNo, flags, errnum, exc) {
		// your function here
	}
};
		
// triggered when jsd.errorHook[onError] returns false 
jsd.debugHook = {
	onExecute: function(frame, type, rv) {
		 // your function here
	}
};

jsd.enumerateScripts({
	// the enumerateScript method will be called once for every script JSD knows about
	enumerateScript: function(script) {
		// your function here
	}
});

A Simple Stack Trace

Here, we will show how to implement a simple JavaScript stack trace using the JSD.

jsd.errorHook = {
	onError: function(message, fileName, lineNo, colNo, flags, errnum, exc) {
		dump(message + "@" + fileName + "@" + lineNo + "@" + colNo + "@" + errnum + "\n");
				
		// check message type
		var jsdIErrorHook = Components.interfaces.jsdIErrorHook;
		var messageType;		
		if (flags & jsdIErrorHook.REPORT_ERROR)
			messageType = "Error";
		if (flags & jsdIErrorHook.REPORT_WARNING)
			messageType = "Warning";
		if (flags & jsdIErrorHook.REPORT_EXCEPTION)
			messageType = "Uncaught-Exception";
		if (flags & jsdIErrorHook.REPORT_STRICT)
			messageType += "-Strict";

		dump(messageType + "\n");

		return false;	// trigger debugHook
		// return true; if you do not wish to trigger debugHook
	}
};
		
// note that debugHook does not _always_ trigger when jsd.errorHook[onError] returns false 
// it is not well-known why debugHook sometimes fails to trigger 
jsd.debugHook = {
	onExecute: function(frame, type, rv) {
		stackTrace = "";
		for (var f = frame; f; f = f.callingFrame) {
			stackTrace += f.script.fileName + "@" + f.line + "@" + f.functionName + "\n";
		}
		dump(stackTrace);

		return Components.interfaces.jsdIExecutionHook.RETURN_CONTINUE;
	}
};

Filters

JSD also allows the use of filters to track which scripts should trigger the hooks. Note that the jsdIFilter only applies to jsdIExecutionHooks, which are breakpointHook, debugHook, debuggerHook, interruptHook and throwHook.

We create a generic createFilter function that takes care of the job.

function createFilter(pattern, pass) {
	var jsdIFilter = Components.interfaces.jsdIFilter;
	
	var filter = {
		globalObject: null,
		flags: pass ? (jsdIFilter.FLAG_ENABLED | jsdIFilter.FLAG_PASS) : jsdIFilter.FLAG_ENABLED,
		urlPattern: pattern,
		startLine: 0,
		endLine: 0
	};
	return filter;
},

We then add the filters we want.

jsd.clearFilters();

// we exclude the scripts with the following filenames from being tracked
jsd.appendFilter(createFilter("*/firefox/components/*"));
jsd.appendFilter(createFilter("*/firefox/modules/*"));
jsd.appendFilter(createFilter("XStringBundle"));
jsd.appendFilter(createFilter("chrome://*"));
jsd.appendFilter(createFilter("x-jsd:ppbuffer*"));
jsd.appendFilter(createFilter("XPCSafeJSObjectWrapper.cpp"));
jsd.appendFilter(createFilter("file://*"));

 

Learning More

The best way to learn about the API behind JSD is to look at the source code from Mozilla Central.
You should also look at the documentation (available in the source code) for associated interfaces:

There references listed below have also proved insightful on how the JSD works.

References

Revision Source

<p>The JavaScript Debugger Service (or simply JSD) is an XPCOM Component that allows the tracking of JavaScript while it is being executed in the browser.</p>
<h2>An Overview</h2>
<h3>Acquiring the Service</h3>
<p>We acquire the service by calling the XPCOM object.</p>
<pre>var jsd = Components.classes["@mozilla.org/js/jsd/debugger-service;1"]
          .getService(Components.interfaces.jsdIDebuggerService);
jsd.on(); // enables the service
if (jsd.isOn) jsd.off(); // disables the service
</pre>
<h3>Hooks</h3>
<p>JSD operates using the events hook mechanism. Next, we add code to the various hooks.</p>
<pre>jsd.scriptHook = {
	onScriptCreated: function(script) {
		// your function here
	},
	onScriptDestroyed: function(script) {
		// your function here
	}
};
jsd.errorHook = {
	onError: function(message, fileName, lineNo, colNo, flags, errnum, exc) {
		// your function here
	}
};
		
// triggered when jsd.errorHook[onError] returns false 
jsd.debugHook = {
	onExecute: function(frame, type, rv) {
		 // your function here
	}
};

jsd.enumerateScripts({
	// the enumerateScript method will be called once for every script JSD knows about
	enumerateScript: function(script) {
		// your function here
	}
});
</pre><h3>A Simple Stack Trace</h3>
<p>Here, we will show how to implement a simple JavaScript stack trace using the JSD.</p>
<pre>jsd.errorHook = {
	onError: function(message, fileName, lineNo, colNo, flags, errnum, exc) {
		dump(message + "@" + fileName + "@" + lineNo + "@" + colNo + "@" + errnum + "\n");
				
		// check message type
		var jsdIErrorHook = Components.interfaces.jsdIErrorHook;
		var messageType;		
		if (flags &amp; jsdIErrorHook.REPORT_ERROR)
			messageType = "Error";
		if (flags &amp; jsdIErrorHook.REPORT_WARNING)
			messageType = "Warning";
		if (flags &amp; jsdIErrorHook.REPORT_EXCEPTION)
			messageType = "Uncaught-Exception";
		if (flags &amp; jsdIErrorHook.REPORT_STRICT)
			messageType += "-Strict";

		dump(messageType + "\n");

		return false;	// trigger debugHook
		// return true; if you do not wish to trigger debugHook
	}
};
		
// note that debugHook does not _always_ trigger when jsd.errorHook[onError] returns false 
// it is not well-known why debugHook sometimes fails to trigger 
jsd.debugHook = {
	onExecute: function(frame, type, rv) {
		stackTrace = "";
		for (var f = frame; f; f = f.callingFrame) {
			stackTrace += f.script.fileName + "@" + f.line + "@" + f.functionName + "\n";
		}
		dump(stackTrace);

		return Components.interfaces.jsdIExecutionHook.RETURN_CONTINUE;
	}
};
</pre>
<h3>Filters</h3>
<p>JSD also allows the use of filters to track which scripts should trigger the hooks. Note that the <code>jsdIFilter</code> only applies to <code>jsdIExecutionHooks</code>, which are <code>breakpointHook</code>, <code>debugHook</code>, <code>debuggerHook</code>, <code>interruptHook</code> and <code>throwHook</code>.</p>
<p>We create a generic <code>createFilter</code> function that takes care of the job.</p>
<pre>function createFilter(pattern, pass) {
	var jsdIFilter = Components.interfaces.jsdIFilter;
	
	var filter = {
		globalObject: null,
		flags: pass ? (jsdIFilter.FLAG_ENABLED | jsdIFilter.FLAG_PASS) : jsdIFilter.FLAG_ENABLED,
		urlPattern: pattern,
		startLine: 0,
		endLine: 0
	};
	return filter;
},
</pre>
<p>We then add the filters we want.</p>
<pre>jsd.clearFilters();

// we exclude the scripts with the following filenames from being tracked
jsd.appendFilter(createFilter("*/firefox/components/*"));
jsd.appendFilter(createFilter("*/firefox/modules/*"));
jsd.appendFilter(createFilter("XStringBundle"));
jsd.appendFilter(createFilter("chrome://*"));
jsd.appendFilter(createFilter("x-jsd:ppbuffer*"));
jsd.appendFilter(createFilter("XPCSafeJSObjectWrapper.cpp"));
jsd.appendFilter(createFilter("file://*"));
</pre>
<p> </p>
<h2>Learning More</h2>
<p>The best way to learn about the API behind JSD is to look at the <a class=" external" href="http://mxr.mozilla.org/mozilla-central/source/js/jsd/idl/jsdIDebuggerService.idl" title="http://mxr.mozilla.org/mozilla-central/source/js/jsd/idl/jsdIDebuggerService.idl">source code from Mozilla Central</a>.<br>
You should also look at the documentation (available in the source code) for associated interfaces:</p>
<ul> <li><a class=" external" href="http://www.oxymoronical.com/experiments/apidocs/interface/jsdIFilter" title="http://www.oxymoronical.com/experiments/apidocs/interface/jsdIFilter">jsdIFilter</a></li> <li><a class=" external" href="http://www.oxymoronical.com/experiments/apidocs/interface/jsdIStackFrame" title="http://www.oxymoronical.com/experiments/apidocs/interface/jsdIStackFrame">jsdIStackFrame</a></li> <li><a class=" external" href="http://www.oxymoronical.com/experiments/apidocs/interface/jsdIScript" title="http://www.oxymoronical.com/experiments/apidocs/interface/jsdIScript">jsdIScript</a></li> <li><a class=" external" href="http://www.oxymoronical.com/experiments/apidocs/interface/jsdIValue" title="http://www.oxymoronical.com/experiments/apidocs/interface/jsdIValue">jsdIValue</a></li>
</ul>
<p>There references listed below have also proved insightful on how the JSD works.</p>
<h3>References</h3>
<ul> <li><a class=" external" href="http://www.hungryfools.com/2008/03/i-was-really-determined-to-figure-out.html" title="http://www.hungryfools.com/2008/03/i-was-really-determined-to-figure-out.html">A quick and dirty introduction by Lei</a></li> <li><a class=" external" href="http://mxr.mozilla.org/mozilla/source/extensions/venkman/resources/content/venkman-debugger.js" title="http://mxr.mozilla.org/mozilla/source/extensions/venkman/resources/content/venkman-debugger.js">Venkman JavaScript Debugger source code</a></li> <li><a class=" external" href="http://code.google.com/p/fbug/source/browse/branches/firebug1.5/components/firebug-service.js" title="http://code.google.com/p/fbug/source/browse/branches/firebug1.5/components/firebug-service.js">Firebug Service source code</a></li> <li><a class=" external" href="http://www.almaden.ibm.com/cs/people/bartonjj/fireclipse/test/DynLoadTest/WebContent/DynamicJavascriptErrors.htm" title="http://www.almaden.ibm.com/cs/people/bartonjj/fireclipse/test/DynLoadTest/WebContent/DynamicJavascriptErrors.htm">Finding Errors in Dynamically Created Javascript Source</a></li>
</ul>
Revert to this revision