得到进程id_GDB调试多进程程序
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 所示的几个命令。
命令语法格式 | 功 能 |
---|---|
(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调试多进程程序相关推荐
- 使用 GDB 调试多进程程序
使用 GDB 调试多进程程序 来源 https://www.ibm.com/developerworks/cn/linux/l-cn-gdbmp/index.html GDB 是 linux 系统上常 ...
- gdb调试多进程程序
1.gdb下调试多进程程序只需要以下几条命令即可 除此之外还可以查看正在调试的进程 info inferiors, 同时也可以将当前正在调试的进程切换到另外一个进程中 ...
- 使用gdb调试多进程程序、同时调试父进程和子进程
参考: [1] GDB debugging multi-process programs [2] Debugging programs with multiple processes 根据这两篇参考链 ...
- 【转】gdb调试多进程程序
GDB 是 linux 系统上常用的 c/c++ 调试工具,功能十分强大.对于较为复杂的系统,比如多进程系统,如何使用 GDB 调试呢?考虑下面这个三进程系统: 进程 Proc2 是 Proc1 的子 ...
- GDB调试多进程程序或同时调试多个程序
转自:http://hellogcc.blogbus.com/logs/71170939.html 在以前,如果在GDB中想调试多进程的程序,需要在fork以前"set follow-for ...
- GDB调试多进程|多线程程序
1. 默认设置下,在调试多进程程序时GDB只会调试主进程.但是GDB(>V7.0)支持多进程的分别以及同时调试,换句话说,GDB可以同时调试多个程序.只需要设置follow-fork-mode( ...
- gdb调试多进程和多线程命令 .
1. 默认设置下,在调试多进程程序时GDB只会调试主进程.但是GDB(>V7.0)支持多进程的 分别以及同时 调试,换句话说,GDB可以同时调试多个程序.只需要设置follow-fork-mod ...
- GDB 调试多进程或者多线程应用
GDB 是 linux 系统上常用的 c/c++ 调试工具, 功能十分强大. 对于较为复杂的系统, 比如多进程系统, 如何使用 GDB 调试呢? 考虑下面这个三进程系统 : 进程 ProcessChi ...
- 使用gdb调试多进程和多线程
GDB调试多进程 1. 默认设置下,在调试多进程程序时GDB只会调试主进程.但是GDB(>V7.0)支持多进程的分别以及同时调试,换句话说,GDB可以同时调试多个程序.只需要设置follow-f ...
最新文章
- 考察大新和南宁农业产业园 农业大健康·李喜贵:赋能乡村振兴
- Centos 利用yum源安装 nginx 1.20.1
- 解决:java.io.IOException: invalid constant type: 15
- 结合MSDN理解windows service 服务安装的三个类。
- python process返回值_如何恢复传递给multiprocessing.Process的函数的返回值?
- python编写排列组合,密码生产功能
- c语言中通过指针将数值赋值到制定内存地址
- CCF201509-3 模板生成系统(100分)
- 【重点!DP】LeetCode 97. Interleaving String
- 大数据分析的特点有哪些
- java题库app有什么,Java面试题库
- bullmind在线流程图软件,在线visio软件
- idea 下查看项目代码量、行数
- 管家婆 打开经营历程 Date exceeds maximum of 19-12-31报错解决
- HDOJ-----5773The All-purpose Zero(LIS)
- RecyclerView 报Scrapped or attached views may not be recycled. as Scrap:false isAttached:true异常
- SPSS免费安装教程(详细版)
- python英文词频统计-Python实现统计英文文章词频的方法分析
- chrome浏览器安装redux-devtools调试工具
- IDEA :插入代码模板(Ctrl+J )
热门文章
- 设备像素比devicePixelRatio简单介绍
- nyoj35 表达式求值
- Restore系统极速还原软件的使用与说明
- 一个完整的嵌入式程序_嵌入式入门-从STM32CudeMX、FreeRtos、Proteu仿真开始
- java转动的风扇课程设计,课程设计—智能风扇设计报告
- 面试官的几句话,差点让我挂在HTTPS上
- 日志的log中如何输出变量_如何在kubernetes中优雅的输出日志
- php文本框长度限制,php截取富文本框中的固定长度的字符
- wxpython有没有可视化设计_python图形化界面设计(wxpython)三树控件(wx.TreeCtrl)
- 在训练期间保存检查点