首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

Linux on Power 上的调试工具和技术(2)

Linux on Power 上的调试工具和技术(2)

调试其他程序问题的工具和技术除了内存 bug 之外,开发人员通常还会碰到程序虽然能够成功编译,但是在运行时却会产生内核转储或段错误的问题。有时在程序完成之后,程序的输出可能与所期望或设计的不同。在这两种情况中,可能代码中存在您认为正确而实际上错误的情况。接下来的几节中介绍的调试器将帮助您找到这些情况的原因。
GNU 项目调试器GDB(GNU 项目调试器)可以让您了解程序在执行时“内部” 究竟在干些什么,以及在程序发生崩溃的瞬间正在做什么。
GDB 做以下 4 件主要的事情来帮助您捕获程序中的 bug:
  • 在程序启动之前指定一些可以影响程序行为的变量或条件
  • 在某个指定的地方或条件下暂停程序
  • 在程序停止时检查已经发生了什么
  • 在程序执行过程中修改程序中的变量或条件,这样就可以体验修复一个 bug 的成果,并继续了解其他 bug
要调试的程序可以是使用 C、C++、Pascal、Objective-C 以及其他很多语言编写的。GDB 的二进制文件名是 gdb。
gdb 中有很多命令。使用 help 命令可以列出所有的命令,以及关于如何使用这些命令的介绍。下表给出了最常用的 GDB 命令。
表 1. gdb 中最常用的命令命令说明例子help显示命令类别help - 显示命令类别
help breakpoints  - 显示属于 breakpoints 类别的命令
help break - 显示 break 命令的解释run启动所调试的程序                                                ?                                        kill终止正在调试的程序的执行通常这会在要执行的代码行已经超过了您想要调试的代码时使用。执行 kill 会重置断点,并从头再次运行这个程序


cont所调试的程序运行到一个断点、异常或单步之后,继续执行                                                ?                                        info break显示当前的断点或观察点                                                ?                                        break在指定的行或函数处设置断点break 93 if i=8 - 当变量 i 等于 8 时,在第 93 行停止程序执行Step单步执行程序,直到它到达一个不同的源代码行。您可以使用 s 来代表 step 命令                                                ?                                        Next与 step 命令类似,只是它不会“单步跟踪到”子例程中                                                ?                                        print打印一个变量或表达式的值print pointer - 打印变量指针的内容
print *pointer - 打印指针所指向的数据结构的内容delete删除某些断点或自动显示表达式delete 1 - 删除断点 1。断点可以通过 info break 来显示                                        watch为一个表达式设置一个观察点。当表达式的值发生变化时,这个观察点就会暂停程序的执行                                                ?                                        where打印所有堆栈帧的栈信息where - 不使用参数,输出当前线程的堆栈信息
where all - 输出当前线程组中所有线程的堆栈信息
where threadindex  - 输出指定线程的堆栈信息attach开始查看一个已经运行的进程attach <process_id> - 附加到进程 process_id 上。process_id 可以使用 ps 命令找到info thread显示当前正在运行的线程                                                ?                                        thread apply threadno command对一个线程运行 gdb 命令thread apply 3 where - 对线程 3 运行 where 命令Thread threadno选择一个线程作为当前线程                                                ?                                       
如果一个程序崩溃了,并生成了一个 core 文件,您可以查看 core 文件来判断进程结束时的状态。使用下面的命令启动 gdb:
1
# gdb programname corefilename




要调试一个 core 文件,您需要可执行程序、源代码文件以及 core 文件。要对一个 core 文件启动 gdb,请使用 -c 选项:
1
# gdb -c core programname




gdb 会显示是哪行代码导致这个程序产生了核心转储。
默认情况下,核心转储在 Novell 的 SUSE LINUX Enterprise Server 9(SLES 9)和 Red Hat? Enterprise Linux Advanced Server(RHEL AS 4)上都是禁用的。要启用核心转储,请以 root 用户的身份在命令行中执行 ulimit –c unlimited。
清单 8 中的例子阐述了如何使用 gdb 来定位程序中的 bug。清单 8 是一段包含 bug 的 C++ 代码。
清单 8 中的 C++ 程序试图构建 10 个链接在一起的数字框(number box),例如:
图 1. 一个包含 10 个链接在一起的数字框的列表然后试图从这个列表中逐个删除数字框。
编译并运行这个程序,如下所示:
清单 9. 编译并运行这个程序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# g++ -g -o gdbtest1 gdbtest1.cpp
# ./gdbtest1
Number Box "0" created
Number Box "1" created
Number Box "2" created
Number Box "3" created
Number Box "4" created
Number Box "5" created
Number Box "6" created
Number Box "7" created
Number Box "8" created
Number Box "9" created
list created
Number Box "9" deleted
Segmentation fault




正如您可以看到的一样,这个程序会导致段错误。调用 gdb 来看一下这个问题,如下所示:
清单 10. 调用 gdb
1
2
3
4
5
6
7
8
9
10
11
12
# gdb ./gdbtest1
GNU gdb 6.2.1
Copyright 2004 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 "ppc-suse-linux"...Using host libthread_db
library "/lib/tls/libthread_db.so.1".
(gdb)




您知道段错误是在数字框 "9" 被删除之后发生的。执行 run 和 where 命令来精确定位段错误发生在程序中的什么位置。
清单 11. 执行 run 和 where 命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
(gdb) run
Starting program: /root/test/gdbtest1
Number Box "0" created
Number Box "1" created
Number Box "2" created
Number Box "3" created
Number Box "4" created
Number Box "5" created
Number Box "6" created
Number Box "7" created
Number Box "8" created
Number Box "9" created
list created
Number Box "9" deleted
Program received signal SIGSEGV, Segmentation fault.
0x10000f74 in NumBox<int>::GetNext (this=0x0) at gdbtest1.cpp:14
14              NumBox<T>*GetNext() const { return Next; }
(gdb) where
#0  0x10000f74 in NumBox<int>::GetNext (this=0x0) at gdbtest1.cpp:14
#1  0x10000d10 in NumChain<int>::RemoveBox (this=0x10012008,
<br>item_to_remove=@0xffffe200) at gdbtest1.cpp:63
#2  0x10000978 in main (argc=1, argv=0xffffe554) at gdbtest1.cpp:94
(gdb)




跟踪信息显示这个程序在第 14 行 NumBox<int>::GetNext (this=0x0) 接收到一个段错误。这个数字框上 Next 指针的地址是 0x0,这对于一个数字框来说是一个无效的地址。从上面的跟踪信息可以看出,GetNext 函数是由 63 行调用的。看一下在 gdbtest1.cpp 的 63 行附近发生了什么:
返回列表