WatchPoint
Save time debugging in GDB with pretty printing
Pretty printing is displaying information in the terminal in such a way that the information can be understood more easily at a glance, saving time when debugging. It is most often done using colour and formatting of data, as opposed to printing out a data structure in its raw form. Example struct Here’s an example program called students.c Now if you were to print the structure normally, it would technically be readable but not very efficiently. There is no formatting retained from the file, and all the data is compressed into the terminal. You could also try and use GDB’s pretty printing to look at the struct. This is nicer to look at as each element of the struct has its own line, so each piece of data can be found more easily. However, this now means the output is significantly longer, taking up more of the terminal, so the gdb pretty printing does come with drawbacks. It can also be enabled for one command, rather than setting it to be on all the time. This next snippet will achieve the same as the previous one: There are other helpful tricks to streamline your print output using GDB. Strings and arrays are usually capped at 200 elements displayed, however this can be customized. As you can see, you can set a specific size of the different strings arrays inside the struct to be output, as well as slice particular parts of an array. You can also set watchpoints on specific slices of the array using GDB. If you continue the program from the breakpoint we’re currently at, then the comments of student[1] are set to a non-literal string using malloc(), allowing the string to be altered one element at a time (which we couldn’t do with string literals, which is how it was initially defined). This allows a watchpoint to be set on a small number of bytes of a large piece of data. GDB doesn’t know how big the malloc string is without being told, but even if you did tell GDB to watch all 128 bytes of the malloc string the x86 watchpoint registers can’t cover that range, as there are only 4 registers of 8 bytes each. Printing also allows you to save a copy of the slice of the array from earlier in the execution. The string at where we are in the program has the X we inserted: However if you print $8, our variable from when earlier when we printed the slice before, it is unchanged: GDB can be customized further for printing, with extra options to work better for specific data types, or to see raw values or static members, etc. You can also use specifiers to customize the format of the value you’re printing. The same can be done with: This customization is useful but not truly specific to our use case. If, for example, we only wanted to see the name of each student in the array, we could use GDB’s Pretty Printing API to manually curate the output. You can learn more about how to use Python pretty printers to get full customization in this tutorial.Intro to Pretty Printing
#include <stdlib.h>
typedef struct
{
const char *first_name;
const char *last_name;
struct
{
int day;
int month;
int year;
} dob;
char *comments;
} student;
student students[] =
{
[0] = {.first_name = "Fred", .last_name = "Smith", .dob = {1,1,1970}},
[1] = {.first_name = "Sarah", .last_name = "G0T0", .dob = {1,1,2002}, .comments = "Lorem ipsum enchanta constrata"}
};
int
main(void)
{
students[1].comments = malloc(128);
students[1].comments[51] = 'X';
return 0;
}
Using GDB’s pretty print
$ gdb students
(gdb) start
Temporary breakpoint 1 at 0x1151: file students.c, line 22
22 int main(void) {
(gdb) print students
$1 = {{first_name = 0x555555556008 “Fred”, last_name = 0x55555555600d “Smith”, dob = {day = 1, month = 1, year = 1970}, comments = 0x0}, {first_name = 0x555555556013 “Sarah”, last_name = 0x555555556019 “G0T0”, dob = {day = 1, month = 1, year = 2002}, comments = 0x5555555560020 “Lorem ipsum enchanta constrata”}}
(gdb) set print pretty on
(gdb) print students
$2 = {{
first_name = 0x555555556008 “Fred”,
last_name = 0x55555555600d “Smith”,
dob = {
day = 1,
month = 1,
year = 1970},
},
comments = 0x0
}, {
first_name = …
…
(gdb) set print pretty off
(gdb) print -pretty on --
…
Printing and watching elements of arrays
(gdb) print -elements 10 -- students
…
comments = 0x5555555560020 “Lorem ipsu”...}}
(gdb) print -elements unlimited --
…
comments = 0x5555555560020 “Lorem ipsum enchanta constrata”}}
(gdb) print students[1].comments[5]@10
$7 = “ ipsum enc”
(gdb) n
24 return 0;
(gdb) print students[1].comments[50]@4
$8 = “\000\000\000”
(gdb) watch students[1].comments [50]@4
Hardware watchpoint 2: students[1].comments [50]@4
(gdb) continue
Continuing.
Hardware watchpoint 2: students[1].comments [50]@4
Old value = “\000\000\000”
New value = “\000X\000”
Main () at students.c:25
25 return 0;
(gdb) print students[1].comments[50]@4
$9 = “\000X\000”
(gdb) p $8
$10 = “\000\000\000”
More basic customization
(gdb) print -
-address -memory-tag-violations -repeats
-array -null-stop -static-members
-array-indexes -object -symbol
-elements -pretty -union
-max-depth -raw-values -vtbl
(gdb) print /x # print previous variable printed in hex
$11 = {0x0, 0x0, 0x0, 0x0}
Custom pretty printers with python
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