All commands described so far allow a controlled execution
of a program, but when a debugger is really efficient is when locating an
execution error. These errors generally appear as an abrupt termination (for
example a segmentation fault
). If executed within the debugger,
such fault returns the control to the debugger. At this point, a few
commands are available to inspect which values are currently set in the
program. In other words, the state of a program can be thoroughly
inspected.
One of these commands is the print command (or its abbreviation p). It receives as an argument a generic expression, and it prints the result of evaluating this expression with the values currently used by the program. Therefore, this command may print the value of any variable present in the visible environment of the execution.
Breakpoint 2, main (argc=1, argv=0xfefff604) at gdb_use.c:42 42 function(buf); (gdb) s function (table=0x804a008) at gdb_use.c:16 16 for (y = 0; y < SIZE - 1; y++) (gdb) n 18 table[y].data = y; (gdb) n 19 table[y].next = &table[y + 1]; (gdb) n 16 for (y = 0; y < SIZE - 1; y++) (gdb) p table[0].data $1 = 0 (gdb) p table[0].next $2 = (struct data_unit *) 0x804a010 (gdb)
Other than variable names, the print command accepts any arbitrary C expression, including those with variable names (for example: print x + 2) or memory addresses.
(gdb) p *table[0].next $3 = {data = 0, next = 0x0} (gdb) p table[0].next->data $4 = 0 (gdb)
As it can be seen, the last command prints the content of the expression tabla[0].next->data. The debugger evaluates this expression exactly as it does the compiler, with the values currently present in the execution and it prints its content.
Some special expressions may be useful to know in detail what exactly is the compiler doing. For example, if a C program needs to allocate memory space for a table of 100 integers, the proper line of code would be:
tabla = (int *)malloc(100 * sizeof(int));
The debugger is capable of evaluating the expression sizeof(int) and show its value on the screen. This is one way to know exactly the sizes for different data types used in the execution platform being used. In the example program, the data structure data_unit occupies 8 bytes as shown by the command:
(gdb) p sizeof(struct data_unit)
$5 = 8
(gdb)