⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 使用 gdb 调试 linux 软件 (转).txt

📁 LINUX下的安装声卡等操作和技巧介绍
💻 TXT
📖 第 1 页 / 共 2 页
字号:
(gdb) break main 
Breakpoint 1 at 0x8048402: file eg1.c, line 15. 
(gdb) run 
... 
Breakpoint 1, main (argc=1, argv=0xbffff954) at eg1.c:15 
15 value = 10; 



要了解 "div" 何时更改,可以使用 watch div,但由于要在 "div" 等于 "value" 时中断,那么应输入: 


(gdb) watch div==value 
Hardware watchpoint 2: div == value 



如果继续执行,那么当表达式 "div==value" 的值从 0(假)变成 1(真)时,gdb 将中断: 


(gdb) continue 
Continuing. 
Hardware watchpoint 2: div == value 

Old value = 0 
New value = 1 
main (argc=1, argv=0xbffff954) at eg1.c:19 
19 for(i = 0; i < 10; i++) 



info locals 命令将验证 "value" 是否确实等于 "div"(再次声明,是 8)。 

info watch 命令将列出已定义的监视点和断点(此命令等价于 info break),而且可以使用与断点相同的语法来启用、禁用和删除监视点。 

core 文件 
在 gdb 下运行程序可以使俘获错误变得更容易,但在调试器外运行的程序通常会中止而只留下一个 core 文件。gdb 可以装入 core 文件,并让您检查程序中止之前的状态。 

在 gdb 外运行示例程序 eg1 将会导致核心信息转储: 

$ ./eg1 
Floating point exception (core dumped) 



要使用 core 文件启动 gdb,在 shell 中发出命令 gdb eg1 core 或 gdb eg1 -c core。gdb 将装入 core 文件,eg1 的程序清单,显示程序是如何终止的,并显示非常类似于我们刚才在 gdb 下运行程序时看到的消息: 


... 
Core was generated by `./eg1. 
Program terminated with signal 8, Floating point exception. 
... 
#0 0x80483ea in wib (no1=8, no2=8) at eg1.c:7 
7 result = no1 / diff; 



此时,可以发出 info locals、print、info args 和 list 命令来查看引起除数为零的值。info variables 命令将打印出所有程序变量的值,但这要进行很长时间,因为 gdb 将打印 C 库和程序代码中的变量。为了更容易地查明在调用 wib() 的函数中发生了什么情况,可以使用 gdb 的堆栈命令。 

堆栈跟踪 
程序“调用堆栈”是当前函数之前的所有已调用函数的列表(包括当前函数)。每个函数及其变量都被分配了一个“帧”,最近调用的函数在 0 号帧中(“底部”帧)。要打印堆栈,发出命令 t(acktrace [回溯] 的缩写): 


(gdb) bt 
#0 0x80483ea in wib (no1=8, no2=8) at eg1.c:7 
#1 0x8048435 in main (argc=1, argv=0xbffff9c4) at eg1.c:21 



此结果显示了在 main() 的第 21 行中调用了函数 wib()(只要使用 list 21 就能证实这一点),而且 wib() 在 0 号帧中,main() 在 1 号帧中。由于 wib() 在 0 号帧中,那么它就是执行程序时发生算术错误的函数。 

实际上,发出 info locals 命令时,gdb 会打印出当前帧中的局部变量,缺省情况下,这个帧中的函数就是被中断的函数(0 号帧)。可以使用命令 frame 打印当前帧。要查看 main 函数(在 1 号帧中)中的变量,可以发出 frame 1 切换到 1 号帧,然后发出 info locals 命令: 


(gdb) frame 1 
#1 0x8048435 in main (argc=1, argv=0xbffff9c4) at eg1.c:21 
21 result = wib(value, div); 
(gdb) info locals 
value = 8 
div = 8 
result = 4 
i = 2 
total = 6 



此信息显示了在第三次执行 "for" 循环时(i 等于 2)发生了错误,此时 "value" 等于 "div"。 

可以通过如上所示在 frame 命令中明确指定号码,或者使用 up 命令在堆栈中上移以及 down 命令在堆栈中下移来切换帧。要获取有关帧的进一步信息,如它的地址和程序语言,可以使用命令 info frame。 

gdb 堆栈命令可以在程序执行期间使用,也可以在 core 文件中使用,因此对于复杂的程序,可以在程序运行时跟踪它是如何转到函数的。 

连接到其它进程 
除了调试 core 文件或程序之外,gdb 还可以连接到已经运行的进程(它的程序已经过编译,并加入了调试信息),并中断该进程。只需用希望 gdb 连接的进程标识替换 core 文件名就可以执行此操作。以下是一个执行循环并睡眠的示例程序: 

eg2 示例代码 
#include 
int main(int argc, char *argv[]) 
{ 
int i; 
for(i = 0; i < 60; i++) 
{ 
sleep(1); 
} 

return 0; 
} 




使用 gcc -g eg2.c -o eg2 编译该程序并使用 ./eg2 & 运行该程序。请留意在启动该程序时在背景上打印的进程标识,在本例中是 1283: 

./eg2 & 
[3] 1283 



启动 gdb 并指定进程标识,在我举的这个例子中是 gdb eg2 1283。gdb 会查找一个叫作 "1283" 的 core 文件。如果没有找到,那么只要进程 1283 正在运行(在本例中可能在 sleep() 中),gdb 就会连接并中断该进程: 


... 
/home/seager/gdb/1283: No such file or directory. 
Attaching to program: /home/seager/gdb/eg2, Pid 1283 
... 
0x400a87f1 in __libc_nanosleep () from /lib/libc.so.6 
(gdb) 



此时,可以发出所有常用 gdb 命令。可以使用 acktrace 来查看当前位置与 main() 的相对关系,以及 mian() 的帧号是什么,然后切换到 main() 所在的帧,查看已经在 "for" 循环中运行了多少次: 

(gdb) backtrace 
#0 0x400a87f1 in __libc_nanosleep () from /lib/libc.so.6 
#1 0x400a877d in __sleep (seconds=1) at ../sysdeps/unix/sysv/linux/sleep.c:78 
#2 0x80483ef in main (argc=1, argv=0xbffff9c4) at eg2.c:7 
(gdb) frame 2 
#2 0x80483ef in main (argc=1, argv=0xbffff9c4) at eg2.c:7 
7 sleep(1); 
(gdb) print i 
$1 = 50 



如果已经完成了对程序的修改,可以 detach 命令继续执行程序,或者 kill 命令杀死进程。还可以首先使用 file eg2 装入文件,然后发出 attach 1283 命令连接到进程标识 1283 下的 eg2。 

其它小技巧 
gdb 可以让您通过使用 shell 命令在不退出调试环境的情况下运行 shell 命令,调用形式是 shell [commandline],这有助于在调试时更改源代码。 

最后,在程序运行时,可以使用 set 命令修改变量的值。在 gdb 下再次运行 eg1,使用命令 reak 7 if diff==0 在第 7 行(将在此处计算结果)设置条件断点,然后运行程序。当 gdb 中断执行时,可以将 "diff" 设置成非零值,使程序继续运行直至结束: 


Breakpoint 1, wib (no1=8, no2=8) at eg1.c:7 
7 result = no1 / diff; 
(gdb) print diff 
$1 = 0 
(gdb) set diff=1 
(gdb) continue 
Continuing. 
0 wibed by 16 equals 10 

Program exited normally. 



结束语 
GNU 调试器是所有程序员工具库中的一个功能非常强大的工具。在本文中,我只介绍了 gdb 的一小部分功能。要了解更多知识,建议您阅读 GNU 调试器手册。 

参考资料 

GNU 调试器手册 
调试会话示例的源代码。 
连接示例的源代码。 

关于作者 

David Seager 是 IBM 的软件开发人员,他从事 Linux 和基于 Web 的应用工作已有两年时间了。 

 

来源:IBM开发网  

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -