GDB pretty-printers for V8

627 views
Skip to first unread message

Andy Wingo

unread,
Apr 18, 2014, 10:54:22 AM4/18/14
to v8-users
Hi all,

I implemented some GDB pretty-printers for V8. They use the debugging
information and the V8 run-time type information to print V8 objects in
a nice way, but without calling V8 code. They are useable on core
files. The pretty-printer is attached, and is also available from:

http://wingolog.org/pub/d8-gdb.scm

It will print all kinds of strings (except externalized strings, as it
doesn't seem possible to call virtual methods from GDB extensions). It
also prints all the oddballs, failures, smis, heap numbers, and
maybeobjects. It can print the values contained by handles, too.

In this frame we can see some examples:

#4 0x0000000000b903ae in v8::internal::MaterializeStackLocalsWithFrameInspector (isolate=0x1c9f030, target=Handle((v8::internal::JSObject *) 0x10edcd0a9479),
function=Handle((v8::internal::JSFunction *) 0x2d8ad3731ac9), frame_inspector=0x7fffffffc240) at ../src/runtime.cc:11485
scope = {isolate_ = 0x1c9f030, prev_next_ = 0x1ce5e98, prev_limit_ = 0x1ce7af0}
value = Handle(the-hole)
name = Handle(0)
i = 0
shared = Handle((v8::internal::SharedFunctionInfo *) 0x2d8ad372e469)
scope_info = Handle((v8::internal::ScopeInfo *) ((v8::internal::FixedArray *) 0x2d8ad373cab9))

Here we see that "value" and "name" are handles to the hole and to Smi
0, respectively. "scope_info" is an interesting case -- the declared
type (the part on the outside) is more refined than the type that is
computed from the map()->instance_type() (the part on the inside). The
pretty printers will print both types if they differ. There's no
problem here, of course; and admittedly it is useful to know when the
actual type is more refined, which does work but I don't have an example
here.

In this frame there's a string:

(gdb) fr 4
#4 0x0000000000b903ae in v8::internal::MaterializeStackLocalsWithFrameInspector (isolate=0x1c9f030, target=Handle((v8::internal::JSObject *) 0x651f90a9479),
function=Handle((v8::internal::JSFunction *) 0xa66ccc31ac9), frame_inspector=0x7fffffffc240) at ../src/runtime.cc:11485
11485 ASSERT(!value->IsTheHole());
(gdb) l
11480 HandleScope scope(isolate);
11481 Handle<Object> value(i < frame_inspector->GetParametersCount()
11482 ? frame_inspector->GetParameter(i)
11483 : isolate->heap()->undefined_value(),
11484 isolate);
11485 ASSERT(!value->IsTheHole());
11486 Handle<String> name(scope_info->ParameterName(i));
11487
11488 RETURN_ON_EXCEPTION(
11489 isolate,
(gdb) p scope_info->ParameterName(i)
$1 = "a"

Here we see that it extracts the string name correctly.

An uninitialized handle prints like this:

details = Handle((v8::internal::JSObject *) 0x0)

To use these pretty printers, just run "source /path/to/d8-gdb.scm". Or
if you put d8-gdb.scm right next to your d8, it will get sourced
automatically. The caveat is that you will need a version of GDB that
allows for Guile extensions, and that's not common right now. However
it is exceptionally easy to get this working. Just install Guile
development libs:

sudo apt-get install guile-2.0-dev

and then fetch and build GDB:

git clone git://sourceware.org/git/binutils-gdb.git
cd binutils-gdb
mkdir +build
cd +build
../configure --prefix=/opt/gdb
make

Now to install it we make the /opt/gdb directory.

sudo mkdir /opt/gdb; sudo chown `whoami` /opt/gdb

Note that since binutils and gdb are lumped into one repo for no good
reason, we should cd into the gdb/ subdir before making install:

cd gdb
make install

Now you have a GDB built from git runnable from /opt/gdb/bin/gdb that
doesn't interfere with anything else on your system, and which can load
up the V8 pretty-printers.

Happy hacking,

Andy
d8-gdb.scm

Ben Noordhuis

unread,
Apr 20, 2014, 5:26:32 AM4/20/14
to v8-u...@googlegroups.com
Nice work, Andy, thanks for sharing. I wrote something similar a
while ago using the gdb python API but it's not nearly as concise (or
polished, or complete) as your script.
Reply all
Reply to author
Forward
0 new messages