In this chapter
在本章中,
Installing gdb安装GDB
page 55
gdb CommandsGDB命令
page 56
Compiling a Program That Is to Be Debugged with gdb 程序编译成可用GDB调试的形式 page 59
A Typical gdb Session一个典型GDB会话
page 60
Debugging Using a Core File使用核心文件调试
page 63
Running the Program and Getting the Core Dump运行程序并得到内核转储
page 64
Graphical gdb Interfaces图形gdb接口
page 65
Data Display Debugger DDD(数据显示调试器)
page 66
InsightInsight(洞察)
page 70
Debugging Symbols Increase the Executable's Size调试符号增大了可执行文件
page 77
Debugging Techniques调试技术
page 78
Summary总结
page 80
Web Resources for GNU DebuggerGNU调试器的网络资源
page 80
The very basic debug method is adding printf() statements to a program. This method can work in several types of problems that need to be debugged. One issue with debugging with printf() is that it is very time-consuming. A debugger like gdb lets you view the program in a more expedited way.
加printf()语句到程序中是非常基本的调试方法。该方法可以工作于几种需要被调试的问题。Printf调试法的一个问题就是非常耗费时间,诸如gdb的调试器能让你更快的观察程序。
The purpose of the GNU debugger, gdb, is to examine what is going on inside a program that needs to be debugged. gdb provides a text-based user interface, and it can be used to debug programs written in several languages (C, C++, and others). Graphical user interfaces (GUIs) can be used with gdb. Two of the GUIs for gdb are Data Display Debugger (ddd) and Insight. Both are covered in this chapter.
GNU
调试器 gdb的目的就是检查需要调试的程序内部什么正在执行,gdb提供了一个基于文本的用户接口,可以用来调试好几种程序语言(c,c++还有其他)。Gdb也可以使用图形用户界面(GUI).ddd 和insight是图形界面gdb当中的两个,本章会讲述着两个工具。
The gdb source-code debugger is available for Linux and other UNIXs. gdb can be used to perform the following operations, which are helpful in the process of debugging a compiled program:
Gdb
源码调试器在linux和其他的unix上都是可用的,在调试被编译的程序时,gdb有如下操作能帮助调试:
- Setting break points: Program execution can be temporarily suspended at specified points (called break points). At a break point the program is stopped, and specific values can be displayed to determine their correctness. Upon program suspension, the programmer can interact with gdb and use its full set of commands to investigate the performance of the executing program before resuming program execution. A break point can be conditional. For example, if you want to see how a loop runs when hi-lo is 1, you tell gdb to break when lo==(hi-1). The command to do this is as follows:
(gdb) condition 1 lo==(hi-1)
设置断点:程序执行可以在特定点(被称为断点)处被临时挂起。程序停于断点处,可以显示一些特定的具体的值来判断它们的正确性。在程序挂起时,程序员可以跟gdb交互,使用全部的gdb命令来调查执行程序的性能。断点可以是有条件的。例如你想要看hi-lo等于1的时候循环如何运行,告诉gdb在lo==(hi-1)处中断就可以了。命令如下:
(gdb) condition 1 lo==(hi-1)
- Hardware watch points: Some processors can use the hardware to watch a small set of memory locations to see when they change. Since the checking is done by hardware, the program runs at full speed until the memory location is modified. At this point the debugger stops and tells you which instruction modified which memory address and what the old and new values are for that address. As an example, assume you want to know when the low-memory global TheMem is changing. Here is how it might look under gdb:
硬件监视点:一些处理器可以采用硬件来监视少许内存位置以断定这些内存何时改变。由于是硬件监视,所以在内存位置被修改前程序可以全速运行。当到达断点的时候,调试器停下来并且告诉用户那条指令修改了内存的何处,该处的旧值和新值分别是多少。举例,如果你想要知道低地址的全局变量TheMem的改变,可以按照如下步骤:
(gdb) watch TheMem
Hardware watchpoint 1: TheMem
(gdb) c
Continuing.
Hardware watchpoint 1: TheMem
Old value = 0
New value = 768
C_FirstMenu (mid=3) at menu1.c:577
At the first (gdb) prompt, you tell gdb that you want to be alerted whenever the expression TheMem changes. gdb watches that expression with a hardware watch point, so it assigns watch point 1 to the task.
在第一个提示符处,你告诉gdb当TheMem表达式被改变的时候你想要被提醒,gdb使用硬件断点监视该表达式,给该监视任务断点1的名称。
- Displaying program values and attributes: gdb can be instructed to display the current contents of variables as the program executes.
显示程序值和属性:gdb可以在程序执行的时候显示变量的当前内容
- Step through a program line by line: Each line of the executable program can be executed one line at a time.
步进调试:可执行程序的每一行都可以一次一行的执行
- Stack frame: Each time a program performs a function call, the information about where in your program the call was made from is saved in a block of data called a stack frame, or frame for short. Each frame is the data associated with one call to one function. The frame contains the arguments given to the function, the function's local variables, and the address where the function is executing. All the stack frames are allocated in a region of memory called the call stack. The basic commands to operate frames are frame, info frame, and backtrace.
栈帧:每次程序执行一次函数调用的时候,程序何处调用的相关信息被保存在一块称为栈帧的数据中,栈帧也常简称为帧。每帧都是与一次函数调用的相关联的数据。帧包含了函数调用的参数,函数的局部变量以及函数执行的地址。所有栈帧被分配在称为调用栈的内存区域。操作帧的基本命令是 frame,info frame和backtrace.
You can tell GDB to switch from frame 0 to frame 1 using the frame command with the frame number as the argument. This gives you access to the variables in frame 1. As you can guess, after switching frames, you can't access variables stored in frame 0.
使用参数为帧号的frame命令你可以让GDB从帧0切换到帧1。此时你可以存取帧1的变量,但如你能想到的,帧0中存储的变量就不能被存取了。
The gdb package comes with information on all the features. You can view this information by typing info gdb after the gdb package has been installed. The debugger also comes with a quick reference card in the file gdb-x.x/doc/refcard.ps.
Gdb包包括了所有特性的信息,在gdb包被安装后,你可以通过命令info gdb来阅读这些信息。调试器也附带了一个快速参考卡的文件,位于gdb-x.x/doc/refcard.ps
Installing gdb
gdb is generally distributed as source code, archived, and compressed into a single file using the tar and gzip utilities. Once the source code is in hand, the user typically decompresses, configures, compiles, and installs the programs. Most, if not all, Linux distributions ship a version of the gdb package, but the steps to install and build it are listed here.
Gdb通常以源代码的形式发行,使用tar和gzip工具被归档和压缩成单个文件。一旦获得了源代码,用户一般会解压缩,配置,编译和安装程序。绝大多数(如果不是所有)情况下,linux发布会带有一个gdb包,安装和构建的步骤如下:
tar zxvf gdb-6.1.tar.gz && cd gdb-6.1 && ./configure && make && make install
Figure 3.1 shows all the steps to decompress and then build and install gdb.
Figure 3.1. Building gdb.
gdb Commands
gdb can start to debug an application by using the command gdb executable_file name. gdb loads the executable's symbols. Then the display prompt is available to start using the debugger.
Gdb可以通过使用命令 gdb 可执行文件名 的方式开始调试应用程序。Gdb加载可执行程序的符号,然后显示提示符表明可以开始使用调试器了。
There are three ways to view a process with this debugger:
Use the attach command to view a running process. attach stops the process.
Use the run command to start the program.
Look at an existing core file to determine the state the process was in when it crashed or was killed. To view a core file, start gdb with the command gdb executable_file corefile.
调试器有三种方法调试进程:
使用attach来查看正在运行的进程。Attach停止进程
使用run来运行进程
当进程崩溃或者被杀后,通过查看存在的内核文件决定进程的状态。为了察看内核文件,用gdb 执行文件内核文件 命令来开始gdb
Before the program is run or before attaching it to a running program, list the source code where the bug is believed to be, and then set break points to start debugging the program. The "Debugging with gdb" link listed in the " Web Resources for GNU Debugger" section at the end of this chapter contains a detailed tutorial on using gdb. gdb also includes extensive online help, which you can view using the help command.
在程序被运行或者被连接上之前,列出源代码并且在认为可能有错误的地方下断点。在GNU调试器的网络资源(列于本章末尾)中“使用gdb调试”这一段包含了一个使用gdb的详细的例子。Gdb也包含了扩展的在线帮助,可以通过help命令来观看。
Some Useful gdb Commands
Many gdb commands have abbreviations, as shown in the following list:
一些有用的gdb命令
很多gdb命令有简写形式,列于下表:
Command
|
Abbreviation
|
Description
|
attach
|
at
|
Attaches to a running process.附着到运行的进程
|
backtrace
|
bt
|
Prints a stack trace.打印栈轨迹
|
break
|
b
|
Sets a break point.设置断点
|
clear
|
|
Clears a break point.清除断点
|
continue
|
c
|
Allows the program to continue executing.程序继续执行
|
delete
|
|
Clears a break point by number.通过数字清除断点
|
detach
|
|
Detaches from the currently attached process.从当前附着的进程分离
|
display
|
|
Displays the value of an expression every time execution stops.每次执行停止的时候打印表达式的值
|
finish
|
|
Runs to the end of the function and displays return values of that function.运行到函数结尾并显示函数返回值
|
help
|
|
Displays help for gdb commands.显示命令帮助
|
jump
|
|
Jumps to an address and continues the execution there.跳转并继续执行
|
listl
|
|
Lists the next 10 lines.列出下10行
|
next
|
n
|
Steps to the next machine language instruction.步进到下一个机器语言指令
|
print
|
p
|
Prints the value of an expression.打印表达式的值
|
run
|
r
|
Runs the current program from the start.从开始运行当前程序
|
set
|
|
Changes the value of a variable.改变变量值
|
step
|
s
|
Steps the program instruction by instruction.步进运行机器执行
|
where
|
w
|
Prints a stack trace.打印栈轨迹
|
Listing 3.1 has an error built into it to demonstrate some of gdb's features. Let's run the gdb-sample1 program without the debugger and see the error message. Figure 3.2 shows the building of gdb-sample1 and running the program without using gdb.
Figure 3.2. Building and running gdb-sample1.c.
|
为了演示gdb的特性,Listing 3.1包含了一个错误。让我们无调试器情况下运行gdb-sample1,会看到一个错误信息,图3.2展示了如何编译gdb-sampl1并且无调试的运行该程序
|
Listing 3.1. Sample Program (gdb-sample1.c)
1 int Change_Value = 0;
2
3 int Sum_it (int, int);
4 void error_with_code (void);
5
6 /******************************************/
7 /* */
8 /* main () - main routine */
9 /* */
10 /******************************************/
11
12 int main (void)
13 {
14 int Arg_1 = 20, Arg_2 = 40;
15 int i;
16
17
18 for (i = 0; i < 10; i++) {
19 if (Arg_1 > Arg_2)
20 Arg_2 = Sum_it (Arg_1, Arg_2);
21 else
22 Arg_1 = Sum_it (Arg_1, Arg_2);
23 }
24
25 error_with_code ();
26
27 } /* End of main() */
28
29
30 /**********************************************************/
31 /* */
32 /* Sum_it() - This routine adds two numbers and returns the
result */
33 /* */
34 /**********************************************************/
35 int Sum_it (int a, int b)
36
37 {
38 return a+b;
39
40 } /* End of Sum_it */
41
42
43
44 /**********************************************************/
45 /* */
46 /* error_with_code() - This routine has an intended bug.
*/
47 /*
*/
48
/***************************************************************
*/
49 void error_with_code(void)
50 {
51 int divide_value;
52 int result;
53
54 divide_value = Change_Value;
55 result = 10 / divide_value;
56 return ;
57
58 } /* End of error_with_code() */
Compiling a Program That Is to Be Debugged with gdb
The source code of the program that is to be debugged using gdb must first be successfully compiled. Once the program source code compiles successfully, compile it one more time using the
-g compiler option:
需要使用gdb调试的源代码首先必须被成功编译。一旦源程序可以成功编译,再使用-g选项编译一次:
g++ -g source_code_file.cpp
or或
gcc -g source_code_file.c
Note注意
g++ is the GNU C++ compiler, and gcc is the GNU C compiler.
g++ 是GNU c++ 编译器,gcc 是GNU c编译器
Using the
-g compiler option causes the compiler to build special symbols and tables of data that gdb needs for subsequent debugging.
使用-g编译器选项使得编译器构造构造特别的符号和表以便调试。
A Typical gdb Session
Invoking the gdb Debugger
After compiling the source code file with the
-g option, you are ready to use gdb and start debugging the program. To invoke gdb enter
gdb executable_file
在用-g选项编译了源代码后,你就可以使用gdb开始调试程序了,调用gdb如下:
Gdb 可执行文件
where
executable_file is the name of the compiled executable form of the program (which is a.out unless you have changed its name).
其中可执行文件是被编译的程序可执行形式的名字(如果没有改动,就是a.out)
Now let's look at the sample program gdb-sample1.c using gdb. Figures 3.3 through 3.5 show the starting of gdb and the following gdb commands:
现在让我们使用gdb来观察例子程序gdb-sample1.c.图3.3 到3.5显示了开始gdb以及如下的gdb命令:
· The
list command displays the source code for the gdb-sample1 program. The list command is entered three times.
List 命令用于显示gdb-sample1程序的源代码,list 命令被输入三次
· The
break command sets the break point on the Sum_it routine.
Break命令设置在Sum_it例程中设置断点
· The
break command sets the break point on line 26 of gdb-sample1.
Break命令设置在gdb-sample1的26行中设置断点
· The
run command starts the program executing. The break point at the Sum_it routine is hit.
Run命令开始程序执行。在Sum_it例程中的断点生效
· The
backtrace command shows the back trace of where the Sum_it routine is called from. In this case it is called from line 40 of main. The Sum_it parameters are a = 20 and b = 40.
Backtrace命令显示Sum_it例程调用的回溯。在此处为被main在40行调用,参数为a=20 和 b=40
· The
delete command removes the first break point on the Sum_it routine.
Delete命令删除位于Sum_it例程中的第一个断点
· The
cont command starts the program executing until the second break point at line 26 is hit.
Cont命令继续程序执行直到位于26行的第二个断点被激活
· The
cont command starts the program executing until the program has Arithmetic exception on line 57.
Cont命令继续执行程序直到程序在57行遇到算术异常
· The
print command displays the variable divide_value, which has a value of 0. The error in the program is caused by trying to divide 10 by 0 and store that result in a variable called result.
Print命令显示为0的divide_value的值。程序的错误就是尝试用0除以10,并存储结果到result变量中。
· The
print command displays the Change_Value variable.
Print命令显示Change_Value变量
· The
run command starts the program again. The program stops when it hits the break point on the error_with_code routine.
Run命令再次开始程序,当遇到error_with_code例程中的断点的时候程序停止运行
· The
set command changes the variable Change_Value to the correct value of 10. This is how the program should have been coded.
Set命令改变Change_Value变量为正确值10,这是程序应该如此编写
· The
s command steps one line of code.
S命令步进一行代码
· The
print command displays the value of the result variable, which is 1.
Print命令显示result变量的值,其值为1
· The
cont command continues running the program.
Cont命令继续运行程序
· The
quit command exits gdb.
Quit命令退出gdb
Figure 3.3. gdb-sample1 gdb commands.
Figure 3.4. gdb-sample1 gdb commands.
Figure 3.5. gdb-sample1 gdb commands
Debugging Using a Core File
For a user mode application to be able to create a core file, the system limit on the size of the core files must be greater than 0.
用户模式的应用程序可以创建一个内核文件,系统对内核文件尺寸的限制是必须大于0
The default core file size is 0. When the core file size is 0, the system does not allow a core dump. Figure 3.6 shows that the core file size is 0 using the
ulimit command with the -a option. To change the core file to 500,000, use the ulimit -c option.
缺省内核文件大小是0。当内核文件尺寸为0,系统不允许核心转储。图3.6中通过-a选项的ulimit命令显示了内核文件大小为0。为了改变内核文件到500,000,使用ulimit –c选项
Figure 3.6. Viewing and changing the core file size.
Running the Program and Getting the Core Dump
Now that core dump functionality has been enabled, Figure 3.7 shows debugging the gdb-sample1 program with a core file. The first step is to use gdb-sample1 as the program to be debugged. The next command,
core-file, says to use the file named core as the core dump. The gdb session using the core dump file identifies that the error occurred in routine error_with_code at line 57. Next, looking at the variable divide_value, you see that it has a value of 0, which is the reason this program took the Arithmetic exception on line 57. The program is doing a divide by 0.
现在内核转储功能已经可以使用了,图3.7显示了用内核文件调试gdb-sample1程序。第一步是使用gdb-sample1作为被调试程序,下一个命令,core-file使用core文件作为内核转储。Gdb会话利用内核转储文件识别出错误出现在error_with_code的57行。下一步,查看变量divide_value,你可以看到为0,这就是程序在57行出现算术异常的原因,程序正在做除0运算。
Figure 3.7. Using gdb on a core dump file.
Linux can create core files named core.PID, where PID is the process ID of the process that dumped the core. This feature can be set using the kernel
sysctl command for the core_uses_pid field. The default coredump filename is core. By setting core_uses_pid to 1, the coredump filename becomes core.PID. If core_pattern does not include %p (the default does not) and core_uses_pid is set, .PID is appended to the filename.
Linux能创建名为core.PID的核心文件,其中pid就是转储核心的进程ID,使用内核sysctl命令设置core_uses_pid到1就可以利用该特性。通过设置,内核转储文件名就变成core.PID。如果core_pattern没有包含 %p(缺省未包含)并且core_uses_pid被设置,.PID就会被添加到文件名。
Graphical gdb Interfaces
Once gdb is working on your system, its text console is fast and easy to use. It is a bit outdated, though. Fortunately, several free graphical add-ons are easy to use. These enhancements all use a running instance of gdb itself as the low-level debugger. We'll cover two of the graphical interfacesData Display Debugger (ddd) and Insight.
一旦gdb可以在你的系统上工作,它的文本控制台用起来又快又容易,但却有点儿过时。幸运的是,几个免费的图形附加扩展很容易使用。这些增强都是用了一个运行的gdb实例作为底层调试器。我们将讨论两个图形界面,DDD和insight
Data Display Debugger
The ddd is a mature, high-quality X Window-based graphical gdb interface. ddd provides an easy-to-navigate graphical data display that allows sophisticated data structure visualization with just a few mouse clicks.
Ddd是程序的高质量的基于X窗口的图形gdb接口。Ddd提供了很容易导航的图形数据显示,仅仅几次鼠标点击,就可以可视化复杂的数据结构
ddd Features
Besides "classic" front-end features such as viewing source code, ddd provides a graphical data display, where data structures are displayed as graphs. A simple mouse click lets you dereference pointers or view structure contents, updated each time the program stops. Using ddd, you can view the application's data easily, not just by watching it execute lines of source code.
Other ddd features include the following:
除了经典的诸如显示源代码等前端特性外,ddd提供了一个图形数据显示,数据结构可以被作为图形显示。一个简单的鼠标单击允许你对指针解引用或者查看结构内容,每次程序停止后的更新。使用ddd能够使你容易的观察应用数据,而不是观看源代码行的执行。
其他的 ddd特性如下:
· Debugging of programs written in C, C++, Ada, Fortran, Java, Perl, Pascal, Modula-2, and Modula-3
· 可以调试C, C++, Ada, Fortran, Java, Perl, Pascal, Modula-2和 Modula-3
· Machine-level debugging
机器层调试
· Hypertext source navigation and lookup
超文本源代码导航和查找
· Break point, back trace, and history editors
断点,回溯以及历史编辑
· Preferences and settings editors
偏好和设置编辑器
· Program execution in a terminal emulator window、
在一个终端模拟窗口执行程序
· Debugging on a remote host
远程主机调试
· Online manual
在线文档
· Interactive help on the Motif user interface
Motif用户接口的交互式帮助
Installing ddd
ddd is generally distributed as source code, archived, and compressed into a single file using the tar and gzip utilities. Once the source code is in hand, the user typically decompresses, configures, compiles, and installs the program. Most, if not all, Linux distributions ship a version of the ddd package, but the steps to install and build it are listed next. You'll download version 3.3.8 of ddd and use that version throughout this chapter. Follow these steps to install ddd:
ddd通常以源代码的形式发行,使用tar和gzip工具被归档和压缩成单个文件。一旦获得了源代码,用户一般会解压缩,配置,编译和安装程序。绝大多数(如果不是所有)情况下,linux发布会带有一个ddd包,安装和构建的步骤如下。你应当下载3.3.8版本的ddd并在本章使用该版本,以下步骤安装ddd:
1. Extract ddd-3.8.8.tar.gz: 抽取ddd-3.3.8.tar.gz
# tar xzvf ddd-3.8.8.tar.gz
# cd ddd-3.8.8
# ./configure
configure looks at the machine's setup and creates the proper local environment in which to build ddd
configure查找机器安装并且创建正确的本地环境构建ddd
2. Tell ddd to compile and install:编译安装ddd
# make
# make install
ddd Ways to View a Program
There are three different ways to invoke ddd:有3种方法调用ddd
· ddd executable_file
· ddd executable_file core
· ddd executable_file process_id
The file named core is produced whenever a program has an error and crashes. The core file contains useful information about the program's status during the error that generates the crash. If your system does not generate core dumps, look at the environment variables for the core (refer to Figure 3.6). (
ulimit -a shows all of them. You also can use ulimit -c value to define the maximum core file size.)
文件名为core的文件是由于程序有错误或者崩溃所产生的。内核文件包含了当错误和崩溃出现时有用的程序状态信息。如果你的系统不生成内核转储,请查看内核的环境变量。(参考图3.6)(ulimit –a显示所有内核环境,你也可以使用ulimit –c 值来定义最大内核文件尺寸)
The
process id allows you to inspect the program during runtime.
进程id允许你在程序运行的时候检查程序。
Figure 3.8 shows an example of using ddd on the program gdb-sample1.
Figure 3.8. Using ddd on gdb-sample1.
Figure 3.9 shows the running of gdb-sample1 with the exception on line 57.
Figure 3.9. gdb-sample1 exception.
ddd has some nice features. If you right-click
main, the following pull-down menu appears:
ddd有一些极好的特性,如果你右击main,如下的菜单将要出现:
Print
main 打印
main
Display
main显示
main
Print
*main 打印
*main
Display
*main 显示
*main
What is
main main是什么?
Lookup
main 查找
main
Break at
main 在
main处设置断点
Clear at
main 清除
main处断点
Figure 3.10 shows the result of choosing the option Break at
main.
Figure 3.10. A break point at main.
Insight
Insight is a graphical enhancement to gdb. In contrast to ddd, Insight's graphics are from Tcl/Tk instead of X Window. Furthermore, Insight is compiled into gdb (rather than its running gdb as a subprocess, the way ddd does). This improves its performance and makes its communications with gdb more interactive.
Insight是gdb的图形增强,对比ddd,Insight的图形是基于tcl/tk的,而不是X窗口的。而且,Insight是编译进gdb的(而不是如ddd那样把gdb作为子进程)。这个特点增强了性能并使得和gdb的通讯更加有交互性。
Insight Features
Insight has the following features:Insight有如下特点:
· Source window源代码窗口
· Dialog boxes for the Source window针对源窗口的对话框
· Stack window栈窗口
· Registers window寄存器窗口
· Memory window内存窗口
· Watch Expressions window监视表达式窗口
· Local Variables window局部变量窗口
· Break points window断点窗口
· Console window控制台窗口
· Function Browser window函数浏览窗口
· Threads window线程窗口
· Help window帮助窗口
· Memory window内存窗口
· Source search widget源代码搜索小控件
· Source window cache (for faster navigation, searches, and settings)
源代码窗口缓存(为更快的导航,搜索和设置)
· Function browser window (a user interface feature to examine functions in source code)
函数浏览窗口(用于检查源代码中函数的用户接口特性)
· Special right-click mouse features for better and faster access to debugger GUI features
特定的右键鼠标特性以便更快的存取调试器GUI特性
Installing Insight
Insight generally is distributed as source code, archived, and compressed into a single file using the tar and gzip utilities. Once the source code is in hand, the user typically decompresses, configures, compiles, and installs the programs. Most, if not all, Linux distributions ship a version of the Insight package, but the steps to install and build it are listed next. You'll download version 6.1 of Insight and use that version throughout this chapter. Follow these steps to install Insight:
Insight通常以源代码的形式发行,使用tar和gzip工具被归档和压缩成单个文件。一旦获得了源代码,用户一般会解压缩,配置,编译和安装程序。绝大多数(如果不是所有)情况下,linux发布会带有一个Insight包,安装和构建的步骤如下。你应当下载6.1版本的ddd并在本章使用该版本,以下步骤安装Insight:
1.
|
Decompress insight-6.1.tar.gz:解压缩insight-6.1.tar.gz
# tar xzvf insight-6.1.tar.gz # cd insight-6.1 # ./configure
configure looks at the machine's setup and creates the proper local environment in which to build Insight.configure
将查看本机设置并创建正确的本地环境来构建insight
|
2.
|
Tell Insight to compile and install:编译和安装insight
# make # make install
|
Figure 3.11 shows gdb-sample1.
Figure 3.11. Using gdb-sample1.
Now let's look at using Insight to debug threaded programs.
现在看一下如何使用Insight来调试多线程程序。
Listing 3.2 is a sample program that uses
pthread_create to create a new thread of control that executes concurrently with the calling thread. The gdb-sample2.c program creates two threads by using the pthread_create API. The first thread uses the Thread_function1 routine, and the second thread uses the Thread_function2 routine. This sample program shows the different commands that are used when programs have multiple threads. Figure 3.12 shows the output from gdb-sample2.
列表3.2时一个使用pthread_create创建一个新线程来控制和调用线程的同步的程序。Gdb-sample2.c使用了pthread_create API创建了两个线程。第一个线程使用Thread_function函数,第二个线程使用Thread_function2函数。例子程序展现了不同的用于调试多线程的命令。图3.12展示了gdb-sample2的输出。
Figure 3.12. Output from gdb-sample2.
Listing 3.2. gdb-sample2.c
1 #include
2 #include
3 #include
4 void* Thread_function1(void * arg)
5 {
6 unsigned int i=1;
7 while(i < 11)
8 {
9 printf("Child Thread Iteration %d/n",i);
10 i++;
11 if(i%2)
12 sleep(2);
13 else
14 sleep(1);
15 }
16 return arg;
17 }
18 void* Thread_function2(void * arg)
19 {
20 unsigned int i=1;
21 while(i < 11)
22 {
23 printf("Child Thread 2 Iteration %d/n",i);
24 i++;
25 if(i%2)
26 sleep(2);
27 else
28 sleep(1);
29 }
30 return arg;
31 }
32 int main (int argc, char *argv[])
33 {
34 pthread_t thread;
35 pthread_t thread2;
36 if(pthread_create(&thread,NULL,Thread_function1,NULL))
37 {
38 return(1);
39 }
40 if(pthread_create(&thread2,NULL,Thread_function2,NULL))
41 {
42 return(1);
43 }
44 unsigned int i = 1;
45 while(i < 11)
46 {
47 printf("Main Loop Iteration %d/n",i);
48 i++;
49 if(i%2)
50 sleep(1);
51 else
52 sleep(2);
53 }
54 return 0;
55 }
Now let's look at the sample program gdb-sample2.c using gdb. Figures 3.13 through Figure 3.15 show the starting of gdb and the following gdb commands:
现在让我们看看例子程序gdb-sample2.c。图3.13到图3.15显示了开始gdb以及紧接着的gdb命令:
· The
run command starts the program. You can press Ctrl-C to break in and stop the program's execution. Four threads are created16384, 32769, 16386, and 32771.
Run命令开始程序,你可以按Ctrl-C切入并停止程序执行,四个线程被创建:16384, 32769, 16386, 和32771.
· The
info threads command displays the program's threads.
Info threads命令显示了程序的线程
· The
thread 4 command switches to that thread.
Thread 4命令切换到第四个线程
· The
where command displays a back trace for thread 4.
Where命令显示了线程4的回溯
· The
thread 3 command switches to that thread.
Thread 3命令切换到线程3
· The
where command displays a back trace for thread 3.
Where命令显示了线程3的回溯
· The
thread 2 command switches to that thread.
Thread 2命令切换到线程2
· The
where command displays a back trace for thread 2.
Where命令显示了线程2的回溯
· The
thread 1 command switches to that thread.
Thread 1命令切换到线程1
· The
where command displays a back trace for thread 1.
Where命令显示了线程1的回溯
· The
list command for gdb-sample2.c.52 sees where thread 1 called the routine sleep from.
List命令gdb-sample2.c:52看线程1中何处调用了sleep
· The
list command for gdb-sample2.c.14 sees where thread 3 called the routine sleep from.
List命令gdb-sample2.c:14看线程3中何处调用了sleep
Figure 3.13. Building gdb-sample2 and running it under gdb.
Figure 3.14. thread and where commands.
Figure 3.15. Viewing threads.
Now that you know some useful gdb threading commands, such as
info threads and thread, you should be able to debug multithreaded programs.
现在知道了一些有用的gdb线程命令,诸如info threads和thread,你应该可以条似乎多线程程序了。
Debugging Symbols Increase the Executable's Size
Most programs and libraries are, by default, compiled with debugging symbols included (with gcc's
-g option). This means that, when debugging a program or library that was compiled with debugging information included, the debugger can give not only memory addresses but also the names of the routines and variables.
绝大部分程序和库在缺省情况下都编译成调试版本(用了gcc的-g选项)。这就意味着当调试带有调试信息的程序或者库的时候,调试器不光给出内存地址,也给出函数和变量的名字
Including these debugging symbols, however, enlarges a program or library significantly. To give you an idea of how much space these symbols occupy, an lsof binary with debugging symbols is 209,229 bytes, and an lsof binary without debugging symbols is 103,894 bytes.
然而包含这些调试符号会显著增大程序或者库的大小。为了使你了解这些符号占有多少空间,一个lsof带调试符号的二进制是209,229字节,一个不带调试符号的二进制是103,894字节。
Sizes may vary somewhat, but when you compare programs with and without debugging symbols, the difference can be a factor between 2 and 4. Programs can be built with debugging symbols included. Then, if the symbols are unneeded, you can remove them using the
strip command. Figure 3.16 shows the last part of building lsof with the -g option added to CFLAGS. Also shown is the size of the lsof program before and after the symbols have been removed.
大小可能有所变化,但是如果你比较有无调试符号的程序,差异可能是2到4倍。程序可以包含调试符号。当符号信息不需要的时候,你可以使用strip命令去除它们。图3.16显示了CFLAGS中带-g选项的lsof库的最后部分。也显示了有无符号的大小差异
Figure 3.16. The strip command to remove symbols.
Debugging Techniques
Now let's look at some helpful hints for debugging an application more quickly.
现在让我们看一些可以帮我们更快的调试应用程序的建议:
When debugging, it is often a good practice to stop program execution at the bottom of a function so that a
print or multiple displays can be done to see the current values stored in the data the function has altered. There is no simple built-in gdb statement to do this, but you can do the following:
当调试的时候,在函数底部停止执行是一个好的实践,一个print或者多个display可以帮你查看已经被函数改变的数据的当前值。没有简单的内建语句完成这个,但你可以如下操作:
1.
|
Do a
list funct_name, and find the number of the line (line#) in that function where the function end-block-delimiter (}) is.
做list funct_name,发现函数结束定界符的行数(line#)
|
2.
|
Set a break point at each of these line numbers using the following:
在所有这些地方使用下面的命令设置断点:
"break "
|
Use the line numbers that were identified in step 1. When the
run command is issued in the debugger, the program execution stops at the end of each function in the program. At that time you can do a print to examine the values currently stored in program data objects (global, local, or parameters passed into the function).
使用步骤1种提到的行号,当调试器使用了run命令后,程序将停止在程序中每个函数的结尾。此时你可以用print检查当前存储在程序数据对象中的当前值(全局的,局部的,被传入的参数等等)
You can find out where a program is crashing. A
segmentation fault - core dumped message, a bus error message, and other such messages indicate that the logic at some point in a program is incorrect. For this reason, the program execution cannot continuethat is, the program stops running, or a crash happens.
你可以发现程序何处崩溃。一个段错误内核转储消息,一个总线错误消息以及其他诸如此类的消息指示了程序某些点上的逻辑是不正确的。由于这个原因,程序无法继续执行,也就是说停止运行或者崩溃发生了
To find out the exact line of source code that caused your program to crash, do the following:
为了查找导致程序崩溃的源代码特定行,可以如下操作:
1. Compile your program using the
-g compiler option if this hasn't already been done.
如果没有的话,使用-g编译器选项编译程序
2. Enter
gdb executable_file from the Linux command line.
在linux命令行输入gdb 可执行文件
3. Enter the
run command. The program begins executing and stops at the first line of code that has an error (the program may have more than one runtime error).
输入run命令,程序开始执行,并停止在第一个有错误的代码行处
4. Enter the gdb command
list. In most cases, gdb lists the line of code that caused the program to crash.
输入gdb的list命令,绝大部分情况下,gdb将会列出导致程序崩溃的那行
5. Edit the source code, and go to the line of code just specified. Fix the logical error and then recompile and run the program to see if things are now working correctly.
编辑源代码,去出问题的行,修复逻辑错误,然后重新编译运行看是否工作已经正常。
Do the following to step through the entire program:
做如下步骤以便步进通过整个程序:
1. Start the executable code by using gdb.
使用gdb开始程序
2. Enter
break main from the gdb command line.
在gdb命令行输入break main
3. Enter
run from the gdb command line. The program begins executing. Execution stops on line 1 of main.
在gdb命令行输入run,程序开始执行并停止在main函数的第一行
4. Repeatedly enter
step from the gdb command line. At each step, you can execute a print command to see the values of variables as the program executes.
在gdb命令行重复输入step命令,在每一步,你可以执行print命令来查看程序执行时变量的值
Summary
This chapter covered gdb and two GUIs for gdbddd and Insightboth of which reduce debugging time. One way that they can do this is by displaying the value of the variable when you move the mouse over that variable. When gdb is used, the
print command must be invoked to display the variable's value. The user can see much more information at one time. The GUI interface is more intuitive, and data structures are easier to visualize.
本章覆盖了gdb和两个gdb图形化接口工具 ddd和insight。图形化工具减少了调试时间,当移动鼠标到变量上的时候,他们可以显示变量的值。如果使用gdb,必须使用print命令显示变量值。用户也可以一次看到更多的信息,GUI界面是更直观的,数据结构也更容易可视化。
Web Resources for GNU Debugger
URL
|
Description
|
http://www.gnu.org/software/gdb/gdb.html
|
gdb
|
http://sources.redhat.com/gdb/current/onlinedocs/gdb.html#SEC_Top
|
Debugging with gdb
|
http://www.gnu.org/software/ddd/
|
ddd
|
http://sources.redhat.com/insight/
|
Insight
|
|