michael@0: This directory holds Python code to support debugging SpiderMonkey with michael@0: GDB. It includes pretty-printers for common SpiderMonkey types like jsval, michael@0: jsid, and JSObject, and makes GDB "see through" the SpiderMonkey rooting michael@0: types like js::Rooted and JS::Handle. For example: michael@0: michael@0: (gdb) frame michael@0: #0 js::baseops::SetPropertyHelper (cx=0xbf3460, michael@0: obj=(JSObject * const) 0x7ffff150b060 [object global] delegate, michael@0: receiver=(JSObject * const) 0x7ffff150b060 [object global] delegate, michael@0: id=$jsid("x"), defineHow=4, vp=$jsval(1), strict=0) michael@0: at /home/jimb/moz/archer/js/src/jsobj.cpp:4495 michael@0: 4495 JS_ASSERT((defineHow & ~(DNP_CACHE_RESULT | DNP_UNQUALIFIED)) == 0); michael@0: (gdb) michael@0: michael@0: Things to note here: michael@0: michael@0: - obj, a JS::HandleObject, prints as: michael@0: obj=(JSObject * const) 0x7ffff150b060 [object global] delegate, michael@0: This immediately shows the handle's referent, along with a JavaScript-like summary michael@0: of the object. michael@0: michael@0: - id, a JS::HandleId, prints as: michael@0: id=$jsid("x"), michael@0: We show the handle's referent, and print the identifier as a string. michael@0: michael@0: - vp, a JS::MutableHandleValue, prints as: michael@0: vp=$jsval(1) michael@0: We show the handle's referent, using the jsval's tag to print it in its michael@0: JavaScript form. michael@0: michael@0: You can still see the raw form of a value with 'print/r': michael@0: michael@0: (gdb) p/r obj michael@0: $1 = {> = {}, ptr = 0x7fffffffca60} michael@0: (gdb) michael@0: michael@0: You can also use GDB's 'disable pretty-printer' command to turn off michael@0: individual pretty-printers; try 'info pretty-printer' first. michael@0: michael@0: GDB should pick these extensions up automatically when you debug the shell, by michael@0: auto-loading the 'js-gdb.py' file that js/src/shell/Makefile.in places in the michael@0: same directory as the 'js' executable. You may need to add a command like the michael@0: following to your '$HOME/.gdbinit' file: michael@0: michael@0: # Tell GDB to trust auto-load files found under ~/moz. michael@0: add-auto-load-safe-path ~/moz michael@0: michael@0: If you do need this, GDB will tell you. michael@0: michael@0: In general, pretty-printers for pointer types include a summary of the michael@0: pointer's referent: michael@0: michael@0: (gdb) b math_atan2 michael@0: Breakpoint 1 at 0x542e0a: file /home/jimb/moz/archer/js/src/jsmath.cpp, line 214. michael@0: (gdb) run michael@0: js> Math.atan2('Spleen', 42) michael@0: Breakpoint 1, math_atan2 (cx=0xbf3440, argc=2, vp=0x7ffff172f0a0) michael@0: (gdb) print vp[0] michael@0: $1 = $jsval((JSObject *) 0x7ffff151c0c0 [object Function "atan2"]) michael@0: (gdb) print vp[1] michael@0: $2 = $jsval((JSObject *) 0x7ffff150d0a0 [object Math]) michael@0: (gdb) print vp[2] michael@0: $3 = $jsval("Spleen") michael@0: (gdb) print vp[3] michael@0: $4 = $jsval(42) michael@0: (gdb) michael@0: michael@0: We used to also have pretty-printers for the actual contents of a JSString michael@0: struct, that knew which union branches were live and which were dead. These were michael@0: more fragile than the summary pretty-printers, and harder to test, so I've michael@0: removed them until we can see how to do better. michael@0: michael@0: There are unit tests; see 'Running the unit tests', below. michael@0: michael@0: I'd love for others to pitch in. GDB's Python API is documented in the GDB michael@0: manual. michael@0: michael@0: I've recently rewritten the printers. The new code is simpler, and more michael@0: robust; unit tests are easier to write; and the new test harness can run michael@0: the tests in parallel. If a printer you'd contributed to in the past was michael@0: dropped in the process, I apologize; I felt we should have good test michael@0: coverage for any printer landed in-tree. You may also be interested in michael@0: 'Personal pretty-printers', below. michael@0: michael@0: Directory layout michael@0: ---------------- michael@0: michael@0: - js/src/gdb/mozilla: The actual SpiderMonkey support code. GDB auto-loads this michael@0: when you debug an executable or shared library that contains SpiderMonkey. michael@0: - js/src/gdb/tests: Unit tests for the above. michael@0: - Each '.py' file is a unit test, to be run by js/src/gdb/run-tests.py. michael@0: - Each '.cpp' file contains C++ code fragments for some unit test to use. michael@0: - js/src/gdb/lib-for-tests: Python modules used by the unit tests. michael@0: michael@0: In js/src/gdb: michael@0: michael@0: - run-tests.py: test harness for GDB SpiderMonkey support unit tests. See michael@0: 'Running the unit tests', below. michael@0: - taskpool.py, progressbar.py: Python modules used by run-tests.py. michael@0: - gdb-tests.cpp, gdb-tests.h: Driver program for C++ code fragments. michael@0: - gdb-tests-gdb.py.in: Template for GDB autoload file for gdb-tests. michael@0: michael@0: Personal pretty-printers michael@0: ------------------------ michael@0: michael@0: If you'd like to write your own pretty-printers, you can put them in a michael@0: module named 'my_mozilla_printers' in a directory somewhere on your Python michael@0: module search path. Our autoload code tries to import 'my_mozilla_printers' michael@0: after importing our other SpiderMonkey support modules. For example: michael@0: michael@0: $ echo $PYTHONPATH michael@0: /home/jimb/python michael@0: $ cat ~/python/my_mozilla_printers.py michael@0: import gdb michael@0: from mozilla.prettyprinters import ptr_pretty_printer michael@0: michael@0: # Simple jschar * printer. Doesn't show address; chases null pointers. michael@0: @ptr_pretty_printer('jschar') michael@0: class jscharPtr(object): michael@0: def __init__(self, value, cache): self.value = value michael@0: def display_hint(self): return 'string' michael@0: def to_string(self): michael@0: c = u'' michael@0: for i in xrange(50): michael@0: if self.value[i] == 0: break michael@0: c += unichr(self.value[i]) michael@0: return c michael@0: $ michael@0: ... michael@0: (gdb) whatis sample michael@0: type = jschar [4] michael@0: (gdb) print &sample[0] michael@0: $1 = "Hi!" michael@0: michael@0: Running the unit tests michael@0: ---------------------- michael@0: michael@0: These extensions have unit tests, invoked as follows: michael@0: michael@0: $ python run-tests.py [OPTIONS] LIBDIR [TESTS...] michael@0: michael@0: where LIBDIR is a directory containing a compiled SpiderMonkey library, michael@0: libmozjs.so; TESTS are names of selected tests to run (if omitted, we run michael@0: them all); and OPTIONS are drawn from the list below. michael@0: michael@0: --gdb=EXECUTABLE michael@0: Instead of running whatever 'gdb' we find in our search path, use michael@0: EXECUTABLE to run the tests. michael@0: michael@0: --srcdir=SRCDIR michael@0: Find the sources corresponding to LIBDIR/libmozjs.so in SRCDIR. Without michael@0: this option, we use the parent of the directory containing michael@0: 'run-tests.py'. Note that SRCDIR must be a complete SpiderMonkey source michael@0: directory, as our tests #include internal SpiderMonkey header files (to michael@0: test pretty-printers for internal types, like parse nodes.) michael@0: michael@0: --testdir=TESTDIR michael@0: Search for Python scripts and any accompanying C++ source code in michael@0: TESTDIR. If omitted, we use the 'tests' directory in the directory michael@0: containing 'run-tests.py'. michael@0: michael@0: --builddir=BUILDDIR michael@0: Build the C++ executable that GDB debugs to run the tests in BUILDDIR. michael@0: If omitted, create a 'gdb-tests' subdirectory of LIBDIR. michael@0: michael@0: (It is safe to use relative paths for LIBDIR, SRCDIR, and so on. They are michael@0: always interpreted relative to the directory that was current when michael@0: run-tests.py was started.) michael@0: michael@0: For example, since I build in a subdirectory 'obj~' of the 'js/src' michael@0: directory, I use this command from 'js/src' to run the pretty-printer unit michael@0: tests: michael@0: michael@0: $ python gdb/run-tests.py obj~ michael@0: michael@0: Writing new unit tests michael@0: ---------------------- michael@0: michael@0: Each unit test consists of a Python script, possibly with some accompanying michael@0: C++ code. Running tests works like this: michael@0: michael@0: - The run-tests.py script calls 'make' in 'BUILDDIR/gdb' to build michael@0: 'gdb-tests'. michael@0: michael@0: - Then, for each '.py' test script in js/src/gdb/tests, the harness starts michael@0: GDB on the 'gdb-tests' executable, and then has GDB run michael@0: js/src/gdb/lib-for-tests/prolog.py, passing it the test script's path as michael@0: its first command-line argument. michael@0: michael@0: Thanks To: michael@0: ---------- michael@0: michael@0: - David Anderson michael@0: - Steve Fink michael@0: - Chris Leary michael@0: - Josh Matthews michael@0: - Jason Orendorff michael@0: - Andrew Sutherland