📄 http:^^www.cs.wisc.edu^~cs367-3^gdb.html
字号:
27 init(strs[i]);</samp></code></pre>
<p>Because we've moved up the call stack, the <em>current procedure</em> is now <code>main</code>, and the current position in the code is now line 27 of function <code>main</code>: </p>
<pre><code><samp>(gdb) list
22 strs[i] = new char [11];
23 }
24
25 for (i= 1; i <= 4; i++)
26 {
27 init(strs[i]);
28 }
29
30 for (i= 1; i <= 4; i++)
31 {</samp></code></pre>
<p>We can now look at the values of variables visible in <code>main</code>. In particular, let's look at the values of <code>i</code>, <code>strs[i]</code>, and <code>*strs[i]</code>: </p>
<pre><code><samp>(gdb) p i
$3 = 4
(gdb) p strs[i]
$4 = 0x4 </samp></code></pre>
<address x4 out of bounds><code><samp>(gdb) p *strs[i] Cannot access memory at address 0x4. </samp></code><p>The value of <code>i</code> is <code>4</code>, which is reasonable. The value of <code>strs[4]</code> is a very small address, which we find cannot be accessed in memory. An illegal pointer value
in <code>strs[4]</code> is what caused the crash. </p>
<p>We now know that <code>strs[4]</code> is invalid, but let's also look at the other values of <code>strs</code>. We ask to see the value of the entire array: </p>
</address>
<pre><code><samp>(gdb) p strs
$5 = {0x0, 0x18a60 "xxxxxxxxxx", 0x18a78 "xxxxxxxxxx", 0x18a90 "xxxxxxxxxx"}</samp></code></pre>
<p><code>Gdb</code> shows us each address in the array and, when possible, the value of the string an address points to. </p>
<p>Now we realize that the last element shown for <code>strs</code> is <em>not</em> the value we were shown for <code>strs[4]</code> (i.e., <code>0x4</code>). Moreover, the last element of <code>strs</code> seems to
be properly initialized! This gives us the final clue. In C++, all arrays are 0-based, so the valid subscripts of <code>strs</code> are 0 to 3; 4 is out of range. </p>
<p>Where did that crazy value for <code>strs[4]</code> come from? When we use a subscript that is too big, we actually access variables declared just after the array.
Looking at our program, that is variable <code>i</code>, which currently has a value of <code>4</code>. If we know how to convert hexadecimal to decimal, we know that 0x4 is in fact
4. </p>
<p>Summarizing, what we were able to find out by using <code>gdb</code> was the following: <em>The program incorrectly went beyond the end of </em><code><em>strs</em></code><em> and tried to use the
value of </em><code><em>i</em></code><em> as a string pointer.</em> </p>
<p>We exit <code>gdb</code> using the command <code>quit</code>. When we change the example program to use subscripts in the range 0 to 3, the program will work correctly. </p>
<p>At this point you should copy the program <code>bug1.C</code> (from <!WA8><a href="http://www.cs.wisc.edu/~cs367-3/gdb/bug1.C">here</a>) and compile it with <code>g++</code>. (Remember to use the <code>-g</code> option.) When you run the executable,
you should get a segmentation fault. Enter <code>gdb</code>, re-run the program, and try out the <code>where</code>, <code>up</code>, <code>down</code>, and <code>print</code> commands. </p>
<p>We'll discuss more commands shortly. If you wish, you can use <code>gdb</code>'s <code>help</code> command to find out the categories of commands available: </p>
<pre><code><samp>(gdb) help
List of classes of commands:
running -- Running the program
stack -- Examining the stack
data -- Examining data
breakpoints -- Making program stop at certain points
files -- Specifying and examining files
status -- Status inquiries
support -- Support facilities
user-defined -- User-defined commands
aliases -- Aliases of other commands
obscure -- Obscure features
internals -- Maintenance commands
Type "help" followed by a class name for a list of commands in that class.
Type "help" followed by command name for full documentation.
Command name abbreviations are allowed if unambiguous.</samp></code></pre>
<p>You can also make a help request to find out about a class of commands, for example: </p>
<pre><code><samp>(gdb) help breakpoints
Making program stop at certain points.
List of commands:
awatch -- Set a watchpoint for an expression
rwatch -- Set a read watchpoint for an expression
watch -- Set a watchpoint for an expression
catch -- Set breakpoints to catch exceptions that are raised
break -- Set breakpoint at specified line or function
clear -- Clear breakpoint at specified line or function
delete -- Delete some breakpoints or auto-display expressions
disable -- Disable some breakpoints
enable -- Enable some breakpoints
thbreak -- Set a temporary hardware assisted breakpoint
hbreak -- Set a hardware assisted breakpoint
tbreak -- Set a temporary breakpoint
condition -- Specify breakpoint number N to break only if COND is true
commands -- Set commands to be executed when a breakpoint is hit
ignore -- Set ignore-count of breakpoint number N to COUNT
Type "help" followed by command name for full documentation.
Command name abbreviations are allowed if unambiguous.</samp></code></pre>
<p>Finally, you can make a help request to find out about individual commands, for example: </p>
<pre><code><samp>(gdb) help break
Set breakpoint at specified line or function.
Argument may be line number, function name, or "*" and an address.
If line number is specified, break at start of code for that line.
If function is specified, break at start of code for that function.
If an address is specified, break at that exact address.
With no arg, uses current execution address of selected stack frame.
This is useful for breaking on return to a stack frame.
Multiple breakpoints at one place are permitted, and useful if conditional.
Do "help breakpoints" for info on other commands dealing with breakpoints.</samp></code></pre>
<h2><a name="incorrect_output">Using Gdb on a Program that Produces Incorrect Output </a></h2>
<p>When a program crashes, at least you have a starting point at which to begin the debugging process: You look at the line that was about to be executed when
the crash occurred and try to determine why the program misbehaved. However, if your program terminates cleanly, but produces incorrect or unexpected
output, things can be harder. </p>
<p>One way to debug a program is to insert print statements at selected points in the program, recompile the program, and rerun it. Hopefully, the additional
data will provide clues as to what went wrong. An alternative -- and usually more efficient -- way to debug is to use <code>gdb</code>, which allows you to supervise and
control the execution of your program interactively. </p>
<p>Some of the things that <code>gdb</code> permits you to do are: (1) Set (and clear) <em>breakpoints</em> at specific functions and line numbers. (A breakpoint stops execution at a
particular point, allowing you to issue additional debugger commands.) (2) Look at the value of variables; (3) <em>Single-step</em> your program, running one source
line at a time; and (4) Resume execution until the next breakpoint is encountered (or the end of the program is reached). </p>
<p>To illustrate how we debug a misbehaving program, consider <!WA9><a href="http://www.cs.wisc.edu/~cs367-3/gdb/bug2.C"><code>bug2.C</code></a>: </p>
<pre><code><samp>1 # include <iostream.h>
2
3 /* Count number of adjacent array elements that are equal */
4 int main()
5 {
6 int a[10] = {1,8,5,3,3,9,8,4,4,10};
7 int cnt = 0; /* how many adjacent elems are equal ? */
8 int i;
9
10 for (i = 0; i < 9; i++)
11 {
12 if (a[i] = a[i+1])
13 {
14 cnt++;
15 }
16 }
17
18 cout << "The number of adjacent values that are equal is " << cnt << endl;
19
20 return(0);
}</samp></code></pre>
<p>This program is designed to step through an array, counting pairs of adjacent elements that are equal. When we compile and run we get the following: </p>
<pre><code><samp>> g++ -g -Wall -o bug2 bug2.C
> bug2
The number of adjacent values that are equal is 9</samp></code></pre>
<p>The program terminates cleanly (i.e., no run-time error is reported), but when we look at the values that array <code>a</code> was given in line 3, we see that the answer
computed -- 9 -- is plainly wrong! It should have been 2. We could explicitly add some print statements and recompile the program, but using <code>gdb</code> is easier
and far more flexible. (Every print statement that you add must eventually be removed or disabled.) </p>
<pre><code><samp>> gdb bug2
GDB is free software and you are welcome to 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.
GDB 4.13 (sparc-sun-sunos4.1.3),
Copyright 1994 Free Software Foundation, Inc...
(gdb) run
Starting program: /afs/cs.wisc.edu/p/course/cs367-reps/private/GDB/bug2
The number of adjacent values that are equal is 9
Program exited normally.
(gdb)</samp></code></pre>
<p>We get the same output as before, with normal termination. </p>
<h3>Remark</h3>
<p>As we saw with <code>bug1</code>, the <code>gdb</code> command<code> run</code> lets us start execution of the program from within <code>gdb</code>. If the program has arguments, these are included in the
<code>run</code> command. For example, a program usually called as</p>
<p><code><samp>testprog -f file1</samp></code></p>
<p>would be run from within <code>gdb</code> by issuing the command </p>
<pre><code><samp>run -f file1</samp></code></pre>
<p>Standard input is entered from the keyboard; standard output appears on the screen, possibly intermixed with the output from <code>gdb</code> commands. </p>
<h3>End Remark</h3>
<p>To get <code>gdb</code> to stop while running a program (so that we can look at values, for example), we use the <code>break</code> command (which can be abbreviated <code>b</code>). We
give either the name of a function or a line number. Each time that function or line number is reached, <code>gdb</code> stops and waits for additional commands (such as a
command to print the value of some variable, or a command to resume execution). </p>
<p>To have execution resume until the next breakpoint is encountered (or the end of the program is reached), we enter <code>continue</code>. To execute just one more line
of the program (known as "single-stepping") we enter <code>next</code> (abbreviated <code>n</code>) or <code>step</code> (abbreviated <code>s</code>). The difference between <code>next</code> and <code>step</code> is that <code>next</code>
takes you to the next source line <em>in the current function</em>, whereas <code>step</code> takes you to the next source line (which may be in another function if the current line
calls a function). </p>
<p>Hitting the <code><b>return</b></code> key reexecutes the most recent command. Thus entering one <code>s</code> or <code>n</code> command, followed by a number of <code>return</code>s, allows you to step
through a program, one line at a time. For long programs, this would be very tedious, but you don't need to start stepping at the very beginning. </p>
<p>For this simple program, we will set a breakpoint at function <code>main</code> and then step through the first few lines of the program. This will give us a sense of how
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -