Support for debugging SpiderMonkey with GDB now landed

January 2, 2013 § 1 Comment

The main source tree for Firefox, Mozilla Central, now includes some code that should make debugging SpiderMonkey with GDB on Linux much more pleasant and productive.

GDB understands C++ types and values, but naturally it has no idea what the debuggee intends them to represent. As a result, GDB’s attempts to display those values can sometimes be worse than printing nothing at all. For example, here’s how a stock GDB displays a stack frame for a call to js::baseops::SetPropertyHelper:

(gdb) frame
#0 js::baseops::SetPropertyHelper (cx=0xc648b0, obj={<js::HandleBase> = {}, ptr = 0x7fffffffc960}, receiver={<js::HandleBase> = {}, ptr = 0x7fffffffc960}, id={<js::HandleBase> = {}, ptr = 0x7fffffffc1e0}, defineHow=4, vp={<js::MutableHandleBase> = {<js::MutableValueOperations<JS::MutableHandle >> = {<js::ValueOperations<JS::MutableHandle >> = {}, }, }, ptr = 0x7fffffffc1f0}, strict=0) at /home/jimb/moz/dbg/js/src/jsobj.cpp:3593

There exist people who can pick through that, but for me it’s just a pile of hexadecimal noise. And yet, if you persevere, what those arguments represent is quite simple: in this case, obj and receiver are both the JavaScript global object; id is the identifier "x"; and vp refers to the JavaScript string value "foo". This SetPropertyHelper call is simply storing "foo" as the value of the global variable x. But it sure is hard to tell—and that’s an annoyance for SpiderMonkey developers.

As of early December, Mozilla Central includes Python scripts for GDB that define custom printers for SpiderMonkey types, so that when GDB comes across a SpiderMonkey type like MutableValueHandle, it can print it in a meaningful way. With these changes, GDB displays the stack frame shown above like this:

(gdb) frame
#0 js::baseops::SetPropertyHelper (cx=0xc648b0, obj=(JSObject * const) 0x7ffff151f060 [object global] delegate, receiver=(JSObject * const) 0x7ffff151f060 [object global] delegate, id=$jsid("x"), defineHow=4, vp=$jsval("foo"), strict=0) at /home/jimb/moz/dbg/js/src/jsobj.cpp:3593

Here it’s much easier to see what’s going on. Objects print with their class, like “global” or “Object”; strings print as strings; jsval values print as appropriate for their tags; and so on. (The line breaks could still be improved, but that’s GDB for you.)

Naturally, the pretty-printers work with any command in GDB that displays values: print, backtrace, display, and so on. Each type requires custom Python code to decode it; at present we have pretty-printers for JSObject, JSString, jsval, the various Rooted and Handle types, and things derived from those. The list will grow.

GDB picks up the SpiderMonkey support scripts automatically when you’re debugging the JavaScript shell, as directed by the js-gdb.py file that the build system places in the same directory as the js executable. We haven’t yet made the support scripts load automatically when debugging Firefox, as that’s a much larger audience of developers, and we’d like a chance to shake out bugs before foisting it on everyone.

Some versions of GDB are patched to trust only auto-load files found in directories you’ve whitelisted; if this is the case for you, GDB will complain, and you’ll need to add a command like the following to your ~/.gdbinit file:

# Tell GDB to trust auto-load files found under ~/moz.
add-auto-load-safe-path ~/moz

If you need to see a value in its plain C++ form, with no pretty-printing applied, you can add the /r format modifier to the print command:

(gdb) print vp
$1 = $jsval("foo")
(gdb) print/r vp
$2 = {
  <js::MutableHandleBase> = {
    <js::MutableValueOperations<JS::MutableHandle >> = {
      <js::ValueOperations<JS::MutableHandle >> = {}, }, },
  members of JS::MutableHandle:
  ptr = 0x7fffffffc1f0
}

If you run into troubles with a pretty-printer, please file a bug in Bugzilla, under the “Core” product, for the “JavaScript Engine” component. (The pretty-printers have their own unit and regression tests; we do want them to be reliable.) In the mean time, you can disable the pretty-printers with the disable pretty-printer command:

(gdb) disable pretty-printer .* SpiderMonkey
12 printers disabled
128 of 140 printers enabled

For more details, see the GDB support directory’s README file.

Emacs hacks for Mozilla hackers

January 5, 2011 § 3 Comments

If you use Emacs to work on Mozilla code, you might find something you like in my mozilla-elisp repository. It currently includes:

  • mozilla-c-style.el, a package which defines a C/C++ indentation style named “Mozilla”, which you can select with C-c . (c-set-style). This properly handles case labels, long return expressions, and things like that. The comments at the top explain how to turn it on by default in Mozilla code. It may have some SpiderMonkey-isms in it; if you send me bug reports, I will split it into “Mozilla” and “SpiderMonkey” styles.
  • mercurial-queues.el, a major mode for editing Mercurial Queues series files, pushing, popping, and refreshing patches, and so on. In particular, the push and pop commands take care of refreshing any buffers visiting modified files. (This is currently slow if you have many buffers open, due to a shortcoming in vc‘s Mercurial support that makes refreshing a buffer take a significant fraction of a second. I have an unpolished workaround; if anyone besides me begins to use this and complains to me, then I’ll certainly finish it up and get it into the code.)
  • diff-find-mq-file.el, a quick hack to help ‘diff-goto-source‘ and ‘diff-apply-hunk‘, commands that jump from a hunk in a patch file to the place where that hunk would apply, find the file to patch when they’re invoked on a patch in a .hg/patches directory.

Happy Hacking!

SpiderMonkey’s conservative collector still needs some rooting

December 20, 2010 § 2 Comments

We’ve just landed the definition in <jsapi.h> of a new template type, js::Anchor, in TraceMonkey. Developers writing code against the JSAPI will need to understand it to avoid garbage collection hazards. The need for js::Anchor became clear in bug 614138, but I’ll let the comments from <jsapi.h> tell the story:

Protecting non-jsval, non-JSObject *, non-JSString * values from collection

Most of the time, the garbage collector’s conservative stack scanner works behind the scenes, finding all live values and protecting them from being collected. However, when JSAPI client code obtains a pointer to data the scanner does not know about, owned by an object the scanner does know about, Care Must Be Taken.

The scanner recognizes only a select set of types: pointers to JSObjects and similar things (JSFunctions, and so on), pointers to JSStrings, and jsvals. So while the scanner finds all live JSString pointers, it does not notice jschar pointers.

So suppose we have:

  void f(JSString *str) {
    const jschar *ch = JS_GetStringCharsZ(str);
    ... do stuff with ch, but no uses of str ...
  }

After the call to JS_GetStringCharsZ, there are no further uses of str, which means that the compiler is within its rights to not store it anywhere. But because the stack scanner will not notice ch, there is no longer any live value in this frame that would keep the string alive. If str is the last reference to that JSString, and the collector runs while we are using ch, the string’s array of jschars may be freed out from under us.

Note that there is only an issue when 1) we extract a thing X the scanner doesn’t recognize from 2) a thing Y the scanner does recognize, and 3) if Y gets garbage-collected, then X gets freed. If we have code like this:

  void g(JSObject *obj) {
    jsval x;
    JS_GetProperty(obj, "x", &x);
    ... do stuff with x ...
  }

there’s no problem, because the value we’ve extracted, x, is a jsval, a type that the conservative scanner recognizes.

Conservative GC frees us from the obligation to explicitly root the types it knows about, but when we work with derived values like ch, we must root their owners, as the derived value alone won’t keep them alive.

A js::Anchor is a kind of GC root that allows us to keep the owners of derived values like ch alive throughout the Anchor’s lifetime. We could fix the above code as follows:

  void f(JSString *str) {
    js::Anchor<JSString *> a_str(str);
    const jschar *ch = JS_GetStringCharsZ(str);
    ... do stuff with ch, but no uses of str ...
  }

This simply ensures that str will be live until a_str goes out of scope. As long as we don’t retain a pointer to the string’s characters for longer than that, we have avoided all garbage collection hazards.

Update: Of course, this belongs in the JSAPI docs, not a blog post or a header file. I’ll get it up there shortly; third try’s a charm.

Debugging SpiderMonkey with Archer

December 20, 2010 § 4 Comments

If you’re hacking on SpiderMonkey, the JavaScript engine used in Mozilla Firefox, the debugger can be less than helpful when viewing SpiderMonkey’s data structures:

(gdb) print str
$1 = (JSString *) 0x7ffff680a440
(gdb) print *str
$2 = {mLengthAndFlags = 148, {mChars = 0x7ffff680a450, mLeft = 0x7ffff680a450}, {mInlineStorage = {118, 97, 114, 32}, e = {{mCapacity = 9007688887369846, mParent = 0x20007200610076, mBufferWithInfo = 0x20007200610076}, {mBase = 0x20003d00200078, mRight = 0x20003d00200078}}, externalStringType = 6357110}}
(gdb) print/c str->mChars[0]@(str->mLengthAndFlags / 16)
$4 = {118 'v', 97 'a', 114 'r', 32 ' ', 120 'x', 32 ' ', 61 '=', 32 ' ', 53 '5'}

If you know enough magic, you can make it work, but there’s a lot of clutter, and it’s a distraction from the task at hand.

The Archer Project is a development branch of GDB that you can customize in Python. In particular, you can have Archer automatically call your own Python functions to format particular types of values. I’ve written a set of pretty-printers for SpiderMonkey’s datatypes, so for me the above interaction would go:

(gdb) print str
$1 = 0x7ffff680a440 "var x=5" ATOMIZED
(gdb) print *str
$2 = {mLengthAndFlags = (7 << 4)|FLAT|ATOMIZED, mChars = 0x7ffff680a450, externalStringType = 6357110}

When printing a pointer to a JSString, Archer shows the string’s contents, and any flags (like ATOMIZED). When printing a JSString struct value, Archer omits dead union branches — in this case, most of the members.

Archer applies the pretty-printers whenever it needs to print a value, so, for example, stack traces are legible, too:

(gdb) where 1
#0  js_SetPropertyHelper (cx=0xa8e550, obj=0x7ffff6803048 [Object global], id=$jsid("x"), defineHow=1, vp=0x7fffffffc7f0, strict=0) at ../jsobj.cpp:5367

Here the JSObject pointer and the jsid have been printed in a more helpful way.

At present, I have pretty-printers for:

  • jsval and js::Value
  • JSString, JSString *, JSAtom *, and jsid
  • JSObject *, JSFunction *, and JSFunction
  • js::PropertyCacheEntry and js::PCVal
  • JSParseNode *, JSDefinition *, JSParseNode, JSDefinition, and JSFunctionBox *
  • js::Shape

You can check out a copy of the current sources using Mercurial:

$ hg clone http://hg.mozilla.org/users/jblandy_mozilla.com/archer-mozilla
destination directory: archer-mozilla
requesting all changes
...
22 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ cd archer-mozilla
$ more README

This creates a directory called archer-mozilla; the README file there explains how to make Archer use the pretty-printers.

This is very much a work in progress; there are certainly bugs, and while there are regression tests, they don’t cover all the pretty-printers the package defines. Please let me know if you find a bug, or have suggestions for improvements.

I use Archer on Linux; I don’t know how well it works on Macintosh OS X or Windows. I hear that these pretty-printers can be used with modern stock GDB releases.

Where Am I?

You are currently browsing the Mozilla category at It Could Be So Much Better.

Follow

Get every new post delivered to your Inbox.