Next: Type Printing API, Previous: Selecting Pretty-Printers, Up: Python API [Contents][Index]
A pretty-printer consists of two parts: a lookup function to detect if the type is supported, and the printer itself.
Here is an example showing how a std::string
printer might be
written. See Pretty Printing API, for details on the API this class
must provide. Note that this example uses the gdb.ValuePrinter
base class, and is careful to use a leading underscore for its local
state.
class StdStringPrinter(gdb.ValuePrinter): "Print a std::string" def __init__(self, val): self.__val = val def to_string(self): return self.__val['_M_dataplus']['_M_p'] def display_hint(self): return 'string'
And here is an example showing how a lookup function for the printer example above might be written.
def str_lookup_function(val): lookup_tag = val.type.tag if lookup_tag is None: return None regex = re.compile("^std::basic_string<char,.*>$") if regex.match(lookup_tag): return StdStringPrinter(val) return None
The example lookup function extracts the value’s type, and attempts to
match it to a type that it can pretty-print. If it is a type the
printer can pretty-print, it will return a printer object. If not, it
returns None
.
We recommend that you put your core pretty-printers into a Python package. If your pretty-printers are for use with a library, we further recommend embedding a version number into the package name. This practice will enable GDB to load multiple versions of your pretty-printers at the same time, because they will have different names.
You should write auto-loaded code (see Python Auto-loading) such that it
can be evaluated multiple times without changing its meaning. An
ideal auto-load file will consist solely of import
s of your
printer modules, followed by a call to a register pretty-printers with
the current objfile.
Taken as a whole, this approach will scale nicely to multiple inferiors, each potentially using a different library version. Embedding a version number in the Python package name will ensure that GDB is able to load both sets of printers simultaneously. Then, because the search for pretty-printers is done by objfile, and because your auto-loaded code took care to register your library’s printers with a specific objfile, GDB will find the correct printers for the specific version of the library used by each inferior.
To continue the std::string
example (see Pretty Printing API),
this code might appear in gdb.libstdcxx.v6
:
def register_printers(objfile): objfile.pretty_printers.append(str_lookup_function)
And then the corresponding contents of the auto-load file would be:
import gdb.libstdcxx.v6 gdb.libstdcxx.v6.register_printers(gdb.current_objfile())
The previous example illustrates a basic pretty-printer. There are a few things that can be improved on. The printer doesn’t have a name, making it hard to identify in a list of installed printers. The lookup function has a name, but lookup functions can have arbitrary, even identical, names.
Second, the printer only handles one type, whereas a library typically has several types. One could install a lookup function for each desired type in the library, but one could also have a single lookup function recognize several types. The latter is the conventional way this is handled. If a pretty-printer can handle multiple data types, then its subprinters are the printers for the individual data types.
The gdb.printing
module provides a formal way of solving these
problems (see gdb.printing).
Here is another example that handles multiple types.
These are the types we are going to pretty-print:
struct foo { int a, b; }; struct bar { struct foo x, y; };
Here are the printers:
class fooPrinter(gdb.ValuePrinter): """Print a foo object.""" def __init__(self, val): self.__val = val def to_string(self): return ("a=<" + str(self.__val["a"]) + "> b=<" + str(self.__val["b"]) + ">") class barPrinter(gdb.ValuePrinter): """Print a bar object.""" def __init__(self, val): self.__val = val def to_string(self): return ("x=<" + str(self.__val["x"]) + "> y=<" + str(self.__val["y"]) + ">")
This example doesn’t need a lookup function, that is handled by the
gdb.printing
module. Instead a function is provided to build up
the object that handles the lookup.
import gdb.printing def build_pretty_printer(): pp = gdb.printing.RegexpCollectionPrettyPrinter( "my_library") pp.add_printer('foo', '^foo$', fooPrinter) pp.add_printer('bar', '^bar$', barPrinter) return pp
And here is the autoload support:
import gdb.printing import my_library gdb.printing.register_pretty_printer( gdb.current_objfile(), my_library.build_pretty_printer())
Finally, when this printer is loaded into GDB, here is the corresponding output of ‘info pretty-printer’:
(gdb) info pretty-printer my_library.so: my_library foo bar
Next: Type Printing API, Previous: Selecting Pretty-Printers, Up: Python API [Contents][Index]