Gdb调试多进程程序

来源:互联网 发布:手机破解软件 编辑:程序博客网 时间:2024/06/11 10:15

Gdb调试多进程程序

程序经常使用fork/exec创建多进程程序。多进程程序有自己独立的地址空间,这是多进程调试首要注意的地方。Gdb功能强大,对调试多线程提供很多支持。

方法1:调试多进程最土的办法:attach pid

Attach是调试进程的常用办法,只要有可执行程序以及相应PID,即可工作。当然,为方便调试,可以在进程启动后,设定sleep一段时间,如30s,这样即可有充足的时间来attach。

方法2: set follow-fork-mode child + main断点

当设置set follow-fork-mode child,gdb将在fork之后直接执行子进程,知道碰到断点后停止。如何设置子进程的断点呢?在父进程中是无法知道子进程的地址空间的(只有等程序载入后方可知)。Gdb提供一个很方便的机制:main函数的断点将被子进程继承(毕竟main是任何程序的入口)。

注意:程序在main停下后,可尝试设置断点。断点是否有效,取决于gdb是否已经载入目标程序的地址空间。

方法3: set follow-fork-mode child + catch exec

Cache点是一种特殊的breakpoint。Gdb能够catch的事件很多,如throw/catch/exception/syscall/exec/fork/vfork等。其中和多进程关系最大的就是exec/fork事件。

举例:

?
GNU gdb Fedora (6.8-27.el5)
Copyright (C) 2008 Free Software Foundation, Inc.
(gdb) catchexec
Catchpoint 1 (exec)
(gdb) set follow-fork-mode child
(gdb) r  -d ***
Catchpoint 1 (exec'd/****/binary), 0x0000003c68800a70 in _start ()
   from /lib64/ld-linux-x86-64.so.2
(gdb) bt
#0  0x0000003c68800a70 in _start () from /lib64/ld-linux-x86-64.so.2
#1  0x0000000000000003 in ?? ()
#2  0x00007fff65c6e85a in ?? ()
#3  0x00007fff65c6e85d in ?? ()
#4  0x00007fff65c6e860 in ?? ()
(gdb) b lib.cc:8720
No symbol table is loaded.  Use the"file" command.
(gdb) c
Continuing
(gdb) bt
#0  0x0000003c68800a70 in _start () from /lib64/ld-linux-x86-64.so.2
#1  0x0000000000000002 in ?? ()
#2  0x00007fff1af7682a in ?? ()
#3  0x0000000000000000 in ?? ()
(gdb)  b lib.cc:8720
Breakpoint 2 at 0x15f9694: file lib.cc, line 8720.
(gdb) c
Continuing.
[Thread debuggingusing libthread_db enabled]
[Thread 0x40861940 (LWP 12602) exited]
[Switching to process 12630]
0x0000003c6980d81c in vfork () from /lib64/libpthread.so.0
Warning:
Cannot insert breakpoint 2.
Error accessing memory address 0x15f9694: Input/output error.
(gdb) bt
#0  0x0000003c6980d81c in vfork () from /lib64/libpthread.so.0
#1  0x000000000040c3fb in ?? ()
#2  0x00002adeab604000 in ?? ()
#3  0x01000000004051ef in ?? ()
#4  0x00007fffff4a42f0 in ?? ()
#5  0x686365746e6f6972 in ?? ()
#6  0x0000000d0000000c in ?? ()
#7  0x0000000b0000000a in ?? ()
#8  0x0000000000000000 in ?? ()
(gdb) delete2  --此处当breakpoint无效时,必须删除,否则程序无法继续
(gdb) c
Continuing.
[New process 12630]
Executing new program: /****/binary
warning: Cannot initializethread debugging library: generic error
[Switching to process 12630]
  
Catchpoint 1 (exec'd/****/binary), 0x0000003c68800a70 in _start ()
   from /lib64/ld-linux-x86-64.so.2
(gdb) bt
#0  0x0000003c68800a70 in _start () from /lib64/ld-linux-x86-64.so.2
#1  0x0000000000000009 in ?? ()
Backtrace stopped: previous frame inner tothis frame (corrupt stack?)
(gdb) b lib.cc:8720
Breakpoint 4 at 0x15f9694: file lib.cc, line 8720.
(gdb) b type.cc:32
Breakpoint 5 at 0x1693050: file type.cc, line 32.
(gdb) c
Continuing.
(gdb)  -- 和正常程序调试一样

说明:catch exec后,程序将在fork/vfork/exec处停下。并非每次停下后,设置断点都是有效的。如提供断点无效,需要删除,否则程序无法继续。要能够在新进程中设置断点,一定要等到新进程的地址空间被载入后,设置断点是才有效(exec将改变原程序的地址空间)。上述例子,主要想展示如何对新进程设置断点!

注意:1)程序地址非常重要(代码和数据地址一样重要)。使用gdb时,多多注意和利用地址信息。2)On some systems, when a child process is spawned by vfork, you cannot debug the child or parent until an exec call completes.

方法4info inferiors/inferiors inferiors

设置set detach-on-fork off/set follow-exec-mode new

If you choose to set `detach-on-fork' mode off, then gdb will retain control of all forked processes (including nested forks). You can list the forked processes under the control of gdb by using theinfo inferiors command, and switch from one fork to another by using theinferior command.

所使用的gdb不支持set detach-on-fork off/set follow-exec-mode new/info inferiors。不清楚。

 

 

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int glob=6;
char buf[]="a write to stdout\n";
int main()
{
int var;
pid_t pid;
var=88;
if(write(STDOUT_FILENO,buf,sizeof(buf)-1)!=sizeof(buf)-1)
perror("wirte");
printf("before fork\n");
if((pid=fork())<0){
perror("fork");
}else if(pid==0){
printf("child\n");
glob++;
var++;
sleep(10);
}else{
printf("parent\n");
sleep(20);
}
printf("pid=%d,glob=%d,var=%d\n",getpid(),glob,var);
exit(0);
}



kym@ubuntu:~/workspace/gdbthread/Debug$ gdb gdbthread
GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2) 7.4-2012.04
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 "i686-linux-gnu".
For bug reporting instructions, please see:
<http://bugs.launchpad.net/gdb-linaro/>...
Reading symbols from /home/kym/workspace/gdbthread/Debug/gdbthread...done.
(gdb) break 13 //在主进程打断点,被子进程继承
Breakpoint 1 at 0x8048908: file ../main.cpp, line 13.
(gdb) set follow-fork-mode child //设置为执行子进程
(gdb) run
Starting program: /home/kym/workspace/gdbthread/Debug/gdbthread 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/i386-linux-gnu/libthread_db.so.1".
a write to stdout

Breakpoint 1, main () at ../main.cpp:13
13 printf("before fork\n");
(gdb) break 19 //在子进程上打断点
Breakpoint 2 at 0x8048956: file ../main.cpp, line 19.
(gdb) c
Continuing.
before fork
[New process 4166]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/i386-linux-gnu/libthread_db.so.1".
parent
child
[Switching to Thread 0xb7fe9700 (LWP 4166)]

Breakpoint 2, main () at ../main.cpp:19
19 var++;
(gdb) c
Continuing.
pid=4166,glob=7,var=89
[Inferior 2 (process 4166) exited normally]
(gdb) pid=4163,glob=6,var=88


在学习Nginx源码的过程中

    碰到一个问题

    使用GDB调试Nginx的时候

    每次在Nginx主程序启动master之后

    主进程就被deattache了.然后整个GDB退出

    这样我们就没法看到最主要的事情的经过了.

    因为主要的进程管理,事件处理等等事情,

    都是发生在fork出来的master以及再后面的worker进程中的

    好在IBM developer works上一直有绝好的文章

    这篇使用 GDB 调试多进程程序就是专门讲述GDB调试多进程程序的三个方法的

    1.使用follow-fork-mode和set detach-on-fork连用来自动跳入fork后的进程中

    这个方法在新版本的内核中都可以使用.

    在gdb中使用者两个指令

    set follow-fork-mode [parent|child]

    parent: fork之后继续调试父进程,子进程不受影响。

    child: fork之后调试子进程,父进程不受影响。

    set detach-on-fork [on|off]

    on: 断开调试follow-fork-mode指定的进程。

    off: gdb将控制父进程和子进程。follow-fork-mode指定的进程将被调试,另一个进程置于暂停(suspended)状态。

    一般是进gdb之后

    set follow-fork-mode child

    set detach-on-fork off

    这样就可以满足调试子进程的要求了

    2.先在环境中使用ps以及pstree确定需要调试子进程的pid

    然后在gdb中使用attach [pid]来进入需要调试的子进程

    这个方法需要解决进入子进程的时候无法确定运行到什么程度的问题

    需要修改子进程的源码,在开始设置个标志位或者标志文件,

    gdb调试之后修改此标志位让子进程执行起来

    3.在主程序调用子程序的地方替换成sh,sh里面用gdb去调用子进程的可执行程序

    这个方法超麻烦,需要xwindow,而且只能在用exec启用子进程的程序使用

    所以此方法虽然可行,但是制约太多.不推荐.

 

 

GDB的功能很强大,本文主要介绍用GDB来调试信号、多进程、多线程,具体如下:

(一)信号

GDB有能力在你调试程序的时候处理任何一种信号,你可以告诉GDB需要处理哪一种信号。你可以要求GDB收到你所指定的信号时,马上停住正在运行的程序,以供你进行调试。你可以用GDB的handle命令来完成这一功能。

    handle <signal> <keywords...>
        在GDB中定义一个信号处理。信号<signal>可以以SIG开头或不以SIG开头,可以用定义一个要处理信号的范围(如:SIGIO- SIGKILL,表示处理从SIGIO信号到SIGKILL的信号,其中包括SIGIO, SIGIOT,SIGKILL三个信号),也可以使用关键字 all来标明要处理所有的信号。一旦被调试的程序接收到信号,运行程序马上会被GDB停住,以供调试。其<keywords>可以是以下几种关键字的一个或多个。

        nostop
            当被调试的程序收到信号时,GDB不会停住程序的运行,但会打出消息告诉你收到这种信号。
        stop
            当被调试的程序收到信号时,GDB会停住你的程序。
        print
            当被调试的程序收到信号时,GDB会显示出一条信息。
        noprint
            当被调试的程序收到信号时,GDB不会告诉你收到信号的信息。
        pass
        noignore
            当被调试的程序收到信号时,GDB不处理信号。这表示,GDB会把这个信号交给被调试程序会处理。
        nopass
        ignore
            当被调试的程序收到信号时,GDB不会让被调试程序来处理这个信号。

    info signals
    info handle
    查看有哪些信号在被GDB检测中。

(二)线程

如果你程序是多线程的话,你可以定义你的断点是否在所有的线程上,或是在某个特定的线程。GDB很容易帮你完成这一工作。

    break <linespec> thread <threadno>
    break <linespec> thread <threadno> if ...
        linespec指定了断点设置在的源程序的行号。threadno指定了线程的ID,注意,这个ID是GDB分配的,你可以通过“info threads”命令来查看正在运行程序中的线程信息。如果你不指定
thread <threadno>则表示你的断点设在所有线程上面。你还可以为某线程指定断点条件。如:

        (gdb) break frik.c:13 thread 28 if bartab > lim

    当你的程序被GDB停住时,所有的运行线程都会被停住。这方便你你查看运行程序的总体情况。而在你恢复程序运行时,所有的线程也会被恢复运行。那怕是主进程在被单步调试时。

线程有自己的寄存器,运行时堆栈或许还会有私有内存。  
gdb提供了以下供调试多线程的进程的功能:  
*   自动通告新线程。  
*   \ "thread   THREADNO\ ",一个用来在线程之间切换的命令。  
*   \ "info   threads\ ",一个用来查询现存线程的命令。  
*   \ "thread   apply   [THREADNO]   [ALL]   ARGS\ ",一个用来向线程提供命令的命令。  
*   线程有关的断点设置。  
注意:这些特性不是在所有gdb版本都能使用,归根结底要看操作系统是否支持。  
如果你的gdb不支持这些命令,会显示出错信息:  
(gdb)   info   threads  
(gdb)   thread   1  
Thread   ID   1   not   known.   Use   the   \ "info   threads\ "   command   to  
see   the   IDs   of   currently   known   threads.  
gdb的线程级调试功能允许你观察你程序运行中所有的线程,但无论什么时候  
gdb控制,总有一个“当前”线程。调试命令对“当前”进程起作用。  
一旦gdb发现了你程序中的一个新的线程,它会自动显示有关此线程的系统信  
息。比如:  
[New   process   35   thread   27]  
不过格式和操作系统有关。  
为了调试的目的,gdb自己设置线程号。  
`info   threads\ "  
显示进程中所有的线程的概要信息。gdb按顺序显示:  
1.线程号(gdb设置)  
2.目标系统的线程标识。  
3.此线程的当前堆栈。  
一前面打\ "*\ "的线程表示是当前线程。  
例如:  
(gdb)   info   threads  
3   process   35   thread   27   0x34e5   in   sigpause   ()  
2   process   35   thread   23   0x34e5   in   sigpause   ()  
*   1   process   35   thread   13   main   (argc=1,   argv=0x7ffffff8)  
at   threadtest.c:68  
`thread   THREADNO\ "  
把线程号为THREADNO的线程设为当前线程。命令行参数THREADNO是gdb内定的  
线程号。你可以用\ "info   threads\ "命令来查看gdb内设置的线程号。gdb显示该线程  
的系统定义的标识号和线程对应的堆栈。比如:  

(gdb)   thread   2  
[Switching   to   process   35   thread   23]  
0x34e5   in   sigpause   ()  
\ "Switching后的内容取决于你的操作系统对线程标识的定义。  

`thread   apply   [THREADNO]   [ALL]   ARGS\ "  
此命令让你对一个以上的线程发出相同的命令\ "ARGS\ ",[THREADNO]的含义同上。  
如果你要向你进程中的所有的线程发出命令使用[ALL]选项。  
无论gdb何时中断了你的程序(因为一个断点或是一个信号),它自动选择信号或  
断点发生的线程为当前线程。gdb将用一个格式为\ "[Switching   to   SYSTAG]\ "的消息  
来向你报告。  

 

(三)进程

1. 用的是attach子进程的方法
attach到正在运行的进程的功能,即attach <pid>命令。因此我们可以利用该命令attach到子进程然后进行调试。

一般的步骤是  1.首先要在要调试的子进程初始代码中,加入一段特殊代码,使子进程睡眠等待,然后运行待调试的程序
2.用ps -ef |grep 查看产生的子进程pid
3. 然后gdb启动,attach <pid>到进程后在该代码段后设上断点,就可以调试了

eg.

        pid = fork();
if (pid <0) {
printf("fork err\n");
exit(-1);
} else if (pid == 0) {
/* in child */
sleep(60); ------------------ (!)

int     value   = 10;

**********
} /**in parent****/

执行程序(比如说是 examp)
examp &   --- 让examp后台运行吧。(不后台运行也可以);

查找进程id:
ps -ef

运行gdb:
gdb
(gdb) attach xxxxx  --- xxxxx为利用ps命令获得的子进程 id
(gdb) stop --- 这点很重要,你需要先暂停那个子进程,然后设置一些断点和一些Watch
(gdb) break xx
Breakpoint 1 at 0x10808: file eg1.c, line 37.
(gdb) c
Continuing.

2. 使用follow-fork-mode 的方法调试多进程
最好使用GDB 6.6或以上版本

使用follow-fork-mode 的方法调试多进程时的一般步骤是:
1.启动gdb
2设置set follow-fork-mode [child/parent] 想调试child就使用child参数,如调试parent则使用parent
3启动程序文件 file ./hello ----------当然路径名自己要搞对哦
4.break num -----------如调试子进程则num是子进程代码的行数,
还有个小技巧就是break fork也就是在fork函数处设置断点

 

GDB 是 linux 系统上常用的 c/c++ 调试工具,功能十分强大。对于较为复杂的系统,比如多进程系统,如何使用 GDB 调试呢?考虑下面这个三进程系统:



进程 

Proc2 是 Proc1 的子进程,Proc3 又是 Proc2 的子进程。如何使用 GDB 调试 proc2 或者 proc3 呢?

实际上,GDB 没有对多进程程序调试提供直接支持。例如,使用GDB调试某个进程,如果该进程fork了子进程,GDB会继续调试该进程,子进程会不受干扰地运行下去。如果你事先在子进程代码里设定了断点,子进程会收到SIGTRAP信号并终止。那么该如何调试子进程呢?其实我们可以利用GDB的特点或者其他一些辅助手段来达到目的。此外,GDB 也在较新内核上加入一些多进程调试支持。

接下来我们详细介绍几种方法,分别是 follow-fork-mode 方法,attach 子进程方法和 GDB wrapper 方法。

在2.5.60版Linux内核及以后,GDB对使用fork/vfork创建子进程的程序提供了follow-fork-mode选项来支持多进程调试。

follow-fork-mode的用法为:

set follow-fork-mode [parent|child]

  • parent: fork之后继续调试父进程,子进程不受影响。
  • child: fork之后调试子进程,父进程不受影响。

因此如果需要调试子进程,在启动gdb后:

(gdb) set follow-fork-mode child

 

并在子进程代码设置断点。

此外还有detach-on-fork参数,指示GDB在fork之后是否断开(detach)某个进程的调试,或者都交由GDB控制:

set detach-on-fork [on|off]

  • on: 断开调试follow-fork-mode指定的进程。
  • off: gdb将控制父进程和子进程。follow-fork-mode指定的进程将被调试,另一个进程置于暂停(suspended)状态。

注意,最好使用GDB 6.6或以上版本,如果你使用的是GDB6.4,就只有follow-fork-mode模式。

follow-fork-mode/detach-on-fork的使用还是比较简单的,但由于其系统内核/gdb版本限制,我们只能在符合要求的系统上才能使用。而且,由于follow-fork-mode的调试必然是从父进程开始的,对于fork多次,以至于出现孙进程或曾孙进程的系统,例如上图3进程系统,调试起来并不方便。

众所周知,GDB有附着(attach)到正在运行的进程的功能,即attach <pid>命令。因此我们可以利用该命令attach到子进程然后进行调试。

例如我们要调试某个进程RIM_Oracle_Agent.9i,首先得到该进程的pid

[root@tivf09 tianq]# ps -ef|grep RIM_Oracle_Agent.9inobody    6722  6721  0 05:57 ?        00:00:00 RIM_Oracle_Agent.9iroot      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 root]# pstree -H 6722




通过 pstree 察看进程 

启动GDB,attach到该进程



用 GDB 连接进程 

现在就可以调试了。一个新的问题是,子进程一直在运行,attach上去后都不知道运行到哪里了。有没有办法解决呢?

一个办法是,在要调试的子进程初始代码中,比如main函数开始处,加入一段特殊代码,使子进程在某个条件成立时便循环睡眠等待,attach到进程后在该代码段后设上断点,再把成立的条件取消,使代码可以继续执行下去。

至于这段代码所采用的条件,看你的偏好了。比如我们可以检查一个指定的环境变量的值,或者检查一个特定的文件存不存在。以文件为例,其形式可以如下:

void debug_wait(char *tag_file){    while(1)    {        if (tag_file存在)            睡眠一段时间;        else            break;    }}

 

当attach到进程后,在该段代码之后设上断点,再把该文件删除就OK了。当然你也可以采用其他的条件或形式,只要这个条件可以设置/检测即可。

Attach进程方法还是很方便的,它能够应付各种各样复杂的进程系统,比如孙子/曾孙进程,比如守护进程(daemon process),唯一需要的就是加入一小段代码。

很多时候,父进程 fork 出子进程,子进程会紧接着调用 exec族函数来执行新的代码。对于这种情况,我们也可以使用gdb wrapper 方法。它的优点是不用添加额外代码。

其基本原理是以gdb调用待执行代码作为一个新的整体来被exec函数执行,使得待执行代码始终处于gdb的控制中,这样我们自然能够调试该子进程代码。

还是上面那个例子,RIM_Oracle_prog fork出子进程后将紧接着执行RIM_Oracle_Agent.9i的二进制代码文件。我们将该文件重命名为RIM_Oracle_Agent.9i.binary,并新建一个名为RIM_Oracle_Agent.9i的shell脚本文件,其内容如下:

[root@tivf09 bin]# mv RIM_Oracle_Agent.9i RIM_Oracle_Agent.9i.binary[root@tivf09 bin]# cat RIM_Oracle_Agent.9i#!/bin/shgdb RIM_Oracle_Agent.binary

 

当fork的子进程执行名为RIM_Oracle_Agent.9i的文件时,gdb会被首先启动,使得要调试的代码处于gdb控制之下。

新的问题来了。子进程是在gdb的控制下了,但还是不能调试:如何与gdb交互呢?我们必须以某种方式启动gdb,以便能在某个窗口/终端与gdb交互。具体来说,可以使用xterm生成这个窗口。

xterm是X window系统下的模拟终端程序。比如我们在Linux桌面环境GNOME中敲入xterm命令:



xterm 

就会跳出一个终端窗口:



终端 

如果你是在一台远程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 New 'tivf09:1 (root)' desktop is tivf09:1Starting applications specified in /root/.vnc/xstartupLog file is /root/.vnc/tivf09:1.log[root@tivf09 root]#[root@tivf09 root]# ps -ef|grep -i vncroot     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 -pnroot     19627     1  0 Jun05 ?        00:00:00 vncconfig -iconicroot     12714 10599  0 01:23 pts/0    00:00:00 grep -i vnc[root@tivf09 root]#

 

Vncserver是一个Perl脚本,用来启动Xvnc(X VNC server)。X client应用,比如xterm,VNC viewer都是和它通信的。如上所示,我们可以使用的DISPLAY值为tivf09:1。现在就可以从本地机器使用VNC viewer连接过去:



VNC viewer:输入服务器 

输入密码:



VNC viewer:输入密码 

登录成功,界面和服务器本地桌面上一样:



VNC viewer 

下面我们来修改RIM_Oracle_Agent.9i脚本,使它看起来像下面这样:

#!/bin/shexport DISPLAY=tivf09:1.0; xterm -e gdb RIM_Oracle_Agent.binary

 

如果你的程序在exec的时候还传入了参数,可以改成:

#!/bin/shexport DISPLAY=tivf09:1.0; xterm -e gdb --args RIM_Oracle_Agent.binary $@ 

 

最后加上执行权限

[root@tivf09 bin]# chmod 755 RIM_Oracle_Agent.9i

 

现在就可以调试了。运行启动子进程的程序:

[root@tivf09 root]# wrimtest -l 9i_linuxResource Type  : RIMResource Label : 9i_linuxHost Name      : tivf09User Name      : mdstatusVendor         : OracleDatabase       : rimDatabase Home  : /data/oracle9i/920Server ID      : rimInstance Home  : Instance Name  : Opening Regular Session...

 

程序停住了。从VNC viewer中可以看到,一个新的gdb xterm窗口在服务器端打开了



gdb xterm窗口 

 

[root@tivf09 root]# ps -ef|grep gdbnobody   24312 24311  0 04:30 ?        00:00:00 xterm -e gdb RIM_Oracle_Agent.binarynobody   24314 24312  0 04:30 pts/2    00:00:00 gdb RIM_Oracle_Agent.binaryroot     24326 10599  0 04:30 pts/0    00:00:00 grep gdb

 

运行的正是要调试的程序。设置好断点,开始调试吧!

注意,下面的错误一般是权限的问题,使用 xhost 命令来修改权限:



xterm 错误 

 

[root@tivf09 bin]# export DISPLAY=tivf09:1.0[root@tivf09 bin]# xhost +access control disabled, clients can connect from any host

 

xhost + 禁止了访问控制,从任何机器都可以连接过来。考虑到安全问题,你也可以使用xhost + <你的机器名>。

上述三种方法各有特点和优劣,因此适应于不同的场合和环境:

  • follow-fork-mode方法:方便易用,对系统内核和GDB版本有限制,适合于较为简单的多进程系统
  • attach子进程方法:灵活强大,但需要添加额外代码,适合于各种复杂情况,特别是守护进程
  • GDB wrapper方法:专用于fork+exec模式,不用添加额外代码,但需要X环境支持(xterm/VNC)。

 

0 0
原创粉丝点击