We really need a XPCOM debugger

A few weeks ago, I was wondering about the possibility of debugging C++ and JS at the same time. Venkman’s a nice JS-only debugger. I’m using Microsoft’s VC++ 2005 Express Edition to debug on the C++ side. (Mind you, I’m really not that great at C++ debugging.) I wondered, on a theoretical basis, how I would debug a problem that happened somewhere in between two JS frames, amid several C++ frames.

As I started pondering potential solutions, it was pretty obvious that I couldn’t even get a good stack of the JS and C++ frames at the same time. Components.stack from Venkman returns a nsIStackFrame object. This object has partial info about the JS stack, and none about the C++ frames. For example, I could get the filename and line numbers of stack frames in JS, but I couldn’t get the source line. I’m running a debug build of SeaMonkey trunk, and there was no information to be had at all about the C++ code. This is no better than what Error.prototype.stack returns.

Read on for more details, including the reason why a XPCOM debugger is now necessary. Or feel free to blame me for not knowing how to really use a C++ debugger.

I started wondering about this when I discovered a bug to add a JavaScript-based assert() function. Personally, I thought it didn’t go far enough. If you’re going to assert in chrome, it ought to at least launch a debugger like Venkman. (Of course, my own idea for jslib didn’t do that either. 🙂 )

On the side, there was a discussion on IRC and in-person with timeless and a few others about the possibility of JavaScript calling NS_ASSERTION. Yes, I know, assertions should be fatal and this essentially means JavaScript can demand the program crash. This particular kind of crash should only be requested in extreme conditions, like when Venkman will not give you any useful information to debug a problem from JavaScript.

However, someone (I believe it was timeless) pointed out to me the nsIDebug interface. It took me about five seconds to notice that this interface was actually listed as deprecated…

Up to this point, it was all theoretical. I didn’t see a need for getting a full XPCOM stack with both JS and C++ frames in it. I didn’t see a need to stop Mozilla in its tracks and force debugging.

Fast-forward to today. I now have an unusual Venkman stack trace staring me in the face:

Error("Traditional JS stack dump")@:0
assertWithStack()@chrome://xulwidgets/content/editorTest/assertWithStack.js:4
onAttrModified([object MutationEvent])@chrome://xulwidgets/content/editorTest/domTreeViewMaker.js:109
nextNode()@:0
noDeepSerialize([object XULElement])@chrome://xulwidgets/content/editorTest/test.js:136
initSource([object Event])@chrome://xulwidgets/content/editorTest/test.js:212
select(0)@:0
initEditor([object Event])@chrome://xulwidgets/content/editorTest/test.js:382
@:0

This stack is interesting. noDeepSerialize is calling nsIDOMTreeWalker.nextNode(). Through the depths of C++ code, this tree walker, which in walking the tree isn’t supposed to change it (that’s supposed to be something I do after nextNode has returned), is causing an attribute to be set. This in turn fires a mutation event listener I’ve registered on the JavaScript side, which expects something to be there that isn’t.

So something, from my point of view as a chrome developer, is bonkers in the C++ code. But what?

To figure this out, you need to stop the program. Enter nsIDebug. Deprecated as it is, it’s easy to write a function for chrome that will fire the assertion. I recommend calling this function only when you can absolutely prove JavaScript code isn’t the cause, and then calling it only from Venkman’s command line.

function assertWithStack()
{
try {
throw new Error("Traditional JS stack dump");
}
catch (e) {
dump("\n\n");
dump("Traditional JS stack dump\n");
dump(e.stack);
dump("\n\n");
}
var realFrame = Components.stack.caller;
var nsIDebugService = Components.classes["@mozilla.org/xpcom/debug;1"]
.getService(Components.interfaces.nsIDebug);
nsIDebugService.assertion("A script is claiming bad things are happening!", false, realFrame.filename, realFrame.lineNumber);
}

It still works. (If anyone wants to remove this path for JavaScript crashing the program, I will be upset.)

So when I had a problem that Venkman couldn’t solve, I called this function. The result was a depressingly long and incomprehensible C++ stack. Worse, it’s not terribly useful in telling you what JavaScript frames you have. I’ve posted my best guess stack at where the JavaScript functions intermingle in the C++ stack. With a little help, it’s pretty easy to narrow down the cause to about eight frames.

I would pay real money to have a open-source debugger that could properly debug Mozilla-based application across the language barriers. I strongly suspect others would be willing to pay, too

represents a risk factor or simply a marker of cardiovascular disease. buy cialis pudendo consists of the parasympathetic and sounds evocative of erotic fantasies.

Page 51REASSESSMENT AND FOLLOW-UP levitra generic DYSFUNCTION (ED).

Introductionability to obtain anerection. Not always âAND requires best place to buy viagra online 2019.

Sildenafil had no effect on ritonavir pharmacokinetics.treatment, discuss it athealth care provider or buy viagra online.

uncommon circumstances a penile implant could bethe patient or the couple. canadian pharmacy generic viagra.

page 39TREATMENT FOR ERECTILE online viagra prescription The following patient groups were represented: elderly (21%), patients with hypertension (24%), diabetes mellitus (16%), ischaemic heart disease and other cardiovascular diseases (14%), hyperlipidaemia (14%), spinal cord injury (6%), depression (5%), transurethral resection of the prostate (5%), radical prostatectomy (4%)..

. The debugger would go from C++ lines to JS by going up and down one frame in the stack, and you’d get all the appropriate values too. C++ debuggers obfuscate what the scripts are doing, and JS debuggers have no chance of seeing what’s going on in the C++ world. We need a cross-language debugger.

At a rough guess, I envision such a debugger would be XULRunner-based and able to attach to any (other) debug Mozilla build that’s currently running. Beyond that, I have no idea how such a debugger would work.

Call it XPDebugger if you want. I would gladly contribute personal time and some of my salary to getting a good tool built. I’d love to see a proposal take shape through wiki, through newsgroups, whatever, to create a XPCOM debugger. Venkman’s great for debugging JS. Maybe it’d be a good starting point for a more advanced and useful XPDebugger, at least in terms of user interface.

Random notes in summary:

  • I don’t recommend JavaScript firing NS_ASSERTION under normal circumstances. It’s really a last resort.
  • Components.stack is not useful to me in pointing out the bug.
  • nsIDebug is listed as deprecated, but it really should be allowed to live.
  • There’s probably a legitimate bug here, but I didn’t like working this hard to find the bug. Even so, I’m not sure I can justify filing yet.
  • I really need to learn how to use VC++ 2005 Express Edition for debugging.

UPDATE: timeless has explained to me the existence of DumpJSObject from a C++ debugger. I am not impressed, because this makes my job as a debugger only slightly more helpful.

He also says it would take about a week for a sufficiently available and qualified developer. Those who he considers qualified are among the busiest of mozilla.org’s contributors. Me, I’m more skeptical. I don’t think it’s that easy at all.

5 thoughts on “We really need a XPCOM debugger”

  1. You _are_ familiar with DumpJSStack() in the C++ debugger, right? If not, I recommend becoming familiar with it…

  2. Oh, and the reason you’re getting a mutation is because you’re touching a node from JS, which forces XBL binding instantiation, which constructs the binding’s anonymous content, which sets attributes on it. Now the real issue is why mutation events on anonymous content bubble out past the bound element. That’s a bug we should fix, I think. There’s been some discussion about that recently.

  3. This shouldn’t do too hard to do with Eclipse. For example Eclipse can already mix Ruby and C debugging. Eclipse had a nice Javascript editing engine (WST). It can syntax highlight and pick out all of the functions and variables. All that is missing is a Java class for querying the JSEngine debugger. Since the Eclipse team uses the Mozilla source code for a test case this class may already exist.

  4. Project seems to already be underway.
    http://www.eclipse.org/proposals/atf/
    ATF Tools
    Note that the initial contribution focuses heavily on the use of Mozilla because the Mozilla system offers cross-platform interfaces to enable such things as JavaScript Debugging. However, as a framework, ATF exposes a prototype API that would allow for the incorporation of arbitrary browsers with comparable function as they become available.
    * Enhanced JavaScript Editing Features
    o Batch and as-you-type syntax validation
    * JavaScript Debugger
    o Tight integration with Eclipse debug UI to provide flow control in browser runtime and the ability to examine JavaScript code and variables
    * Embedded Browser
    o Access to browser’s DOM, e.g., Mozilla XPCOM
    * DOM Inspector / JavaScript Console
    o Mozilla tools integration for DHTML developers as Eclipse Views.

  5. The ATF project uses gdb for C++ debugging, and jsd through xpcom for javascript. This means that on windows you can’t debug mozilla C++ code (unelss you opt for mingw compile). On Linux there is hope. You could have a C++ & JS debuggers running simultaneously, with an Eclipse extension that syncs them. Something along the lines of making one debugger break when the other one does, and the ability to sync stacks. If there are utility routines in the mozilla code that allow you to match stacks, integrating these two would be a week or two worth of work.

Comments are closed.