GDB调试多进程/线程

GDB调试多进程与多线程

Linux下工作,使用VIM编辑器,调试使用GDB。如同金科玉律一般,但熟练使用得费些力气才行。
VIM编辑器,要熟练各种快捷键,否则,对于新手,简直就是噩梦!
GDB调试器,相比GUI界面,使用起来不那么直观,但功能很强大!
本文以nghttp2的多进程/线程调试为例。
入正题!

1 多进程[process]与多线程[thread]

我们写的比较多的是多线程程序,一个进程下开启了多个线程。而多进程的程序很少涉及到。(线程与进程的区别不赘述!)。多进程的程序一般是服务器程序,比如 nginx , nghttp2 等,在启动的时候,会有一个master进程与一个或者多个worker进程被创建,master进程的任务就是对worker进程进行管理,worker进程主要处理业务。而每个worker进程下可能又会有一个或者多个线程在运行。

2 进程号PID

启动一个程序的时候,一般会有对应的进程号 PID,服务器程序会有master进程与worker进程,因为是worker进程在处理业务,所以,我们需要worker进程的 PID

ps -ef | grep <program>

一般master进程在上,worker进程在下,worker进程号也一般大于master进程号,这与创建顺序有关。

得到进程号,然后就可以启动GDB进行调试了。

3 多进程调试方法

3.1 attach PID

attach是调试进程的最常用办法,只要有可执行程序以及相应PID即可。如果程序运行太快,来不及attach 怎么办?
可以采用延时进入主程序的方法,比如在进程启动后,设定sleep一段时间,如10s的时间来attach。方法1需要sleep,方法2不需要,可以直接在gdb中控制程序运行,直接调试。

attach <PID>

3.2 set follow-fork-mode child

设置GDB
set follow-fork-mode child
gdb将在fork之后直接执行子进程,直到断点处停止。

以nghttpx实例

提供两种方式,一种是先运行多进程程序,一种是使用gdb来带参数运行。
方法1:

  1. 启动,多进程程序。 nghttpx –conf=conf/nghttpx.conf
  2. 查看worker进程PID, ps -ef | grep nghttpx
  3. 启动gdb
  4. attach PID (worker进程)
  5. 设置断点,等等,
  6. 发送请求,开始调试

方法2 :

  1. gdb bin/nghttpx
  2. 设置参数 set args –conf=conf/nghttpx.conf
  3. 设置 set follow-fork-mode child,gdb将在fork之后直接执行子进程 // 不设置,不能调试
  4. 设置断点 ,等等
  5. run
  6. 发送请求,开始调试

4 多线程调试

4.1 GDB多线程调试的基本命令

info threads 显示当前可调试的所有线程,每个线程会有一个GDB为其分配的ID,后面操作线程的时候会用到这个ID。 前面有*的是当前调试的线程。
thread ID 切换当前调试的线程为指定ID的线程。

break thread_test.c:123 thread all 在所有线程中相应的行上设置断点

thread apply ID1 ID2 command 让一个或者多个线程执行GDB命令command。

thread apply all command 让所有被调试线程执行GDB命令command。

set scheduler-locking off|on|step 在使用step或者continue命令调试当前被调试线程的时候,其他线程也是同时执行的,怎么只让被调试程序执行呢?通过这个命令就可以实现这个需求。off不锁定任何线程,也就是所有线程都执行,这是默认值。 on 只有当前被调试程序会执行。 step 在单步的时候,除了next过一个函数的情况(熟悉情况的人可能知道,这其实是一个设置断点然后continue的行为)以外,只有当前线程会执行。

4.2 实例

info threads
  4 Thread 1099119552 (LWP 12940)   0xffffe002 in ?? ()
  3 Thread 1090731072 (LWP 12939)   0xffffe002 in ?? ()
  2 Thread 1082342592 (LWP 12938)   0xffffe002 in ?? ()
* 1 Thread 1073951360 (LWP 12931)   main (argc=1, argv=0xbfffda04) at thread.c:21

用 thread THREADNUMBER 进行切换,THREADNUMBER 为上文提到的线程号1,2,3,4。下例显示将活动线程从 1 切换至 4。

(gdb) info threads
   4 Thread 1099119552 (LWP 12940)   0xffffe002 in ?? ()
   3 Thread 1090731072 (LWP 12939)   0xffffe002 in ?? ()
   2 Thread 1082342592 (LWP 12938)   0xffffe002 in ?? ()
* 1 Thread 1073951360 (LWP 12931)   main (argc=1, argv=0xbfffda04) at thread.c:21
(gdb) thread 4
[Switching to thread 4 (Thread 1099119552 (LWP 12940))]#0   0xffffe002 in ?? ()
(gdb) info threads
* 4 Thread 1099119552 (LWP 12940)   0xffffe002 in ?? ()
   3 Thread 1090731072 (LWP 12939)   0xffffe002 in ?? ()
   2 Thread 1082342592 (LWP 12938)   0xffffe002 in ?? ()
   1 Thread 1073951360 (LWP 12931)   main (argc=1, argv=0xbfffda04) at thread.c:21

后面就是直接在你的线程函数里面设置断点,然后continue到那个断点,一般情况下多线程的时候,由于是同时运行的,最好设置 set scheduler-locking on这样的话,只调试当前线程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值