GDB调试器不只可以调试多线程程序,还可以调试多进程程序。对于 C 和 C++ 程序而言,多进程的实现往往借助的是头文件中的 fork() 函数或者 vfork() 函数。举个例子:

#include #include int main(){    pid_t pid = fork();    if(pid == 0)    {        printf("this is child,pid = %d\n",getpid());    }    else    {        printf("this is parent,pid = %d\n",getpid());    }    return 0;}

程序的存储路径为~/demo/myfork.c。可以看到,程序中包含 2 个进程,分别为父进程(又称主进程)和使用 fork() 函数分离出的子进程。

事实上在多数 Linux 发行版系统中,GDB 并没有对多进程程序提供友好的调试功能。无论程序中调用了多少次 fork() 函数(或者 vfork() 函数),从父进程中分离出多少个子进程,GDB 默认只调试父进程,而不调试子进程。那么问题就出现了,如何使用 GDB 调试多进程程序中的子进程呢?

GDB attach命令调试进程

首先,无论父进程还是子进程,都可以借助 attach 命令启动 GDB 调试它。attach 命令用于调试正在运行的进程,要知道对于每个运行的进程,操作系统都会为其配备一个独一无二的 ID 号。在得知目标子进程 ID 号的前提下,就可以借助 attach 命令来启动 GDB 对其进行调试。这里还需要解决一个问题,很多场景中子进程的执行时间都是一瞬而逝的,这意味着,我们可能还未查到它的进程 ID 号,该进程就已经执行完了,何谈借助 attach 命令对其调试呢?对于 C、C++ 多进程程序,解决该问题最简单直接的方法是,在目标进程所执行代码的开头位置,添加一段延时执行的代码。例如,将上面程序中if(pid==0)判断语句整体做如下修改:

if(pid == 0){    int num =10;    while(num==10){        sleep(10);    }    printf("this is child,pid = %d\n",getpid());}

可以看到,通过添加第 3~6 行代码,该进程执行时会直接进入死循环。这样做的好处有 2 个,其一是帮助 attach 命令成功捕捉到要调试的进程;其二是使用 GDB 调试该进程时,进程中真正的代码部分尚未得到执行,使得我们可以从头开始对进程中的代码进行调试。

有读者可能会问,进程都已经进行死循环了,后续代码还可以进行调试吗?当然可以,以上面示例中给出的死循环,我们只需用 print 命令临时修改 num 变量的值,即可使程序跳出循环,从而执行后续代码。

就以调试修改后的 myfork.c 程序(已将其编译为 myfork.exe 可执行文件)为例:

[root@bogon demo]# gdb myfork.exe -qReading symbols from ~/demo/myfork.exe...done.(gdb) rStarting program: ~/demo/myfork.exeDetaching after fork from child process 5316.  5316this is parent,pid = 5313               Program exited normally.(gdb) attach 5316                          5316 的子进程......(gdb) n                                           Single stepping until exit from function __nanosleep_nocancel,which has no line number information.0x00000037ee2acb50 in sleep () from /lib64/libc.so.6(gdb) nSingle stepping until exit from function sleep,which has no line number information.main () at myfork.c:1010  while(num==10){(gdb) p num=1$1 = 1(gdb) n                                           13         printf("this is child,pid = %d\n",getpid());(gdb) cContinuing.this is child,pid = 5316Program exited normally.(gdb)

对于子进程 ID 号的获取,除了依靠 GDB 调试器打印出的信息,也可以使用 pidof 命令手动获取。有关 pidof 命令获取进程 ID 好的具体用法,我已经在《调用GDB的几种方式》一节中做了详细的讲解,这里不再重复赘述。

GDB显式指定要调试的进程

前面提到,GDB 调试多进程程序时默认只调试父进程。对于内核版本为 2.5.46 甚至更高的 Linux 发行版系统来说,可以通过修改 follow-fork-mode 或者 detach-on-fork 选项的值来调整这一默认设置。

GDB follow-fork-mode选项

确切地说,对于使用 fork() 或者 vfork() 函数构建的多进程程序,借助 follow-fork-mode 选项可以设定 GDB 调试父进程还是子进程。该选项的使用语法格式为:

(gdb) set follow-fork-mode mode

参数 mode 的可选值有 2 个:

  • parent:选项的默认值,表示 GDB 调试器默认只调试父进程;

  • child:和 parent 完全相反,它使的 GDB 只调试子进程。且当程序中包含多个子进程时,我们可以逐一对它们进行调试。

举个例子:

(gdb) show follow-fork-modeDebugger response to a program call of fork or vfork is "parent".(gdb) set follow-fork-mode child                        <-- 调试子进程(gdb) r Starting program: ~/demo/myfork.exe[New process 5376]this is parent,pid = 5375                  <-- 父进程执行完成Program received signal SIGTSTP, Stopped (user).[Switching to process 5376]             <-- 自动进入子进程0x00000037ee2accc0 in __nanosleep_nocancel () from /lib64/libc.so.6(gdb) nSingle stepping until exit from function __nanosleep_nocancel,which has no line number information.0x00000037ee2acb50 in sleep () from /lib64/libc.so.6(gdb) nSingle stepping until exit from function sleep,which has no line number information.main () at myfork.c:1010  while(num==10){(gdb) p num=1$2 = 1(gdb) cContinuing.this is child,pid = 5376

通过执行如下命令,我们可以轻松了解到当前调试环境中 follow-fork-mode 选项的值:

(gdb) show follow-fork-mode
Debugger response to a program call of fork or vfork is "child".

GDB detach-on-fork选项

注意,借助 follow-fork-mode 选项,我们只能选择调试子进程还是父进程,且一经选定,调试过程中将无法改变。如果既想调试父进程,又想随时切换并调试某个子进程,就需要借助 detach-on-fork 选项。detach-on-fork 选项的语法格式如下:

(gdb) set detach-on-fork mode

其中,mode 参数的可选值有 2 个:

  • on:默认值,表明 GDB 只调试一个进程,可以是父进程,或者某个子进程;

  • off:程序中出现的每个进程都会被 GDB 记录,我们可以随时切换到任意一个进程进行调试。

和 detach-on-fork 搭配使用的,还有如表 1 所示的几个命令。

表 1 GDB多进程调试常用命令
命令语法格式 功 能
(gdb)show detach-on-fork 查看当前调试环境中 detach-on-fork 选项的值。
(gdb) info inferiors 查看当前调试环境中有多少个进程。其中,进程 id 号前带有 * 号的为当前正在调试的进程。
(gdb) inferiors id 切换到指定 ID 编号的进程对其进行调试。
(gdb) detach inferior id 断开 GDB 与指定 id 编号进程之间的联系,使该进程可以独立运行。不过,该进程仍存在 info inferiors 打印的列表中,其 Describution 列为 ,并且借助 run 仍可以重新启用。
(gdb) kill inferior id 断开 GDB 与指定 id 编号进程之间的联系,并中断该进程的执行。不过,该进程仍存在 info inferiors 打印的列表中,其 Describution 列为 ,并且借助 run 仍可以重新启用。
remove-inferior id 彻底删除指令 id 编号的进程(从 info inferiors 打印的列表中消除),不过在执行此操作之前,需先使用 detach inferior id 或者 kill inferior id 命令将该进程与 GDB 分离,同时确认其不是当前进程。

除表 1 罗列的这几个命令,GDB 调试其提供有其它的一些命令,由于不常用,这里不再罗列,读者可前往 GDB官网自行查看。

这里仍以调试 myfork.c 程序为例,不过为了让读者清楚地感受 detach-on-fork 选项的功能,这里需要对 else 语句块的代码进行如下修改:

else

{

int mnum=5;

while(mnum==5){

sleep(1);

}

printf("this is parent,pid = %d\n",getpid());

}

也就是说,myfork.c 程序中,父进程和子进程中各拥有一个死循环。

在此基础上,进行如下调试:

(gdb) set detach-on-fork off             (gdb) b 6Breakpoint 1 at 0x11b5: file myfork.c, line 6.(gdb) rStarting program: ~/demo/myfork.exeBreakpoint 1, main () at myfork.c:66     pid_t pid = fork();(gdb) n[New inferior 2 (process 5163)]           Reading symbols from ~/demo/myfork.exe...Reading symbols from /usr/lib/debug/lib/x86_64-linux-gnu/libc-2.31.so...7     if(pid == 0)(gdb) n                                                17     int mnum=5;(gdb) info inferiors       Num  Description       Executable       * 1    process 5159      ~/demo/myfork.exe  2    process 5163       ~/demo/myfork.exe(gdb) inferior 2                                   [Switching to inferior 2 [process 5163] (~/demo/myfork.exe)][Switching to thread 2.1 (process 5163)](gdb) n53 in ../sysdeps/unix/sysv/linux/arch-fork.h(gdb) n__libc_fork () at ../sysdeps/nptl/fork.c:7878 ../sysdeps/nptl/fork.c: No such file or directory.(gdb) n......                                                       (gdb) nmain () at myfork.c:7                           7     if(pid == 0)(gdb) n9         int num =10;(gdb)

可以看到,通过设置 detach-on-fork 选项值为 off,再配合使用 info inferiors 等命令,即可随意切换到当前环境中的各个进程,并对它们进行调试。

感兴趣的读者,可自行以默认模式(即 detach-on-fork 值为 on)调试该程序,对比它们之间的区别。

得到进程id_GDB调试多进程程序相关推荐

  1. 使用 GDB 调试多进程程序

    使用 GDB 调试多进程程序 来源 https://www.ibm.com/developerworks/cn/linux/l-cn-gdbmp/index.html GDB 是 linux 系统上常 ...

  2. gdb调试多进程程序

        1.gdb下调试多进程程序只需要以下几条命令即可              除此之外还可以查看正在调试的进程 info inferiors, 同时也可以将当前正在调试的进程切换到另外一个进程中 ...

  3. 使用gdb调试多进程程序、同时调试父进程和子进程

    参考: [1] GDB debugging multi-process programs [2] Debugging programs with multiple processes 根据这两篇参考链 ...

  4. 【转】gdb调试多进程程序

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

  5. GDB调试多进程程序或同时调试多个程序

    转自:http://hellogcc.blogbus.com/logs/71170939.html 在以前,如果在GDB中想调试多进程的程序,需要在fork以前"set follow-for ...

  6. GDB调试多进程|多线程程序

    1. 默认设置下,在调试多进程程序时GDB只会调试主进程.但是GDB(>V7.0)支持多进程的分别以及同时调试,换句话说,GDB可以同时调试多个程序.只需要设置follow-fork-mode( ...

  7. gdb调试多进程和多线程命令 .

    1. 默认设置下,在调试多进程程序时GDB只会调试主进程.但是GDB(>V7.0)支持多进程的 分别以及同时 调试,换句话说,GDB可以同时调试多个程序.只需要设置follow-fork-mod ...

  8. GDB 调试多进程或者多线程应用

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

  9. 使用gdb调试多进程和多线程

    GDB调试多进程 1. 默认设置下,在调试多进程程序时GDB只会调试主进程.但是GDB(>V7.0)支持多进程的分别以及同时调试,换句话说,GDB可以同时调试多个程序.只需要设置follow-f ...

最新文章

  1. 考察大新和南宁农业产业园 农业大健康·李喜贵:赋能乡村振兴
  2. Centos 利用yum源安装 nginx 1.20.1
  3. 解决:java.io.IOException: invalid constant type: 15
  4. 结合MSDN理解windows service 服务安装的三个类。
  5. python process返回值_如何恢复传递给multiprocessing.Process的函数的返回值?
  6. python编写排列组合,密码生产功能
  7. c语言中通过指针将数值赋值到制定内存地址
  8. CCF201509-3 模板生成系统(100分)
  9. 【重点!DP】LeetCode 97. Interleaving String
  10. 大数据分析的特点有哪些
  11. java题库app有什么,Java面试题库
  12. bullmind在线流程图软件,在线visio软件
  13. idea 下查看项目代码量、行数
  14. 管家婆 打开经营历程 Date exceeds maximum of 19-12-31报错解决
  15. HDOJ-----5773The All-purpose Zero(LIS)
  16. RecyclerView 报Scrapped or attached views may not be recycled. as Scrap:false isAttached:true异常
  17. SPSS免费安装教程(详细版)
  18. python英文词频统计-Python实现统计英文文章词频的方法分析
  19. chrome浏览器安装redux-devtools调试工具
  20. IDEA :插入代码模板(Ctrl+J )

热门文章

  1. 设备像素比devicePixelRatio简单介绍
  2. nyoj35 表达式求值
  3. Restore系统极速还原软件的使用与说明
  4. 一个完整的嵌入式程序_嵌入式入门-从STM32CudeMX、FreeRtos、Proteu仿真开始
  5. java转动的风扇课程设计,课程设计—智能风扇设计报告
  6. 面试官的几句话,差点让我挂在HTTPS上
  7. 日志的log中如何输出变量_如何在kubernetes中优雅的输出日志
  8. php文本框长度限制,php截取富文本框中的固定长度的字符
  9. wxpython有没有可视化设计_python图形化界面设计(wxpython)三树控件(wx.TreeCtrl)
  10. 在训练期间保存检查点