Reading Assignment: All of Programming Ch37.2 Debugger: gdb
Useful Reference:
Debugging is the process of identifying precisely what is wrong with your code and fixing it. The debugger helps you gather information about what is going on in your code.
Getting Started
The first step in using gdb
is to compile the code with debugging symbols–extra information to help a debugging tool understand what the layout of the code and data in memory is–included in the binary. The -g
option to gcc
requests that it include this debugging information, but if you are using gdb
in particular, you should use -ggdb3
, which requests the maximum amount of debug information.
To run gdb
inside emacs
, use the command M-x gdb
. At this point, emacs
should prompt you for how you want to run gdb
and provide a proposed command line.
The first commands are listed below:
- start: Begin the program’s execution.
- run: This command runs the program.
- step: Advance the program one “step”, in much the same way that we would advance the execution arrow when executing code by hand. It can be abbreviated as
s
. - next: Advance the program one line of code. Unlike
step
, if current line of code is a function call,gdb
will execute the entire called function without stopping. It can be abbreviated asn
. - print: It takes an expression as an argument, evaluates that expression and prints the results. If you do
print x = 3
, it will setx
to3
, then print3
. You can put/x
afterprint
to get the result printed in hex format. It can be abbreviated asp
orp/x
to print in hex. Every time you print the value of an expression,gdb
will remember the value in its own internal variables which are named$1, $2...
. You can use these$
variables in other expressions if you want to make use of these values later.gdb
also has a feature to let you print multiple elements from an array–if you put@number
after an lvalue,gdb
will printnumber
values starting at the location you named. For example, ifa
is an array, you can dop a[0]@5
to print the first 5 elements of a; - display: This command takes an expression as an argument, and displays its value every time
gdb
stops and displays prompt. For example,display i
will evaluate and printi
before each (gdb
) prompt. You can abbreviate this command asdisp
.
If you hit enter without entering any command, gdb
will repeat the last command you entered. This feature is most useful when you want to use step
or next
multiple times in a row.
video 37.2.1 illustrates the use of the basic gdb
commands that we just discussed.
Investigating the State of Your Program
One useful features is the ability to inspect the current set of stack frames, and move up and down within them. The backtrace
command lists all of the stack frames.
Sometimes, you might want to inspect variables in other frames further up the stack, You can instruct gdb
to select different frame with up
and down
, which move up and down the stack specifically. One particularly common use of up
is when your program stops in a failed assert
. At this time, gdb
will go deep inside the C library, in the code that handles assert
. However, you will want to get back to your own code, which is a few stack frames up. You can use up
a few times until gdb
returns to a frame corresponding to your code.
You can also get information about various aspects of the program with the info
command, which has various subcommands. For example, info frame
will describe the memory layout of the current frame, info types
will describe the types that are in the current program. There are a variety of info
commands, you can use help info
to see them all.
Controlling Execution
One of the most useful ways to control the execution of our program is to set a breakpoint on a particular line. A breakpoint instructes gdb
to stop execution whenever the program reaches that particular line. you can set a breakpoint with the break line_number
command. In emacs, you can also press C-x space
to set a breakpoint at the point. You can even set a breakpoint in memory address.
Once we have set a breakpoint, we can run
the program, it will execute until the breakpoint is encountered, and gdb
will return control to us at a prompt, allowing for other commands.
We can set conditional breakpoints sometime. For example, if we want to make a breakpoint on line size for the condition i == 25000
, we could tell gdb: (gdb) break 7 if i==25000
. Alternatively, if the breakpoint already existed, for example, as breakpoint 1, we could write cond 1 i==25000
. If we write a cond
command with no expression, then it makes a breakpoint unconditional.
We can also enable
or disable
or delete
breakpoints by its numeric id. You can use the info breakpoints
command to see the status of current breakpoints.
Two other useful commands to control the execution of the program are until
, which causes a loop to execute until it finished, and finish
, which finishes the current function.
Watchpoints
Watchpoint can have gdb
stop when the value of particular expression changes. For example, we can write watch i
, which will cause gdb
to stop whenever the value of i
changes. When gdb
stops in response to a watchpoint, it will print the old value of the expression and the new value.
It can be powerful when you have pointer-related problems.
Signals
Whenever your program receives a signal, gdb
will stop the program and give you control. There are three particularly common signals.
SIGSEGV
, indicating a segmentation fault. Running it ingdb
can help you gather a lot of information about what is happening.SIGABRT
happens when your program callsabort()
or fails anassert
. If your code is failing asserts, then running it ingdb
can be incredibly useful–you will get the control of the program at the point whereassert
causes the program to abort, and see exactly what was going on when the problem happened.SIGINT
happens when the program is interrupted. It is useful when your program is getting stuck in an infinite loop.
Notes
1 | ptype # print type of a variable |