多进程 多线程调试方法 GDB调试 .
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
[root@tivf09 root]# ps -ef|grep -i vnc
root 19609 1 0 Jun05 ?
00:08:46 Xvnc :1 -desktop
tivf09:1 (root)
-httpd /usr/share/vnc/classes -auth /root/.Xauthority
-geometry 1024x768
-depth 16 -rfbwait 30000 -rfbauth /root/.vnc/passwd -rfbport
5901 -pn
root 19627 1 0 Jun05 ?
00:00:00 vncconfig
-iconic
root 12714 10599 0 01:23 pts/0 00:00:00 grep -i vnc
Attach 子进程
众所周知,GDB 有附着(attach)到正在运行的进程的功能,即 attach <pid>命令。因此我们可以利用该命令 attach 到子进程然后进行调试。
例如我们要调试某个进程 RIM_Oracle_Agent.9i,首先得到该进程的 pid
[root@tivf09 tianq]# ps -ef|grep RIM_Oracle_Agent.9i
3、GDB wrapper 方法:专用于 fork+exec 模式,不用添加额外代码, 但需要 X 环境支持(xterm/VNC)这种方式没有使用过,一般对于企业 开发的话是不是很多都没有 x 环境支持的吧(猜测:))
follow-fork-mode 方式比较简单,通过 set follow-fork-mode child | parent 来觉得跟踪 child 还是 parent,然后可以设置断点跟踪了
set follow-fork-mode [程,子进程不受影响。 child: fork 之后调试子进程,父进程不受影响。
因此如果需要调试子进程,在启动 gdb 后:
(gdb) set follow-fork-mode child
Proc2 是 Proc1 的子进程,Proc3 又是 Proc2 的子进程。如何使用 GDB 调试 proc2 或者 proc3 呢? 实际上,GDB 没有对多进程程序调试提供直接支持。例如,使用 GDB 调试某个进程,如果该进程 fork 了子进程,GDB 会继续调试该进程, 子进程会不受干扰地运行下去。如果你事先在子进程代码里设定了断 点,子进程会收到 SIGTRAP 信号并终止。那么该如何调试子进程呢? 其实我们可以利用 GDB 的特点或者其他一些辅助手段来达到目的。此 外,GDB 也在较新内核上加入一些多进程调试支持。
还是上面那个例子,RIM_Oracle_prog fork 出子进程后将紧接着执行 RIM_Oracle_Agent.9i 的二进制代码文件。我们将该文件重命名为 RIM_Oracle_Agent.9i.binary,并新建一个名为 RIM_Oracle_Agent.9i 的 shell 脚本文件,其内容如下:
关于 gdb 调试多进程很早之前就看过,但一直没有总结很深入的学习, 今天又碰到这个问题了,记录下
记得 kk 跟我说过,在开发程序的时候尽量少调试,尽量少使用 gdb 等 调试工具,尽量多的使用 log 等方式来定位错误,这样会大大减少调试 所需的时间和精力,同时也能快速的定位问题。当然,利用 gdb 调试还 是有很多的优势的,比如对于我这个菜鸟来说,可以好好学习下强大的 gdb~ 关于 gdb 的基本调试,基本已经掌握了,经常会使用的一些命令有: s----step n----next c-----continue p----print bt---backtrace b----break 等等
今天查找多进程调试的时候突然注意到 stop 命令,之前一直没有留意, 发现这个命令可以在多进程调试中起到作用
下面描述下多进程的调试
关于 gdb 调试多进程,很经典的一篇文章是 IBM developerworks 上面 的一篇: /developerworks/cn/linux/l-cn-gdbmp/index.html 详细内容见下面描述。
并在子进程代码设置断点。
此外还有 detach-on-fork 参数,指示 GDB 在 fork 之后是否断开(detach) 某个进程的调试,或者都交由 GDB 控制:
set detach-on-fork [on|off]
on: 断开调试 follow-fork-mode 指定的进程。 off: gdb 将控制父进程和子进程。follow-fork-mode 指定的进程
[root@tivf09 root]# pstree -H 6722
通过 pstree 察看进程
启动 GDB,attach 到该进程 用 GDB 连接进程
现在就可以调试了。一个新的问题是,子进程一直在运行,attach 上去 后都不知道运行到哪里了。有没有办法解决呢?
一个办法是,在要调试的子进程初始代码中,比如 main 函数开始处, 加入一段特殊代码,使子进程在某个条件成立时便循环睡眠等待,attach 到进程后在该代码段后设上断点,再把成立的条件取消,使代码可以继 续执行下去。
VNC viewer:输入服务器
输入密码: VNC viewer:输入密码 登录成功,界面和服务器本地桌面上一样:
VNC viewer
下面我们来修改 RIM_Oracle_Agent.9i 脚本,使它看起来像下面这样: #!/bin/sh export DISPLAY=tivf09:1.0; xterm -e gdb RIM_Oracle_Agent.binary 如果你的程序在 exec 的时候还传入了参数,可以改成: #!/bin/sh export DISPLAY=tivf09:1.0; xterm -e gdb --args RIM_Oracle_Agent.binary $@
[root@tivf09 root]#
Vncserver 是一个 Perl 脚本,用来启动 Xvnc(X VNC server)。X client 应用,比如 xterm,VNC viewer 都是和它通信的。如上所示,我们可 以使用的 DISPLAY 值为 tivf09:1。现在就可以从本地机器使用 VNC viewer 连接过去:
New ''tivf09:1 (root)'' desktop is tivf09:1
Starting applications specified in /root/.vnc/xstartup Log file is /root/.vnc/tivf09:1.log
[root@tivf09 root]#
} }
当 attach 到进程后,在该段代码之后设上断点,再把该文件删除就 OK 了。当然你也可以采用其他的条件或形式,只要这个条件可以设置/检 测即可。
Attach 进程方法还是很方便的,它能够应付各种各样复杂的进程系统, 比如孙子/曾孙进程,比如守护进程(daemon process),唯一需要的 就是加入一小段代码。
至于这段代码所采用的条件,看你的偏好了。比如我们可以检查一个指 定的环境变量的值,或者检查一个特定的文件存不存在。以文件为例, 其形式可以如下:
void debug_wait(char *tag_file) {
while(1) {
if (tag_file 存在) 睡眠一段时间;
else break;
attach 方法首先要找到待调试进程的 pid,一般是通过 ps 相关命令,例 如 pstree、ps –aux | grep 进程名称等等,然后通过 attach 关联到相 应的进程。
下面分别是一些介绍文章: GDB 是 linux 系统上常用的 c/c++ 调试工具,功能十分强大。对于较 为复杂的系统,比如多进程系统,如何使用 GDB 调试呢?考虑下面这 个三进程系统: 进程
将被调试,另一个进程置于暂停(suspended)状态。
注意,最好使用 GDB 6.6 或以上版本,如果你使用的是 GDB6.4,就只 有 follow-fork-mode 模式。
follow-fork-mode/detach-on-fork 的使用还是比较简单的,但由于其系 统内核/gdb 版本限制,我们只能在符合要求的系统上才能使用。而且, 由于 follow-fork-mode 的调试必然是从父进程开始的,对于 fork 多次, 以至于出现孙进程或曾孙进程的系统,例如上图 3 进程系统,调试起来 并不方便。
GDB wrapper 很多时候,父进程 fork 出子进程,子进程会紧接着调用 exec 族函数 来执行新的代码。对于这种情况,我们也可以使用 gdb wrapper 方法。 它的优点是不用添加额外代码。
其基本原理是以 gdb 调用待执行代码作为一个新的整体来被 exec 函数 执行,使得待执行代码始终处于 gdb 的控制中,这样我们自然能够调试 该子进程代码。
就会跳出一个终端窗口:
终端
如果你是在一台远程 linux 服务器上调试,那么可以使用 VNC(Virtual Network Computing) viewer 从本地机器连接到服务器上使用 xterm。 在此之前,需要在你的本地机器上安装 VNC viewer,在服务器上安装 并启动 VNC server。大多数 linux 发行版都预装了 vnc-server 软件包, 所以我们可以直接运行 vncserver 命令。注意,第一次运行 vncserver 时会提示输入密码,用作 VNC viewer 从客户端连接时的密码。可以在 VNC server 机器上使用 vncpasswd 命令修改密码。 [root@tivf09 root]# vncserver
nobody 6722 6721 0 05:57 ?
00:00:00
RIM_Oracle_Agent.9i
root
7541 27816 0 06:10 pts/3 00:00:00 grep -i
rim_oracle_agent.9i
通过 pstree 可以看到,这是一个三进程系统,oserv 是 RIM_Oracle_prog 的父进程,RIM_Oracle_prog 又是 RIM_Oracle_Agent.9i 的父进程。
[root@tivf09 bin]# mv RIM_Oracle_Agent.9i RIM_Oracle_Agent.9i.binary [root@tivf09 bin]# cat RIM_Oracle_Agent.9i
#!/bin/sh gdb RIM_Oracle_Agent.binary 当 fork 的子进程执行名为 RIM_Oracle_Agent.9i 的文件时,gdb 会被首 先启动,使得要调试的代码处于 gdb 控制之下。 新的问题来了。子进程是在 gdb 的控制下了,但还是不能调试:如何与 gdb 交互呢?我们必须以某种方式启动 gdb,以便能在某个窗口/终端与 gdb 交互。具体来说,可以使用 xterm 生成这个窗口。 xterm 是 X window 系统下的模拟终端程序。比如我们在 Linux 桌面环 境 GNOME 中敲入 xterm 命令: xterm
IBM developerworks 上的这篇文章介绍了三种 gdb 调试多进程的方法:
1、follow-fork-mode 方法
这是一种比较简单的方式,通过 set follow-fork-mode 的方式来调试父 进程或子进程
2、attach 的方式,这种应该是比较常用的方式,也是很多文章中介绍 的一种方式。这种方式一般需要增加一些代码来实现对进程的 attach
接下来我们详细介绍几种方法,分别是 follow-fork-mode 方法,attach 子进程方法和 GDB wrapper 方法。 follow-fork-mode 在 2.5.60 版 Linux 内核及以后,GDB 对使用 fork/vfork 创建子进程的程 序提供了 follow-fork-mode 选项来支持多进程调试。 follow-fork-mode 的用法为: