7. Pretty printing, part 1

Consider this simple C++ program:

#include <string>
std::string str = "hello world";
int main ()
{
  return 0;
}

Compile it and start it under gdb.  Look what happens when you print the string:

(gdb) print str
$1 = {static npos = 4294967295,
  _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x804a014 "hello world"}}

Crazy!  And worse, if you’ve done any debugging of a program using libstdc++, you’ll know this is one of the better cases — various clever implementation techniques in the library will send you scrambling to the gcc source tree, just to figure out how to print the contents of some container.  At least with string, you eventually got to see the contents.

Here’s how that looks in python-gdb:

(gdb) print str
$1 = hello world

Aside from the missing quotes (oops on me), you can see this is much nicer.  And, if you really want to see the raw bits, you can use “print /r“.

So, how do we do this?  Python, of course!  More concretely, you can register a pretty-printer class by matching the name of a type; any time gdb tries to print a value whose type matches that regular expression, your printer will be used instead.

Here’s a quick implementation of the std::string printer (the real implementation is more complicated because it handles wide strings, and encodings — but those details would obscure more than they reveal):

class StdStringPrinter:
    def __init__(self, val):
        self.val = val

    def to_string(self):
        return self.val['_M_dataplus']['_M_p'].string()
gdb.pretty_printers['^std::basic_string<char,.*>$'] = StdStringPrinter

The printer itself is easy to follow — an initializer that takes a value as an argument, and stores it for later; and a to_string method that returns the appropriate bit of the object.

This example also shows registration.  We associate a regular expression, matching the full type name, with the constructor.

One thing to note here is that the pretty-printer knows the details of the implementation of the class.  This means that, in the long term, printers must be maintained alongside the applications and libraries they work with.  (Right now, the libstdc++ printers are in archer.  But, that will change.)

Also, you can see how useful this will be with the auto-loading feature.  If your program uses libstdc++ — or uses a library that uses libstdc++ — the helpful pretty-printers will automatically be loaded, and by default you will see the contents of containers, not their implementation details.

See how we registered the printer in gdb.pretty_printers?  It turns out that this is second-best — it is nice for a demo or a quick hack, but in production code we want something more robust.

Why?  In the near future, gdb will be able to debug multiple processes at once.  In that case, you might have different processes using different versions of the same library.  But, since printers are registered by type name, and since different versions of the same library probably use the same type names, you need another way to differentiate printers.

Naturally, we’ve implemented this.  Each gdb.Objfile — the Python wrapper class for gdb’s internal objfile structure (which we briefly discussed in an earlier post) — has its own pretty_printers dictionary.  When the “-gdb.py” file is auto-loaded, gdb makes sure to set the “current objfile”, which you can retrieve with “gdb.get_current_objfile“.  Pulling it all together, your auto-loaded code could look something like:

import gdb.libstdcxx.v6.printers
gdb.libstdcxx.v6.printers.register_libstdcxx_printers(gdb.get_current_objfile())

Where the latter is defined as:

def register_libstdcxx_printers(objfile):
   objfile.pretty_printers['^std::basic_string<char,.*>$'] = StdStringPrinter

When printing a value, gdb first searches the pretty_printers dictionaries associated with the program’s objfiles — and when gdb has multiple inferiors, it will restrict its search to the current one, which is exactly what you want.  A program using libstdc++.so.6 will print using the v6 printers, and (presumably) a program using libstdc++.so.7 will use the v7 printers.

As I mentioned in the previous post, we don’t currently have a good solution for statically-linked executables.  That is, we don’t have an automatic way to pick up the correct printers.  You can always write a custom auto-load file that imports the right library printers.  I think at the very least we’ll publish some guidelines for naming printer packages and registration functions, so that this could be automated by an IDE.

The above is just the simplest form of a pretty-printer.  We also have special support for pretty-printing containers.  We’ll learn about that, and about using pretty-printers with the MI interface, next time.

35 Comments

  • “Crazy!…One thing to note here is that the pretty-printer knows the details of the implementation of the class. This means that, in the long term, printers must be maintained alongside the applications and libraries they work with.”

    Man, the insane lengths to which C++ can drive a man are something to behold.

    To me,it seems fairly obvious that the problems which C++ tries to solve are much simpler and fewer than the problems which it introduces.

    Writing and maintaining custom debugger extensions? Puke.

  • So, in the gnome backtrace stuff I pretty printed all GObjects (with the runtime introspected type name). To do this I have to do some introspection on each type to see if it is a GObject.

    But the pretty printer stuff above just matches a typename, so its not enough for me. Any chance of getting a more generic hook?

  • Alexander — We might be able to work something out. Send some email to the Archer list, with details… in particular I’m curious to know how these variables are declared.

  • This is all very cool. I guess this can be used to mitigate the ghastly template hack needed to get covariance in c++ (see http://www.cs.technion.ac.il/~vitus/papers/TypeSafeCovariance.pdf).

  • Don’t I need to join the list to post? I’m on too many list.

    As an example, take a “GtkWidget *” variable.
    GtkWidget is generally a typedef to struct _GtkWidget, which as the first element has its parent class struct, in this case “GtkObject object”, etc. At the top of the hierarchy you get “GTypeInstance”, which means the type is derived from this and we can use g_type_name_from_instance() to get the runtime introspected type name of the actual object.

    Its really quite similar to having a C++ pretty printer that catches all types that derive from a certain class.

  • You don’t have to join the list. But I don’t mind discussing it here, either.

    It seems like it would not be too hard to write a generic printer that understands GObjects. It could dig into the value and pull out the type name, etc. FWIW — it is a little better in general to do this entirely in Python rather than relying on inferior function calls, because then the support will also work on core files.

    You can also register a printer for pointer types if you want to do something special there; for instance print a pointer as if it were cast to its runtime type.

    FWIW, gdb has this kind of thing built-in for C++, if you “set print object on”.

    So, if you had such a generic printer, then you would simply register all the GObject subclasses in the pretty_printers dictionary, all pointing at the same constructor.

    If you wanted to get really tricky you could iterate over all the symbols, looking for new types matching the profile (“inherits from GTypeInstance”) and register those dynamically. python-gdb doesn’t have the necessary symbol table iterator for this yet, though.

  • I already have the code to pull out the runtime introspected typename, not using inferiour calls.

    However, I don’t want to register all GObject derived names. First of all, there would be hundreds of them, then it wouldn’t automatically pick up new ones form libraries etc.

    However, if you can register a pretty printer for all pointer types that could work. It would just check if the pointer points to a GObject and if not bail.

  • Yeah, right now things aren’t ideal for your situation. You can register a handler for all pointer types, but there’s no way to say “I give up, call the next printer” — there’s not even a decent notion of next printer.

    Also you’d probably want to register printers for the struct types themselves, so that “p foo” followed by “p *foo” does what the user would expect.

    Walking the symbol table — once I implement that — might be your best bet. What do you think of that?

  • Well, right now i don’t pretty print the objects themselves, that would require object specific knowledge.

    All i do is tag gobject pointer with their actual runtime type, which is generally a subclass of the type the pointer is specified to. This is very useful, because in very many calls the arguments are just of type GtkWidget *, and knowing if the input is a button or a dialog helps understanding a lot.

  • I remembered how you can do this.

    Make a printer that matches any pointer type. Rather than pointing this entry at a constructor, though, point it at a function. This function should invoke the constructor the type is a GObject derivative. Otherwise, it should return None — this will let gdb skip to the next printer, if any.

    This function could records the types it checks so that it will do less work in future calls.

    BTW I “git pull”d from your repo but I don’t see any pretty-printers… could you check them in? I’d like to see the code more concretely.

  • tom: I didn’t write them as pretty printers (as i didn’t know it was possible to do it).

    But, in the gnome.gdbinit code, “describe_value() is pretty much it.

  • Trying to make pretty printing work on OS X 10.5 with python2.6 (from MacPorts). Finally came to the following problem:

    bash-3.2# ../build/gdb/gdb test
    GNU gdb (GDB) 6.8.50.20090106-cvs
    Copyright (C) 2009 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law. Type “show copying”
    and “show warranty” for details.
    This GDB was configured as “i386-apple-darwin9.6.0”.
    For bug reporting instructions, please see:

    Setting up the environment for debugging gdb.
    $1 = 111
    Traceback (most recent call last):
    File “…/sandbox/gcc/archer/archer/gdb/python/lib/gdb/libstdcxx/v6/printers.py”, line 474, in to_string
    print self.val[‘_M_dataplus’][‘_M_p’].string(encoding)
    RuntimeError: Error reading string from inferior: Input/output error

    Any idea about how to fix all that would be highly appreciated

  • Find out an interesting thing. The variables s1 and s are displayed properly after setting breakpoint on line 8 and run (in gdb: b 8 / r / p s1 / p s)
    —————-
    #include
    #include

    std::string s = “The long long string”;
    int main ()
    {
    std::string s1 = “The short and not long string”;
    std::cout << “Hello, world!\n”;
    std::cout << s1;
    return 0;
    }

  • I am trying to use archer in Eclipe-Cygwin environment. Currently Eclipse can’t be used to debug STL as it gives row gdb output. I could enable the python scripting in GDB. But the STL containers are not printing data. It worked straight in debian. The following log (Cygwin) explains more:

    (gdb) python print 10
    10
    (gdb) print myList
    $1 = {<_List_base<int, std::allocator >> = {
    _M_impl = {<allocator<std::_List_node >> = {<new_allocator<std::_List_n
    ode >> = {}, }, _M_node = {
    _M_next = 0x681838, _M_prev = 0x6818c8}}}, }
    (gdb) python print myList
    Traceback (most recent call last):
    File “”, line 1, in
    NameError: name ‘myList’ is not defined
    Error while executing Python code.
    (gdb)

    I am clue-less about the error! what could go wrong?

  • Hi all! I’m trying to use python GDB for pretty-printing of C structs using custom printing routines.

    More in detail, I have an AST and want to print it as a simple string.

    I have my printer routine in my C code, I would like that GDB always prints that type of structure pointer with my routine..

    is that possible? I’m not able to getting it working

  • You can try making an inferior function call from a pretty-printer.
    I have heard that people have done it, but it is not very safe, because
    you might hit a breakpoint during the call, and then weird things happen.
    Also, implementing a printer this way prevents people from using them
    when debugging core files.

    Anyway, if you really want to do it, try using gdb.parse_and_eval from
    your printer.
    From what you say it sounds like the problem you are having is that
    your printer is not being found at all, though. I would probably start
    by writing a printer to print anything at all (“Hello”) and then make that
    work, and then expand it to do what it really ought to do.

  • class StdStringPrinter:
    def __init__(self, val):
    self.val = val
    def to_string(self):
    return None
    def display_hint(self):
    return ‘string’
    gdb.current_objfile().pretty_printers.append(StdStringPrinter)

    (gdb) print s
    $1 = TypeError: Could not convert Python object: None

    Is this expected behavior? I can’t do the “== None” comparison shown in the GDB reference example because I get this same error message.

    The reference says None cannot be converted to gdb.Type, however it also says pretty_printers should skip the entry if a pretty-printer object is not returned.

  • The API has changed a bit since this blog series.
    You’ll have to look at the manual to see what to do.
    I am not sure you can return None from to_string;
    but if you want to get that effect then your value-recognizer
    can return None.

  • Thanks for the answer and for all of your hard work on this Tom. The python API is great.

    For reference for anyone else working on this, this is what I have working so far from the latest git checkout, modified from the manual:

    class StdStringPrinter:
    def __init__ (self, val):
    self.val = val
    def to_string (self):
    return self.val[‘_M_p’]
    def display_hint (self):
    return ‘string’

    def str_lookup_function (val):
    lookup_tag = val.type.tag
    regex = re.compile (“^std::basic_string”)
    if lookup_tag == None:
    return None
    if regex.match (lookup_tag):
    return StdStringPrinter (val)
    return None

    gdb.current_objfile().pretty_printers.append(str_lookup_function)

    This will print (better than default but still incomplete):

    (gdb) print s
    $1 = {static npos = 0xffffffffffffffff, _M_dataplus = 0x608238 “hello world”}

  • I found my mistake by looking at the libstdc++ svn:
    http://sourceware.org/gdb/wiki/STLSupport

    You need to get the unqualified type, stripped of typedefs, which is not shown in the manual. This can be done as:
    type = val.type.unqualified().strip_typedefs()

    After this:
    (gdb) print s
    $1 = “hello world” 🙂

  • I amenthusiastic about this as I hope it will replace the ugly way of inspecting objects via the CLI-Interface and gdb-macros I used before. Nevertheless I have the problem of line breaks getting shown as simple “\n” inside the normal inspection environment of CDT.

    Printing containers in GDB/CLI inside CDT works as expected, the linebreaks produced by python are interpreted. This is not the case when using the graphical frontent of CDT.

    Is this a general problem or just mine?

  • Offhand, I don’t know where the bug is. It could be the CDT, or it could be GDB. You’d have to investigate deeper. At the very least, could you file a bug report in GDB’s bugzilla? That would help. Thanks.

  • I investigated further and found something related:

    https://bugs.eclipse.org/bugs/show_bug.cgi?id=255946
    https://bugs.eclipse.org/bugs/show_bug.cgi?id=286785

    However, it is marked as fixed in 6.0.1 and is related to gdb server debugger and application output.

    I am not quite shure anymore if my “problem” is just a missing feature or a bug. Maybe someone with more Eclipse/CDT knowledge can help to clarify that. I will show an example.

    Printing a variable on GDB-Console or via the CLI-Console inside CDT gives this output:

    p initialLEDs

    $1 = std::map with 2 elements = {
    [1] = {
    x = 124,
    y = 99,
    led = 1 ’01’,
    val = 0
    },
    [2] = {
    x = 126,
    y = 102,
    led = 2 ’02’,
    val = 0
    }
    }

    Clicking on the “Variables” tab to this variable instead shows this:
    std::map with 2 elements = {\n [1] = {\n x = 124, \n y = 99, \n led = 1 ’01’, \n val = 0\n },\n [2] = {\n x = 126, \n y = 102, \n led = 2 ’02’, \n val = 0\n }\n}

    Deflating the triangle in front of the variable shows the STL internals as usual. Is this the “intended” or at least current behaviour of CDT? I don’t know as I just started using the python print facilities. If someone disagrees this might be a bug in CDT.

  • I agree with snub’s above observation. I also observe same behavior.

    I am also not sure whether it is a bug or intended behavior of CDT. Please throw some light on this.

  • I don’t know a whole lot about the CDT.

    MI users need some (small) modifications to work properly with pretty-printing. I assume those changes haven’t yet been made to the CDT.

  • […] nos objets complexes et les afficher d’une autre façon qui nous convient mieux. Il ya des articles et des bouts de code sur codesearch pour en savoir plus là […]

  • […] we look at the code, I suggest reading Tromey’s blog post on pretty printing in Gdb if you don’t know the basic idea. To start off, here’s a basic pretty printer that […]

  • […] STL support for gdb.. Python and gdb tutorial. And This blog entry. Also, this is my .gdbrc currently: set print pretty on set print object on set print […]

  • Hey! Nice one, managed to configure gdb to use them. But when using with eclipse (cdt 7), my application hangs when started. If the pretty print is disabled, there is no start-up delay.
    Any hints, why could happen this?

    Gr3go

  • http://sourceware.org/gdb/onlinedocs/gdb/Values-From-Inferior.html#Values-From-Inferior

    has an example that shows if a gdb.Value object is of type TYPE_CODE_FUNC, we can make the function call from within python.

    If a gdb.Value object is of type TYPE_CODE_METHOD, how do we make the call from within python?

    Thanks.

  • […] Tromey???????part 1?part 2???libstdc++-v6 pretty printer […]

  • I have tried your first example:

    class StdStringPrinter:
    def __init__(self, val):
    self.val = val

    def to_string(self):
    # return self.val[‘_M_dataplus’][‘_M_p’].string()
    return “hello world”

    gdb.pretty_printers[‘^std::basic_string$’] = StdStringPrinter

    For `source`ing it from gdb it says about the last line:

    File “~/gdb.py”, line 9, in
    TypeError: list indices must be integers or slices, not str

  • @Hi-Angel found in another blog: the correct way to register printers is to create a python function, and then to append it to pretty_printers.

    So, given the following simple pretty printer for a simple struct MyStruct{const char* a; int b};:


    class MyStructPrinter:
    def __init__(self, val):
    self.val = val

    def to_string(self):
    return f'MyStruct\n\ta = {self.val["a"]}\n\tb = {self.val["b"]}'

    Registering it is the following code:


    def register_printers(val):
    return MyStructPrinter(val) if str(val.type)=='MyStruct'\
    else None

    gdb.pretty_printers.append(register_printers)

  • […] un vistazo a los bonitos tutoriales de impresión de Tom Tromey parte 1 y parte 2. También está la bonita implementación de impresora libstdc ++-v6 para mirar, que es […]

Join the Discussion

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

This site uses Akismet to reduce spam. Learn how your comment data is processed.