http://www.openlogic.com/wazi/bid/351471/more-gdb-tips-and-tricks
The syntax of the command is
To understand how to use the
GDB doesn't know anything about macros by default either, but you can enable macro debugging in the debugger using compile-time flags such as
You can also use the
To alter this behavior, use the
Run the
The GNU Debugger (GDB) is a powerful tool for developers. In an earlier article I talked about how to use breakpoints and watchpoints, and how to auto-display values and call user-defined and system functions. This time, let's see how to use GDB to examine memory and debug macros and signal handlers. To create the examples here, I used GDB 7.6.1 and GCC 4.8.1, and compiled the C code using the
-ggdb
option.Examine memory
Use GDB'sx
command
to examine memory. The command offers several formatting options that
let you control the number of bytes to display and the way you'd like to
display them.The syntax of the command is
x/FMT ADDRESS
, where FMT specifies the output format and ADDRESS is the memory address to be examined. FMT consists of three types of information: the repeat count, the display format, and the unit size. For example: x/3uh 0x786757
is a request to display three halfwords (h) of memory, formatted as
unsigned decimal integers (u), starting at address 0x786757. Available
format letters are o (octal), x (hex), d (decimal), u (unsigned
decimal), t (binary), f (float), a (address), i (instruction), c (char)
and s (string), while available unit size letters are b (byte), h
(halfword), w (word), g (giant, 8 bytes). And it doesn't matter whether
the unit size or format comes first; either order works.To understand how to use the
x
command, consider the following code:#includeSuppose the main() and the func() functions are in different modules, and while debugging a problem you want to examine the value pointed to by the#include void func(char *ptr) { char tmp[] = "someOtherString"; char *new_ptr = ptr+3; if(strncmp(tmp, new_ptr, sizeof(tmp))) { /* * Some processing */ } } int main(void) { func("1. Openlogic"); return 0; }
new_ptr
pointer. Load the program using GDB, put a breakpoint at the strncmp
line, then run the program. Once the program hits the breakpoint, you'll get a prompt:$ gdb test Reading symbols from /home/himanshu/practice/test...done. (gdb) break 8 Breakpoint 1 at 0x80484a9: file test.c, line 8. (gdb) run Starting program: /home/himanshu/practice/test Breakpoint 1, func (ptr=0x8048590 "1. Openlogic") at test.c:8 8 if(strncmp(tmp, new_ptr, sizeof(tmp))) (gdb)Run
x/s new_ptr
at this prompt, and you'll get the following output:(gdb) x/s new_ptr 0x8048593: "Openlogic" (gdb)The
x
command with the s
format letter displays the value stored at the memory address pointed by new_ptr
as a string. To display the value in character format, change the format specifier to c
:(gdb) x/9c new_ptr 0x8048593: 79 'O' 112 'p' 101 'e' 110 'n' 108 'l' 111 'o' 103 'g' 105 'i' 0x804859b: 99 'c'
Debugging macros
One of the biggest reasons developers prefer inline functions over macros is that debuggers tend to be better at dealing with the former. For example, consider the following code:#includeThe cube of 4 is 64, but watch what happens when you run the program:#define CUBE(x) x*x*x int main(void) { int a =3; printf("\n The cube of [%d] is [%d]\n", a+1, CUBE(a+1)); return 0; }
$ ./test The cube of [4] is [10]It can be a nightmare to pinpoint the cause of this kind of problem in a project with a large code base, as most debuggers simply aren't good at debugging macros.
GDB doesn't know anything about macros by default either, but you can enable macro debugging in the debugger using compile-time flags such as
-gdwarf-2
and -g3
; for more info on these options, read the man page
of the GCC compiler. Once the program is compiled with the
aforementioned command-line options, load and run it with GDB in the
standard way. Put in a breakpoint so that you can debug the macro while
the program is running:$ gdb test Reading symbols from /home/himanshu/practice/test...done. (gdb) break 9 Breakpoint 1 at 0x8048459: file test.c, line 9. (gdb) run Starting program: /home/himanshu/practice/test The cube of [4] is [10] Breakpoint 1, main () at test.c:9 9 return 0; (gdb)When the program hits the breakpoint, run the following command to see how the macro is expanded:
(gdb) macro expand CUBE(3+1) expands to: 3+1*3+1*3+1That expansion is equivalent to:
3 + ( 1 * 3 ) + ( 1 * 3 ) + 1
, or 10. Once you know the problem, you can easily correct it by redefining the macro as #define CUBE(x) (x)*(x)*(x)
.You can also use the
info macro
command to find out more about a macro. For example:(gdb) info macro CUBE Defined at /home/himanshu/practice/test.c:3 #define CUBE(x) x*x*xRead this document to learn more on how to debug macros using GDB.
Debugging signal handlers
Debugging signal handlers is not as easy as debugging normal functions with GDB. For example, consider the following program:#includeThe program defines a signal handler for#include #include void sighandler(int signum) { printf("\n Caught SIGNIT - : %d", signum); } int main() { signal(SIGINT, (void*)sighandler); while (1) { printf("\n Waiting for user action..."); sleep(1); } }
SIGINT
, which is usually generated when someone presses Ctrl-C. Load the program using GDB, put a breakpoint at the sighandler()
function, as you would do for any other normal function that you want to debug, then run the program:$ gdb test Reading symbols from /home/himanshu/practice/test...done. (gdb) break sighandler Breakpoint 1 at 0x8048483: file test.c, line 7. (gdb) run Starting program: /home/himanshu/practice/test Waiting for user action... Waiting for user action... Waiting for user action... Waiting for user action...Now generate the
SIGINT
signal by pressing Ctrl-C, and you'll see the problem:Waiting for user action... Waiting for user action... ^C Program received signal SIGINT, Interrupt. 0xb7fdd424 in __kernel_vsyscall () (gdb)Instead of the breakpoint being hit, the signal is intercepted by the debugger.
To alter this behavior, use the
handle
command. It expects a list of signals, along with the actions to be applied on them. In this case, the actions nostop
and pass
are of interest. The former makes sure that GDB doesn't stop the
program when the signal happens, while the latter makes sure that GDB
allows the program to see this signal.Run the
handle
command after setting the breakpoint:$ gdb test Reading symbols from /home/himanshu/practice/test...done. (gdb) break sighandler Breakpoint 1 at 0x8048483: file test.c, line 7. (gdb) handle SIGINT nostop pass SIGINT is used by the debugger. Are you sure you want to change it? (y or n) y Signal Stop Print Pass to program Description SIGINT No Yes Yes Interrupt (gdb)Make sure you answer in the affirmative the question asked by the debugger. Now when you run the program and press Ctrl-C to generate and send SIGINT, the breakpoint is hit:
(gdb) run Starting program: /home/himanshu/practice/test Waiting for user action... Waiting for user action... ^C Program received signal SIGINT, Interrupt. Breakpoint 1, sighandler (signum=2) at test.c:7 7 printf("\n Caught SIGNIT - : %d", signum); (gdb)
No comments:
Post a Comment