Difference between revisions of "Tip 9: gdb"

From Vlsiwiki
Jump to: navigation, search
 
(4 intermediate revisions by the same user not shown)
Line 1: Line 1:
 
The GNU Debugger (gdb) is extremely useful as a quick way to find problems in codes. I also like it because it is available on MANY platforms. If it is not on your current platform, it is probably easily available as a pre-built package. Here is a quick start guide to the most useful features. More is available in various tutorials and the man page. You can abbreviate almost any gdb command by typing just enough characters to provide a unique match. Tab completion also works.
 
The GNU Debugger (gdb) is extremely useful as a quick way to find problems in codes. I also like it because it is available on MANY platforms. If it is not on your current platform, it is probably easily available as a pre-built package. Here is a quick start guide to the most useful features. More is available in various tutorials and the man page. You can abbreviate almost any gdb command by typing just enough characters to provide a unique match. Tab completion also works.
 +
 +
== Running gdb ==
  
 
gdb can be run in three ways:
 
gdb can be run in three ways:
 +
 
1)  
 
1)  
 
  gdb program
 
  gdb program
 
(or gdb --args program -my -program -argument)
 
(or gdb --args program -my -program -argument)
 
will load your program and give a gdb prompt.
 
will load your program and give a gdb prompt.
 +
 
2)  
 
2)  
 
  gdb program core
 
  gdb program core
 
will run your program using the state saved in a core dump.
 
will run your program using the state saved in a core dump.
 +
 
3)  
 
3)  
 
  gdb program pid
 
  gdb program pid
Line 19: Line 24:
  
 
At any time, you can press Ctrl-C to interrupt and return to the debug prompt. Once there, you can single step into functions ("step" or just "s") or go to the next instruction ("next" or "n"). If you want to keep running, you can type "cont" or "c".
 
At any time, you can press Ctrl-C to interrupt and return to the debug prompt. Once there, you can single step into functions ("step" or just "s") or go to the next instruction ("next" or "n"). If you want to keep running, you can type "cont" or "c".
 +
 +
 +
 +
== Investigating code ==
  
 
Also at the prompt, you may want to see where you are at in the program. To see the current code, you can type "list" or to see the current call stack you can type "backtrace" (or "bt").  
 
Also at the prompt, you may want to see where you are at in the program. To see the current code, you can type "list" or to see the current call stack you can type "backtrace" (or "bt").  
Line 29: Line 38:
 
  #1  0x0000003977231d10 in abort () from /lib64/libc.so.6
 
  #1  0x0000003977231d10 in abort () from /lib64/libc.so.6
 
  #2  0x00000039772296e6 in __assert_fail () from /lib64/libc.so.6
 
  #2  0x00000039772296e6 in __assert_fail () from /lib64/libc.so.6
  #3  0x0000000000453276 in mrg_assert (test=false, msg=
+
  #3  0x0000000000453276 in my_function() from foo.C
        {static npos = 18446744073709551615, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x7fff8732a380 "?? \003"}}) at global.C:770
+
...
...
+
 
  #11 0x000000000047a94e in main (argc=6, argv=0x7fff8732ad68) at main.C:53
 
  #11 0x000000000047a94e in main (argc=6, argv=0x7fff8732ad68) at main.C:53
 
  (gdb)
 
  (gdb)
 +
 +
At this point, go to the failing function by typing:
 +
(gdb) up
 +
#1  0x0000003977231d10 in abort () from /lib64/libc.so.6
 +
(gdb)
 +
#2  0x00000039772296e6 in __assert_fail () from /lib64/libc.so.6
 +
(gdb)
 +
#3  0x0000000000453276 in my_function() from foo.C
 +
(gdb)
 +
 +
Note that pressing "enter" on a blank line will repeat the last command.
 +
 +
== Querying Values ==
 +
 +
At any point, you can print a variable value with by using:
 +
 +
(gdb) print i
 +
$2 = 0
 +
 +
For structures or classes, it will show the nested values:
 +
 +
(gdb) print nodes[i]
 +
$4 = (node_t *&) @0x31d3900: 0x3123270
 +
(gdb) print *nodes[i]
 +
$5 = {static node_id = 18, name = {static npos = 18446744073709551615,
 +
etc.
 +
 +
You can also access data structures:
 +
(gdb) print nodes[i]->name
 +
$6 = {static npos = 18446744073709551615,
 +
  _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x3123258 "1"}}
 +
 +
which shows the char data in the string class is "1". The structures can get pretty nasty if there is a lot in them.
 +
 +
 +
== Breakpoints ==
 +
 +
You can set breakpoints in several ways:
 +
 +
1) By function
 +
 +
(gdb) break main
 +
Breakpoint 3 at 0x47a89d: file main.C, line 39.
 +
 +
2) By file/line number
 +
 +
(gdb) break main.C:39
 +
Note: breakpoint 3 also set at pc 0x47a89d.
 +
Breakpoint 4 at 0x47a89d: file main.C, line 39.
 +
 +
 +
To see your breakpoints, type:
 +
(gdb) info b
 +
Num    Type          Disp Enb Address            What
 +
3      breakpoint    keep y  0x000000000047a89d in main at main.C:39
 +
4      breakpoint    keep y  0x000000000047a89d in main at main.C:39
 +
 +
To remove a breakpoint, type:
 +
(gdb) del b 3
 +
(gdb) info b
 +
Num    Type          Disp Enb Address            What
 +
4      breakpoint    keep y  0x000000000047a89d in main at main.C:39
 +
 +
== Watches ==
 +
 +
You can also "watch" a value and break when it changes.
 +
 +
(gdb) watch i
 +
Hardware watchpoint 5: i
 +
 +
This is often useful for debugging corrupt stacks due to memory mismanagement.
 +
 +
== gdb interfaces ==
 +
 +
There are also several interfaces available to gdb. I use the emacs gdb mode which can be accessed with M-x gdb. There are also several GUIs including ddd (Data Display Debugger) and kdebug.

Latest revision as of 02:23, 5 May 2010

The GNU Debugger (gdb) is extremely useful as a quick way to find problems in codes. I also like it because it is available on MANY platforms. If it is not on your current platform, it is probably easily available as a pre-built package. Here is a quick start guide to the most useful features. More is available in various tutorials and the man page. You can abbreviate almost any gdb command by typing just enough characters to provide a unique match. Tab completion also works.

Running gdb

gdb can be run in three ways:

1)

gdb program

(or gdb --args program -my -program -argument) will load your program and give a gdb prompt.

2)

gdb program core

will run your program using the state saved in a core dump.

3)

gdb program pid

will attach gdb to an already running program. (There are various ways to attach gdb over a network for embedded processors too...)

Once gdb is running, you have a prompt:

(gdb)

at which you can tell it to run:

(gdb) run

At any time, you can press Ctrl-C to interrupt and return to the debug prompt. Once there, you can single step into functions ("step" or just "s") or go to the next instruction ("next" or "n"). If you want to keep running, you can type "cont" or "c".


Investigating code

Also at the prompt, you may want to see where you are at in the program. To see the current code, you can type "list" or to see the current call stack you can type "backtrace" (or "bt").

If your program experiences a signal (segfault, bus error, fork, etc), it will return to the prompt. At this point, you want to investigate why the signal happened. The call stack is useful for this:

Program received signal SIGABRT, Aborted.
0x0000003977230265 in raise () from /lib64/libc.so.6
(gdb) bt
#0  0x0000003977230265 in raise () from /lib64/libc.so.6
#1  0x0000003977231d10 in abort () from /lib64/libc.so.6
#2  0x00000039772296e6 in __assert_fail () from /lib64/libc.so.6
#3  0x0000000000453276 in my_function() from foo.C
...
#11 0x000000000047a94e in main (argc=6, argv=0x7fff8732ad68) at main.C:53
(gdb)

At this point, go to the failing function by typing:

(gdb) up
#1  0x0000003977231d10 in abort () from /lib64/libc.so.6
(gdb) 
#2  0x00000039772296e6 in __assert_fail () from /lib64/libc.so.6
(gdb) 
#3  0x0000000000453276 in my_function() from foo.C
(gdb)

Note that pressing "enter" on a blank line will repeat the last command.

Querying Values

At any point, you can print a variable value with by using:

(gdb) print i
$2 = 0

For structures or classes, it will show the nested values:

(gdb) print nodes[i]
$4 = (node_t *&) @0x31d3900: 0x3123270
(gdb) print *nodes[i]
$5 = {static node_id = 18, name = {static npos = 18446744073709551615, 
etc.

You can also access data structures:

(gdb) print nodes[i]->name
$6 = {static npos = 18446744073709551615, 
  _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x3123258 "1"}}

which shows the char data in the string class is "1". The structures can get pretty nasty if there is a lot in them.


Breakpoints

You can set breakpoints in several ways:

1) By function

(gdb) break main
Breakpoint 3 at 0x47a89d: file main.C, line 39.

2) By file/line number

(gdb) break main.C:39
Note: breakpoint 3 also set at pc 0x47a89d.
Breakpoint 4 at 0x47a89d: file main.C, line 39.


To see your breakpoints, type:

(gdb) info b
Num     Type           Disp Enb Address            What
3       breakpoint     keep y   0x000000000047a89d in main at main.C:39
4       breakpoint     keep y   0x000000000047a89d in main at main.C:39

To remove a breakpoint, type:

(gdb) del b 3
(gdb) info b
Num     Type           Disp Enb Address            What
4       breakpoint     keep y   0x000000000047a89d in main at main.C:39

Watches

You can also "watch" a value and break when it changes.

(gdb) watch i
Hardware watchpoint 5: i

This is often useful for debugging corrupt stacks due to memory mismanagement.

gdb interfaces

There are also several interfaces available to gdb. I use the emacs gdb mode which can be accessed with M-x gdb. There are also several GUIs including ddd (Data Display Debugger) and kdebug.