如何使用gdb调试多进程
来源:互联网 发布:蚁群算法教程 编辑:程序博客网 时间:2024/05/05 18:15
GDB提供了两种方式来调试正在运行的进程:一种是在GDB命令行上指定进程的PID,另一种是在GDB中使用“attach”命令。例如,开发人员可以先启动debugme程序,让其开始等待用户的输入。示例如下:
#./debugme Enter a string to count words:
接下去在另一个虚拟控制台中用下面的命令查出该进程对应的进程号:
# ps -ax | grep debugme 555 pts/1 S 0:00 ./debugme
得到进程的PID后,就可以使用GDB对其进行调试了:
# gdb debugme 555 GNU gdb Red Hat Linux (5.3post-0.20021129.18rh) Attaching to program: /home/xiaowp/debugme, process 555 Reading symbols from /lib/libc.so.6...done. ……
在上面的输出信息中,以Attaching to program开始的行表明GDB已经成功地附加在PID为555的进程上了。另外一种连接到其它进程的方法是先用file命令加载调试时所需的符号表,然后再通过“attaché”命令进行连接:
(gdb) file /home/xiaowp/debugme Reading symbols from /home/xiaowp/debugme...done. (gdb) attach 555 ……
如果想知道程序现在运行到了哪里,同样可以使用“backtrace”命令。当然也可以使用“step”命令对程序进行单步调试。
在完成调试之后,不要忘记用detach命令断开连接,让被调试的进程可以继续正常运行。
面临问题:一般情况下,如果被gdb调试的程序中调用fork派生出一个新的子进程,这时gdb调试的仍然还是父进程,其子进程的执行不被理会。如果之前你在子进程的执行routine上设置了断点,那么当子进程执行到那个断点时,子进程会因为收到一个SIGTRAP信号而自行终止,除非你在子进程中拦截了该信号。
那么使用GDB该如何调试多进程程序呢?
测试程序]
我们先看看我们的测试程序:
gcc eg1.c -o eg1 -g
/* in eg1.c */
intwib(int no1, int no2)
{
int result, diff;
diff = no1 - no2;
result = no1 / diff;
return result;
}
intmain()
{
pid_t pid;
pid = fork();
if (pid <0) {
printf("forkerr/n");
exit(-1);
} else if (pid == 0) {
/* in child process */
sleep(60);------------------ (!)
int value = 10;
int div = 6;
int total = 0;
int i = 0;
int result = 0;
for (i = 0; i < 10; i++) {
result =wib(value, div);
total += result;
div++;
value--;
}
printf("%d wibed by %d equals%d/n", value, div, total);
exit(0);
} else {
/* in parent process */
sleep(4);
wait(-1);
exit(0);
}
}
该测试程序中子进程运行过程中会在wib函数中出现一个'除0'异常。现在我们就要调试该子进程。
[调试原理]
不知道大家发现没有,在(!)处在我们的测试程序在父进程fork后,子进程调用sleep睡了60秒。这就是关键,这个sleep本来是不该存在于子进程代码中的,而是而了使用GDB调试后加入的,它是我们调试的一个关键点。为什么要让子进程刚刚运行就开始sleep呢?因为我们要在子进程睡眠期间,利用shell命令获取其process id,然后再利用gdb调试外部进程的方法attach到该process id上,调试该进程。
[调试过程]
我觉上面的调试原理的思路已经很清晰了,剩下的就是如何操作的问题了。我们来实践一次吧!
我所使用的环境是SolarisOS 9.0/GCC 3.2/GDB 6.1。
GDB调试程序的前提条件就是你编译程序时必须加入调试符号信息,即使用'-g'编译选项。首先编译我们的源程序'gcc -g -o eg1 eg1.c'。编译好之后,我们就有了我们的调试目标eg1。由于我们在调试过程中需要多个工具配合,所以你最好多打开几个终端窗口,另外一点需要注意的是最好在eg1的working directory下执行gdb程序,否则gdb回提示'No symbol table is loaded'。你还得手工load symbol table。好了,下面我们就'按部就班'的开始调试我们的eg1。
执行eg1:
eg1 & --- 让eg1后台运行吧。
查找进程id:
ps -fu YOUR_USER_NAME
运行gdb:
gdb
(gdb) attach xxxxx --- xxxxx为利用ps命令获得的子进程process id
(gdb)stop---这点很重要,你需要先暂停那个子进程,然后设置一些断点和一些Watch
(gdb) break 37 --在result =wib(value, div);这行设置一个断点,可以使用list命令察看源代码
Breakpoint 1 at 0x10808: file eg1.c, line 37.
(gdb) continue 继续执行程序,直至下一中断或者程序结束
Continuing.
Breakpoint1, main () at eg1.c:37
37 result =wib(value, div);
(gdb) step 执行一行源代码而且进入函数内部
wib (no1=10, no2=6) at eg1.c:13
13 diff = no1 - no2;
(gdb) continue
Continuing.
Breakpoint1, main () at eg1.c:37
37 result =wib(value, div);
(gdb) step
wib (no1=9, no2=7) at eg1.c:13
13 diff = no1 - no2;
(gdb) continue
Continuing.
Breakpoint1, main () at eg1.c:37
37 result =wib(value, div);
(gdb) step
wib (no1=8, no2=8) at eg1.c:13
13 diff = no1 - no2;
(gdb) next
14 result = no1 / diff;
(gdb) print diff
$6 = 0 ------- 除数为0,我们找到罪魁祸首了。
(gdb) next
Program received signal SIGFPE, Arithmetic exception.
0xff29d830 in .div() from /usr/lib/libc.so.1
至此,我们调试完毕。
上面仅仅是一个简单的多进程程序,在我们平时开发的多进程程序远远比这个复杂,但是调试基本原理是不变,有一些技巧则需要我们在实践中慢慢摸索
实战:
root@ubuntu:/home/ygm/tmp# ./eg1 &
[1] 2597
root@ubuntu:/home/ygm/tmp# ps -ef | grep eg1
root 2597 2167 0 06:09 pts/0 00:00:00 ./eg1
root 2598 2597 0 06:09 pts/0 00:00:00 ./eg1
root 2600 2167 0 06:09 pts/0 00:00:00 grep --color=auto eg1
root@ubuntu:/home/ygm/tmp# gdb
GNU gdb (Ubuntu/Linaro 7.4-2012.02-0ubuntu2) 7.4-2012.02
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://bugs.launchpad.net/gdb-linaro/>.
(gdb) attach 2598 (将GDB附加在PID为2598 的进程上)
Attaching to process 2598
Reading symbols from /home/ygm/tmp/eg1...done.
Reading symbols from /lib/x86_64-linux-gnu/libc.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib/x86_64-linux-gnu/libc.so.6
Reading symbols from /lib64/ld-linux-x86-64.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib64/ld-linux-x86-64.so.2
0x00007f305d47fda0 in nanosleep () from /lib/x86_64-linux-gnu/libc.so.6
(gdb) stop (让进程暂停)
(gdb) l
5 diff = no1 - no2;
6 result = no1 / diff;
7 return result;
8 }
9
10 int main()
11 {
12 pid_t pid;
13
14 pid = fork();
(gdb) l
15 if (pid <0) {
16 printf("forkerr/n");
17 exit(-1);
18 } else if (pid == 0) {
19 /* in child process */
20 sleep(60);
21
22 int value = 10;
23 int div = 6;
24 int total = 0;
(gdb) l
25 int i = 0;
26 int result = 0;
27
28 for (i = 0; i < 10; i++) {
29 result =wib(value, div);
30 total += result;
31 div++;
32 value--;
33 }
34
(gdb) b 29
Breakpoint 1 at 0x4006af: file eg1.c, line 29.
(gdb) continue
Continuing.
Breakpoint 1, main () at eg1.c:29
29 result =wib(value, div);
(gdb) step (进入函数中执行下调命令)
wib (no1=10, no2=6) at eg1.c:5
5 diff = no1 - no2;
(gdb) continue
Continuing.
Breakpoint 1, main () at eg1.c:29
29 result =wib(value, div);
(gdb) step
wib (no1=9, no2=7) at eg1.c:5
5 diff = no1 - no2;
(gdb) continue
Continuing.
Breakpoint 1, main () at eg1.c:29
29 result =wib(value, div);
(gdb) step
wib (no1=8, no2=8) at eg1.c:5
5 diff = no1 - no2;
(gdb) next
6 result = no1 / diff;
(gdb) p diff
$1 = 0
(gdb)
- 如何使用gdb调试多进程
- 使用gdb调试多进程
- 如何使用gdb调试多进程 (attach方法)
- 如何使用gdb调试多进程 (attach方法)
- 如何使用gdb调试多进程 (attach方法)
- 如何使用gdb调试多进程 (attach方法)
- 如何使用gdb调试多进程 (attach方法)
- Linux:如何使用gdb调试多进程多线程程序
- gdb调试常用指令及如何使用gdb调试多进程 (attach方法)
- 使用gdb调试多进程多线程调试
- 使用gdb调试进程
- gdb如何调试多线程以及多进程
- 使用 GDB 调试多进程程序
- 使用 GDB 调试多进程程序
- 使用 GDB 调试多进程程序
- 使用 GDB 调试多进程程序
- 使用GDB 调试多进程程序
- 使用 GDB 调试多进程程序
- 排序篇之堆排序
- python的一个html解析器 Beautiful Soup
- Top 10 tough core Java interview questions answers programming
- 网络模型&网络编程&io
- 用MyEclipse和wsdl文件,生成调用wsdl的java代码
- 如何使用gdb调试多进程
- error C2143的原因及解决办法
- C#中金额千分位显示
- 函数作用(持续积累)
- linux的mount(挂载)命令详解
- Java 理论与实践: 正确使用 Volatile 变量
- 首次写博客
- 亲和串 - HDU 2203 KMP
- suffix tree学习