-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathGDBAp.tex
More file actions
311 lines (271 loc) · 15.4 KB
/
GDBAp.tex
File metadata and controls
311 lines (271 loc) · 15.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
\chapter{Using the GDB Debugger}
\label{gdbappendix}
By the time you read this appendix, you will likely have written at least
one program with an error in it. In assembly language, even minor errors
usually have results such as the whole program crashing with a segmentation
fault error. In most programming languages, you can simply print out the
values in your variables as you go along, and use that output to find
out where you went wrong. In assembly language, calling output functions
is not so easy. Therefore, to aid in determining the source of errors,
you must use a \emph{source debugger}.
A debugger is a program that helps you find bugs by stepping through the
program one step at a time, letting you examine memory and register
contents along the way. A \emph{source debugger} is
a debugger that allows you to tie the debugging operation directly
to the source code of a program. This means that the debugger
allows you to look at the source code as you typed it in - complete with
symbols, labels, and comments.
The debugger we will be looking at is GDB - the GNU Debugger. This application
is present on almost all GNU/Linux distributions. It can debug programs
in multiple programming languages, including assembly language.
\section{An Example Debugging Session}
The best way to explain how a debugger works is by using it. The program
we will be using the debugger on is the \icode{maximum}
program used in \autoref{firstprogs}. Let's say that you entered
the program perfectly, except that you left out the line:
\begin{simpletyping}
\begin{lstlisting}
incl {\ediBare}
\end{lstlisting}
\end{simpletyping}
When you run the program, it just goes in an infinite loop - it never exits.
To determine the cause, you need to run the program under GDB. However,
to do this, you need to have the assembler include debugging information in the
executable. All you need to do to enable this is to add the
\icode{--gstabs} option to the \icode{as} command.
So, you would assemble it like this:
\begin{simpletyping}
\begin{lstlisting}
as --gstabs maximum.s -o maximum.o
\end{lstlisting}
\end{simpletyping}
Linking would be the same as normal. "stabs" is the debugging format used
by GDB. Now, to run the program under the debugger, you would type in
\icode{gdb ./maximum}. Be sure that the source files are in
the current directory. The output should look similar to this:
\begin{simpletyping}
\begin{lstlisting}
GNU gdb Red Hat Linux (5.2.1-4)
Copyright 2002 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public
License, and you are welcome to change it and/or
distribute copies of it under certain conditions. Type
"show copying" to see the conditions. There is
absolutely no warranty for GDB. Type "show warranty"
for details.
This GDB was configured as "i386-redhat-linux"...
(gdb)
\end{lstlisting}
\end{simpletyping}
Depending on which version of GDB\index{GDB} you are running, this output may vary
slightly. At this point, the program is loaded, but is not running yet.
The debugger is waiting your command. To run your program, just type in
\icode{run\index{run}}. This will not return, because the program
is running in an infinite loop. To stop the program, hit control-c.
The screen will then say this:
\begin{simpletyping}
\begin{lstlisting}
Starting program: /home/johnnyb/maximum
Program received signal SIGINT, Interrupt.
start\_loop () at maximum.s:34
34 movl data\_items(,{\ediBare},4), {\eaxBare}
Current language: auto; currently asm
(gdb)
\end{lstlisting}
\end{simpletyping}
This tells you that the program was interrupted by the SIGINT\index{SIGINT} signal (from your
control-c), and was within the section labelled \icode{start\_loop},
and was executing on line 34 when it stopped. It gives you the code that
it is about to execute. Depending on exactly when you hit control-c, it may
have stopped on a different line or a different instruction than the example.
One of the best ways to find bugs in a program is to follow the flow of
the program to see where it is branching incorrectly. To follow the
flow of this program, keep on entering \icode{stepi\index{stepi}} (for
"step instruction"), which will cause the computer to execute one
instruction at a time. If you do this several times, your output will
look something like this:
\begin{simpletyping}
\begin{lstlisting}
(gdb) stepi
35 cmpl {\ebxBare}, {\eaxBare}
(gdb) stepi
36 jle start\_loop
(gdb) stepi
32 cmpl \$0, {\eaxBare}
(gdb) stepi
33 je loop\_exit
(gdb) stepi
34 movl data\_items(,{\ediBare},4), {\eaxBare}
(gdb) stepi
35 cmpl {\ebxBare}, {\eaxBare}
(gdb) stepi
36 jle start\_loop
(gdb) step
32 cmpl \$0, {\eaxBare}
\end{lstlisting}
\end{simpletyping}
As you can tell, it has looped. In general, this is good, since we wrote it
to loop. However, the problem is that it is
\emph{never stopping}. Therefore, to find out what the problem
is, let's look at the point in our code where we should be exitting the loop\index{loop}:
\begin{simpletyping}
\begin{lstlisting}
cmpl \$0, {\eaxBare}
je loop\_exit
\end{lstlisting}
\end{simpletyping}
Basically, it is checking to see if {\eaxReg} hits zero. If so, it should exit
the loop. There are several things to check here.
First of all,
you may have left this piece out altogether. It is
not uncommon for a programmer to forget to include a way to exit a loop.
However, this is not the case here.
Second, you should make sure that \icode{loop\_exit} actually is
outside the loop. If we put the label in the wrong place, strange things
would happen. However, again, this is not the case.
Neither of those potential problems are the culprit. So, the next
option is that perhaps {\eaxReg} has the wrong value. There are two ways to
check the contents of register in GDB. The first one is the command
\icode{info register\index{info register}}. This will display the contents of
all registers in hexadecimal. However, we are only interested in {\eaxReg}
at this point. To just display {\eaxReg} we can do \icode{print/\$eax}
to print it in hexadecimal, or do \icode{print\index{print}/d \$eax} to print
it in decimal. Notice that in GDB, registers are prefixed with dollar
signs rather than percent signs. Your screen should have this on it:
\begin{simpletyping}
\begin{lstlisting}
(gdb) print/d \$eax
\$1 = 3
(gdb)
\end{lstlisting}
\end{simpletyping}
This means that the result of your first inquiry is 3. Every inquiry
you make will be assigned a number prefixed with a dollar sign. Now,
if you look back into the code, you will find that 3 is the first number
in the list of numbers to search through. If you step through the loop
a few more times, you will find that in every loop iteration {\eaxReg} has the number 3. This is not what should be happening. {\eaxReg} should go to the next
value in the list in every iteration.
Okay, now we know that {\eaxReg} is being loaded with the same value over
and over again. Let's search to see where {\eaxReg} is being loaded
from. The line of code is this:
\begin{simpletyping}
\begin{lstlisting}
movl data\_items(,{\ediBare},4), {\eaxBare}
\end{lstlisting}
\end{simpletyping}
So, step until this line of code is ready to execute. Now, this code depends
on two values - \icode{data\_items} and {\ediReg}.
\icode{data\_items} is a symbol, and therefore constant. It's a
good idea to check your source code to make sure the label is in front of the
right data, but in our case it is. Therefore, we need to look at {\ediReg}. So,
we need to print it out. It will look like this:
\begin{simpletyping}
\begin{lstlisting}
(gdb) print/d \$edi
\$2 = 0
(gdb)
\end{lstlisting}
\end{simpletyping}
This indicates that {\ediReg} is set to zero, which is why it keeps on loading the
first element of the array. This should cause you to ask yourself two
questions - what is the purpose of {\ediReg}, and how should its value be changed?
To answer the first question, we just need to look in the comments.
{\ediReg} is holding the current index of \icode{data\_items}.
Since our search is a sequential search through the list of numbers in
\icode{data\_items}, it would make sense that {\ediReg} should
be incremented with every loop iteration.
Scanning the code, there is no code which alters {\ediReg} at all. Therefore,
we should add a line to increment {\ediReg} at the beginning of every loop
iteration. This happens to be exactly the line we tossed out at the beginning.
Assembling, linking, and running the program again will show that it now
works correctly.
Hopefully this exercise provided some insight into using GDB to help you
find errors in your programs.
\section{Breakpoints and Other GDB Features}
The program we entered in the last section had an infinite loop, and could be
easily stopped using control-c. Other programs may simply abort or finish
with errors. In these cases, control-c doesn't help, because by the time
you press control-c, the program is already finished. To fix this, you
need to set \emph{breakpoints\index{breakpoints}}. A breakpoint is a place
in the source code that you have marked to indicate to the debugger that
it should stop the program when it hits that point.
To set breakpoints\index{breakpoints} you have to set them up before you run the
program. Before issuing the
\icode{run} command, you can set up breakpoints using the
\icode{break\index{break}} command. For example, to break on line 27,
issue the command \icode{break 27}. Then, when the program
crosses line 27, it will stop running, and print out the current line
and instruction. You can then step through the program from that
point and examine registers and memory. To look at the lines and line
numbers of your program, you can simply use the command \icode{l}.
This will print out your program with line numbers a screen at a time.
When dealing with functions, you can also break on the function names.
For example, in the factorial program in \autoref{functionschapter},
we could set a breakpoint for the factorial function by typing in
\icode{break factorial}. This will cause the debugger to
break immediately after the function call and the function setup (it
skips the pushing of {\ebpRegIdx} and the copying of {\espRegIdx}).
When stepping through code, you often don't want to have to step through
every instruction of every function. Well-tested functions are usually
a waste of time to step through except on rare occasion. Therefore, if
you use the \icode{nexti\index{nexti}} command instead of the
\icode{stepi\index{stepi}} command, GDB will wait until completion of the
function before going on. Otherwise, with \icode{stepi}, GDB
would step you through every instruction within every called function.
\begin{sidebar}[Warning]
One problem that GDB has is with handling interrupts\index{interrupts}. Often times
GDB will miss the instruction that immediately follows an interrupt.
The instruction is actually executed, but GDB doesn't step through
it. This should not be a problem - just be aware that it may happen.
\end{sidebar}
\section{GDB Quick-Reference}
\label{gdbquickref}
This quick-reference table is copyright 2002 Robert M. Dondero, Jr., and is used by
permission in this book. Parameters listed in brackets are optional.
\begin{table}[h]
\begin{tabular}{l | l}
Miscellaneous \\
quit\index{quit} & Exit GDB \\
help\index{help} [cmd] & Print description of debugger command \icode{cmd}. Without \icode{cmd}, prints a list of topics. \\
directory\index{directory} [dir1] [dir2] ... & Add directories \icode{dir1}, \icode{dir2}, etc. to the list of directories searched for source files. \\
Running the Program \\
run\index{run} [arg1] [arg2] ... & Run the program with command line arguments \icode{arg1}, \icode{arg2}, etc. \\
set\index{set} args arg1 [arg2] ... & Set the program's command-line arguments to \icode{arg1}, \icode{arg2}, etc. \\
show\index{show} args & Print the program's command-line arguments. \\
Using Breakpoints \\
info\index{info} breakpoints & Print a list of all breakpoints and their numbers (breakpoint numbers are used for other breakpoint commands). \\
break\index{break} \emph{linenum} & Set a breakpoint at line number \emph{linenum}. \\
break *\emph{addr} & Set a breakpoint at memory address \emph{addr}. \\
break \emph{fn} & Set a breakpoint at the beginning of function \emph{fn}. \\
condition\index{condition} \emph{bpnum} \emph{expr} & Break at breakpoint \emph{bpnum} only if expression \emph{expr} is non-zero. \\
command\index{command} [\emph{bpnum}] \emph{cmd1} [\emph{cmd2}] ... & Execute commands \emph{cmd1}, \emph{cmd2}, etc. whenever breakpoint \emph{bpnum} (or the current breakpoint) is hit. \\
continue\index{continue} & Continue executing the program. \\
kill\index{kill} & Stop executing the program. \\
delete\index{delete} [\emph{bpnum1}] [\emph{bpnum2}] ... & Delete breakpoints \emph{bpnum1}, \emph{bpnum2}, etc., or all breakpoints if none specified. \\
clear\index{clear} *\emph{addr} & Clear the breakpoint at memory address \emph{addr}. \\
clear [\emph{fn}] & Clear the breakpoint at function \emph{fn}, or the current breakpoint. \\
clear \emph{linenum} & Clear the breakpoint at line number \emph{linenum}. \\
disable\index{disable} [\emph{bpnum1}] [\emph{bpnum2}] ... & Disable breakpoints \emph{bpnum1}, \emph{bpnum2}, etc., or all breakpoints if none specified. \\
enable\index{enable} [\emph{bpnum1}] [\emph{bpnum2}] ... & Enable breakpoints \emph{bpnum1}, \emph{bpnum2}, etc., or all breakpoints if none specified. \\
Stepping through the Program \\
nexti\index{nexti} & "Step over" the next instruction (doesn't follow function calls). \\
stepi\index{stepi} & "Step into" the next instruction (follows function calls). \\
finish\index{finish} & "Step out" of the current function. \\
Examining Registers and Memory \\
info registers\index{info registers} & Print the contents of all registers. \\
print\index{print}/\emph{f} \$\emph{reg} & Print the contents of register \emph{reg} using format \emph{f}. The format can be x (hexadecimal), u (unsigned decimal), o (octal), a(address), c (character), or f (floating point). \\
x\index{x}/\emph{rsf} \emph{addr} & Print the contents of memory address \emph{addr} using repeat count \emph{r}, size \emph{s}, and format \emph{f}. Repeat count defaults to 1 if not specified. Size can be b (byte), h (halfword), w (word), or g (double word). Size defaults to word if not specified. Format is the same as for print, with the additions of s (string) and i (instruction). \\
info display\index{info display} & Shows a numbered list of expressions set up to display automatically at each break. \\
display\index{display}/\emph{f} \$\emph{reg} & At each break, print the contents of register \emph{reg} using format \emph{f}. \\
display/\emph{s}i addr & At each break, print the contents of memory address \emph{addr} using size \emph{s} (same options as for the x command). \\
display/\emph{s}s addr & At each break, print the string of size \emph{s} that begins in memory address \emph{addr}. \\
undisplay\index{undisplay} \emph{displaynum} & Remove \emph{displaynum} from the display list. \\
Examining the Call Stack \\
where\index{where} & Print the call stack. \\
backtrace\index{backtrace} & Print the call stack. \\
frame\index{frame} & Print the top of the call stack. \\
up\index{up} & Move the context toward the bottom of the call stack. \\
down\index{down} & Move the context toward the top of the call stack. \\
\end{tabular}
\caption{Common GDB Debugging Commands}
\end{table}