As far as I know (and ignoring my previous efforts on chroniquery along these lines), up until now you had your C/C++ Mozilla backtraces via gdb (chocolate) and your JS backtraces via “call DumpJSStack()” or the debugger keyword from within JS (peanut butter), but these two great flavors had never come together to make a lot of money for dentists.
The screenshots (which is actually just one screenshot split in two) show invocation of a custom python gdb command building on my previous exciting pretty gdb commands. The command has filtered out boring JS interpreter / XPConnect code and interleaved exciting interesting JS stack frames.
The implementation is reasonably simple and intended to be able to be implemented using VProbes to support my recent performance work along those lines. We walk stack frames the usual way. Ahead of time, we have marked out the PC ranges of interesting JS interpreter functions (js_Interpret and js_Execute). If the stack frame’s instruction pointer is in one of those functions we grab the JSContext argument. We pop frames until we reach the native frame those functions allocate from their own stack space (whose boundaries we know from the stack walking).
There is one trick we have to do involving dormantFrameChain. While js_Execute has a consistent and straightforward usage of JS_SaveFrameChain, XPConnect and its quickstub friends are more complex. Right now we use a dumb heuristic that just looks if our frame pointer is 0 and there is a dormantFrameChain, and in that case we restore it. (Thankfully the garbage collector needs to know about the shelved frames, otherwise we might have to chase frames down.) I haven’t put much effort into thinking about it, but the heurstic seems a bit reckless. We could likely just concurrently walk the XPConnect context stack to figure out when to restore dormant frame chains. The existing VProbe JS stack (only) code already goes to the horrible effort to get at the thread-local stack, so it wouldn’t be too much more work. Things probably also fall down during garbage collection right now.
Hg repository is here. Under no circumstances try to use this with jblandy’s excellent archer-mozilla JS magic right now. The current code is very distrustful of gdb.Value in a dumb way and does exceedingly dangerous things wherein pointers are bounced to strings and back to integers because direct integer coercion is forbidden. With pretty printers installed this is likely to break. Also, this is all only tested on 1.9.1.
Gaudily syntax-highlighted code listing in gdb joins the gaudy gdb plugin family! (Other members include gaudily colorized backtraces, which you can also see in the bottom of the screenshot.) This, of course, requires gdb with python crammed inside. It might require one crammed a few months ago too; I haven’t updated my archer-gdb repo for at least that long.
The “sl” plugin uses Pygments for the syntax highlighting. Although pygments has a 256 color terminal formatter (woo!), I ended up using my pyflam module because it did not support my need to color the background of the current line without doing something convoluted. (I would have had to create a filter that did its own line-counting and created background-color-styled token variant of every token on the desired line.) Also, it didn’t do line numbers.
The color theme is based off the “fruity” color theme. Much of the gaudy comes from a filter I added that tries to do various Mozilla C++-aware code styling things by recognizing naming patterns of Name tokens. Before you complain about the colors hurting your brain, remember that this is the alternative:
That’s right. It’s like looking at static. You can barely make anything out. And imagine if it was more than just the 10 lines “list” gives you.
Anywho, the repo is here: http://hg.mozilla.org/users/bugmail_asutherland.org/pythongdb-gaudy/
The README tells you what to do. For complete-ness, and because I went to all the effort to write documentation for the command, here is what it does!
Prints a syntax-highlighted source listing. Currently limited to only
work based on the current debug frame and position.
By default, the 11 lines before the current position and 8 lines after are
displayed. A line context is saved between command invocations if the current
source line does not change.
Arguments when used in a new context:
(none) Shows the 11 lines before the current position and 8 lines after.
N Shows the N/2 lines befores the current position and N/2 lines after.
-N Shows the N lines before the current position and 8 lines after.
+N Shows the 11 lines before the current position and N lines after.
M N Shows the M lines before the current position and N lines after.
Arguments in an existing context:
(none) Shows the 20 lines after the last-shown lines.
- Shows the 20 lines preceding the last-shown lines.
N Shows the N lines after the last-shown lines.
-N Shows the N lines preceding the last-shown lines.
M N Shows the M last lines of the last-shown lines and N lines after the
Arguments regardless of context
@A,B Shows lines A through B.