WatchPoint
Here is a quick way to pretty-print structures in GDB
Using pretty-printers can save you a lot of time staring at your computer screen and improve the flow of your debugging too! In this tutorial, I start off with writing a basic pretty-printer to display the value of the We love debugging in GDB. We all use structures and classes in the code we write, and GDB strives to display what these are but misses the contextual information; when you use a handful of members, and in particular unions, then interpreting these more complicated structures quickly becomes overwhelming. When GDB prints a value, it first checks whether there is a pretty-printer registered for that value. If there is, then GDB uses the pretty-printer to display the value. Otherwise, the value prints in the usual way. For example, in my previous tutorial, I used the Messy and not easy to read. To start off, we write a basic pretty-printer that returns the Almost every pretty-printer comprises of two main elements: We write our program in Python. Now, run your inferior program and hit Ctrl-C to quit. Our pretty-printer returns the value 2; the value for a Much easier to read. I demonstrate this basic pretty-printer in my video. Do watch it here. Of course, we can and should improve our printer. In my next example, I print the textual name of the When we run our inferior program again and hit Ctrl-C to quit, now the printer returns the value 2, plus the textual name That’s pretty easy. The possibilities are endless. You can extract and print any value of a member in a structure with your pretty-printer program. In my next example, I use the That is it. We now have a pretty-printer for the Investing a very small amount of time in creating your pretty-printers upfront pays off quickly and almost certainly moves up your debugging a couple of gears. You will find that you become more productive and write code you can be truly proud of. Consider making a Job done! In my video, I do explain and run all the code I have written in this tutorial, so I do encourage you to watch it here. GDB Training Want to know more about what you can do with pretty printers? Check out Part 2 Do not miss my next GDB tutorial: sign up for the gdbWatchPoint mailing below.si_signo
field in the siginfo_t
structure, before doing some more advanced stuff.Why we need pretty-printers
print info
command to confirm whether the inferior program received my Ctrl-C. But, because I didn’t have a pretty-printer for the siginfo_t
structure, the command returned all the data of the structure, including expanding the many unions that structure uses.See how easily you can write a basic pretty-printer
si_signo
value from the siginfo_t
structure for an interrupt signal that the inferior program receives.
$ vim prettyprint.py
# Start off with defining the printer as a Python object.
class SiginfoPrinter:
# The constructor takes the value and stores it for later.
def __init__(self, val):
self.val = val
# The to_string method returns the value of the
# si_signo attribute of the directory.
def to_string(self):
signo = self.val['si_signo']
return str(signo)
# Next, define the lookup function that returns the
# printer object when it receives a siginfo_t.
# The function takes the GDB value-type, which, in
# our example is used to look for the siginfo_t.
def my_pp_func(val):
if str(val.type) == 'siginfo_t': return SiginfoPrinter(val)
# Finally, append the pretty-printer as object/ function to
# the list of registered GDB printers.
gdb.pretty_printers.append(my_pp_func)
# Our pretty-printer is now available when we debug
# the inferior program in GDB.
SIGINT
.(gdb) source prettyprint.py
(gdb) print info
$4 = 2
(gdb)
si_signo
member. I use a file called signames, which simply contains a list of the signal numbers with their corresponding textual signal names.class SiginfoPrinter:
def _init_(self, val):
self.val = val
# Watch the variable type that you print.
# signames is an object and takes an integer variable.
def to_string(self):
signo = int (self.val['si_signo'])
signame = signames[signo]
return str(signo) + ' ('+ signame +')'
def my_pp_func(val):
if str(val.type) == 'siginfo_t': return SiginfoPrinter(val)
gdb.pretty_printers.append(my_pp_func)
SIGINT
.(gdb) source signames.py
(gdb) source prettyprint.py
(gdb) print info
$5 = 2 (SIGINT)
(gdb)
Are you ready to build out the pretty-printer some more?
code
field to identify the kill
signal, but also return the sender of that kill
command.class SiginfoPrinter:
def __init__(self, val):
self.val = val
def to_string(self):
signo = int(self.val['si_signo'])
# Determine the signal with the code member,
# for example, 0 = kill, and 128 = Ctrl-C.
code = int(self.val['si_code'])
signame = signames[signo]
# Determine sender of the kill with the union _sifields
sender = self.val['_sifields']['_kill']['si_pid']
# If the signal is a kill (code =0) then print sender.
if code == 0:
return str(signo) + ' ('+ signame +') sender = '+ str(sender)
# For any other signal print the code.
return str(signo) + ' ('+ signame +') code = '+ str(code)
def my_pp_func(val):
if str(val.type) == 'siginfo_t': return SiginfoPrinter(val)
db.pretty_printers.append(my_pp_func)
Writing pretty-printers pays off
siginfo_t
structure. But, of course, you can extrapolate this handy printer to display whatever structure you want.gdbinit
per project, and committing to your project’s source control so that everyone working on that project can benefit.
Master GDB and save time debugging. 1-2 day on-site course for teams of C++ engineers working on complex codebases.
Learn more »Learn more about pretty printers
Sign-up Today
Get tutorials straight to your inbox
Become a GDB Power User. Get Greg’s debugging tips directly in your inbox every 2 weeks.
Want GDB pro tips directly in your inbox?
Share this tutorial