gdb调试多线程多进程

多进程调试

我们使用gdb调试程序,gdb的调试默认是调试父进程的,如果要做到对父进程和子进程都做到调试,所以附加了调试子进程的功能。

1. 设置条件

如果让gdb可以同时调试多个程序,只需要设置follow-fork-mode(默认:parent)和detach-on-fork(默认:on)就好了。

follow-fork-mode detach-on-fork 操作
parent on 只调试主进程
child on 只调试子进程
parent off 同时调试两个进程,gdb跟进父进程,子进程block在fork处
child off 同时调试两个进程,gdb跟进子进程,父进程block在fork处
注:设置方法:
set follow-fork-mode [parent|child]
set detach-on-fork [on|off]

2. 启动方法

  1. gbd program

  2. gdb program core
  #同时调试一个运行程序和core文件

  3. gdb program pid
  # 如果你的程序是一个服务程序,那么你可以指定这个服务程序运行时的进程。

3. 查询进程

  1. 查询正在调试的进程:info inferiors
  2. 切换调试的进程:inferior
  3. 添加新的调试进程:add-inferior [-copies n] [-exec executable].

4. 常见命令

命令 功能
I 从第一行开始列出源码
break func 在函数func的入口处设置断点
break n 在第n行处设置断点
info break 查看断点信息
r 运行程序
n 单步执行
c 继续运行
p 打印变量值
bt 查看函数堆栈
finish 退出函数
shell 命令行 执行shell命令行
set args 指定运行时参数
show args 查看设置好的参数
show paths 查看程序运行路径
clear n 清除第n行断点
delete n 删除第n个断点
disable n 暂停第n个断点
enable n 开启第n个断点
step 单步调试如果有函数调用,则进入函数
list 简记为l,列出程序源代码,默认每次显示十行
list 行号 将显示当前文件以行号为中心的前后10行代码
list 函数名 将显示函数名所在函数的源代码
run 简记为r,运行程序,当遇到断点时,程序会在断点处停止运行。
回车 重复上一条命令
print a 将显示整数a的值
print name 将显示字符串name的值
watch 表达式 设置一个监视点一旦被监视的“表达式”的值改变,gdb将强行终止正在被调试的程序。
kill 强制终止当前调试程序
help help命令将显示常用帮助信息
call 函数 调试函数
layout 用于分割窗口,可以一边查看代码,一边测试
quit 简记为q,退出gdb
set environment varname [=value] 设置环境变量。如:set env USER=hchen;
show environment [varname] 查看环境变量;

5. 调试多进程

以下面程序为例进行调试:

#include <stdio.h>                                                          
  2 #include <unistd.h>
  3 #include <stdlib.h>
  4 
  5 void son_fun()
  6 {
  7 
  8     pid_t pid=getpid();
  9     printf("son:%d\n",pid);
 10 }
 11 void father_fun()
 12 {
 13     pid_t pid=getpid();
 14     printf("father:%d\n",pid);
 15 }
 16 int main()
 17 {
 18     pid_t id=fork();
 19     if(id<0)
 20     {
 21         perror("fork");
 22         exit (1); 
  else if(id==0)
 25     {
 26       son_fun();
 27     }
 28     else
 29     {
 30         father_fun();
 31     }
 32     return 0;
 33 }                                                                           

这里写图片描述
这里写图片描述
这里写图片描述
其他重要命令

  1. add-inferior [-copies n] [-exec executable]
    添加新的调试进程,可以用file executable来分配给inferior可执行文件。增加n个inferior并执行程序为executable。如果不指定n只增加一个inferior。如果不指定executable,则执行程序留空,增加后可使用file命令重新指定执行程序。这时候创建的inferior其关联的进程并没启动。

  2. remove-inferiors infno
    删除一个infno号的inferior。如果inferior正在运行,则不能删除,所以删除前需要先kill或者detach这个inferior。

  3. clone-inferior [-copies n] [infno]
    复制n个编号是infno的inferior。如果不指定n的话,就只复制一个inferior。如果不指定infno,则就复制正在调试的inferior。

  4. detach inferior infno
    detach去掉编号是infno的inferior。注意这个inferior还存在,可以再次用run命令执行它。

  5. kill inferior infno
    kill掉infno号inferior。注意这个inferior仍然存在,可以再次用run等命令执行它

这里写图片描述

多线程调试

gbd默认支持调试多线程,跟踪主线程,子线程断点在create thread。

1. 常见命令

info thread: 查看当前进程的线程
thread ID :切换调试的线程为指定ID的线程。
break file.c:100 thread all : 在file文件第100行处为所有经过第100行的线程设置断点。

set scheduler-locking off |on|step
在使用step或continue命令调试当前被调试线程的时候,其他线程也同时执行。
如果只让被调试程序执行,我们需要以下命令。

命令 含义
off 不锁定任何线程,也就是所有线程都执行,默认值。
on 只有当前被调试程序执行
step 在单步的时候,出来next过一个函数的情况(设置断点然后continue的行为)。

2. 调试程序

以下面程序为例进行调试:

void* thread1(void* arg)
{
    printf("thread1, tid is %lu\n", pthread_self());
    return NULL;
}

void* thread2(void* arg)
{
    printf("thread2, tid is %lu\n", pthread_self());
    return NULL;
}

int main()
{
    pthread_t tid1, tid2;
    pthread_create(&tid1, NULL, thread1, NULL);
    pthread_create(&tid2, NULL, thread2, NULL);

    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);
    return 0;
}

这里写图片描述
这里写图片描述

猜你喜欢

转载自blog.csdn.net/qq_37954088/article/details/81046129