gdb调试【多进程,多线程】

一.gdb简介

  • gdb工具是Linux环境下的调试工具。(本文在centos6.5环境下测试)
  • 在编译源文件时候必须加上 -g选项。
  • 开始调试方式:gdb binfile
  • 退出方式 quit 或者ctrl+d.

gdb调试过程常用命令:

   list/l 行号:显示源代码,接着上次的位置往下列,每次列10行。
   list/l 函数名:列出某个函数的源代码。
   r或run:运行程序。
   s或step:进入函数调用
   breaktrace(bt):查看各级函数调用及参数
   info(i) locals:查看当前栈帧局部变量的值
   info break :查看断点信息。
   finish:执行到当前函数返回,然后挺下来等待命令
   print(p):打印表达式的值,通过表达式可以修改变量的值或者调用函数
   set var:修改变量的值
   quit:退出gdb
   break(b) 行号:在某一行设置断点
   break 函数名:在某个函数开头设置断点
   continue(或c):从当前位置开始连续而非单步执行程序
   run(或r):从开始连续而非单步执行程序
   delete breakpoints:删除所有断点
   delete breakpoints n:删除序号为n的断点
   disable breakpoints:禁用断点
   enable breakpoints:启用断点
   info(或i) breakpoints:参看当前设置了哪些断点
   display 变量名:跟踪查看一个变量,每次停下来都显示它的值
   undisplay:取消对先前设置的那些变量的跟踪
   until X行号:跳至X行
   p 变量:打印变量值
   n 或 next:单条执行

二、调试多进程

在默认的情况下,gdb只会调试主进程,如果想要调试多个进程,需要进行一些设置:
1.show follow-fork-mode命令和show detach-on-fork
这里写图片描述这个命令是查看这两个模式设置:
默认follow-fork-mode是parent,detach-on-fork是on,此时只调试主进程。
2.set follow-fork-mode和set detach-on-fork
这个命令可以对这两个模式重新设置进行多进程的调试
其中follow-fork-mode 有两个选项:[parent]和[child]
detach-on-fork 有两个选项:[on]和[off]
那么就有以下四种情况,各自代表不同的含义:

1.parent                   on               只调试主进程(GDB默认)
2.child                    on               只调试子进程
3.parent                   off              同时调试两个进程,gdb跟主进程,子进程block在fork位置
4.child                    off              同时调试两个进程,gdb跟子进程,主进程block在fork位置

下面进行设置:
这里写图片描述

测试文件:

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<sys/types.h>
  4 #include<sys/wait.h>
  5 #include<stdlib.h>
  6 int main()
  7 {
  8 pid_t pid;
  9 pid=fork();
 10 if(pid<0)
 11 {
 12  
 13     perror("fork");
 14     exit(1);
 15  
 16 }
 17 if(pid==0)
 18 {//child
 19 printf("I am Child,My id is:%d,My fathers id is:%d\n",getpid(),getppid());
 20  
 21 }
 22 if(pid>0)
 23 {//father
 24 printf("I am Father,My id is:%d\n",getpid());
 25 wait(NULL);                                                                                                                                                                                   
 26 }
 27  
 28     return 0;
 29 }

3.接下来,在分别在父子进程的地方下断点:
这里写图片描述
4.运行程序,查询正在运行的进程:
这里写图片描述
这里写图片描述
每一个被调试的进程,操作系统都会给他分配一个inferior结构体来描述这个进程的调试信息,并且为它分配id,每一个进程对应一个inferior,每个不同的inferior都有不同的地址空间,有时候在进程的还没有启动的时候inferior就存在了。
5.切换调试的进程:

inferior<infer number>

这里写图片描述
6.其他操作
添加调试进程

1.add-inferior [-copies n] [-exec executable]

添加一个或者多个调试进程,n代表添加个数,没有指定时候,默认添加一个,executable为调试文件路径,如果没有指定,则程序留空,增加后可使用file命令重新指定执行程序。这时候创建的inferior其关联的进程并没启动。
删除编号为inferno的inferior。如果这个程序正在运行,则不能删除,必须先detach掉或者kill掉这个inferior。

2.remove-inferior inferno

复制n个编号为inferno的inferior,如果不指定n,则复制一个,不指定inferno的话,默认复制当前进程。

3.clone-inferior [n][inferno]

detach分离掉编号为inferno 的inferior,注意就算detach掉,这个inferior还是存在,等待用户再一次使用run命令让它运行起来。

4.detach-inferior inferno

kill掉编号为inferno 的inferior,注意就算被掉,这个inferior同样还是存在,等待用户再一次使用run命令让它运行起来。

5.kill-inferior inferno

6.set schedule-multiple on|off

当设置为off的时候:只有当前inferior会执行
当设置为on的时候:所有是执行状态的inferior都会执行

7.scheduler-locking

注意当scheduler-locking为on的时候,即使scheduler-multiple为on,也只有当前进程的当前线程会执行。默认是step。可以通过show sheduler-locking来查看,

8.set follow-exec-mode new|same

设置为new:当发生exec的时候,在执行exec的inferior上控制子进程。
设置为same:新建一个inferior给执行起来的子进程。而父进程的inferior仍然保留,当前保留的inferior的程序状态是没有执行。

9. set print inferior-events

用于设置inferior的状态提示信息,可以设置为on或者off。

10.maint info program-spaces

用来查看当前GDB一共管理了多少的地址空间。


三、调试多线程

gdb是默认支持调试多线程的。跟主线程,新线程block在创建的地方。
测试文件:

  1 #include<stdio.h>
  2 #include<pthread.h>
  3     
  4 void *run1(void *arg)
  5 {   
  6 printf("I am thread 1,My id is:%d\n",pthread_self());
  7 }   
  8 void * run2(void *arg)
  9 {   
 10     printf("I am thread2 ,My id is:%d\n",pthread_self());
 11 }   
 12  int main()
 13 {   
 14     pthread_t t1,t2;
 15     pthread_create(&t1,NULL,run1,NULL);
 16     pthread_create(&t2,NULL,run2,NULL);
 17     pthread_join(t1,NULL);
 18     pthread_join(t2,NULL);
 19     return 0;
 20 }
 21       

这里创建了两个线程,所以一共有三个线程。这里分别在两个线程函数内部打了两个断点.
这里写图片描述
1.调试多线程常用命令

1.info threads

当调试多线程的时候,gdb会为每一个线程分配一个线程id,一般从1开始,这里的线程id和t1不一样。我们可以查看线程情况,由于我们的第一个断点在线程run1中,所以2号线程正在运行。

2.thread ID

切换调试的线程,ID即线程编号。

3.show scheduler-locking
  set  scheduler-locking on|off|step

查看线程锁定情况和设置线程锁定情况,当设置为on的时候,锁定其余线程,只有当前线程会运行。设置为off,不锁定任何线程,默认值。当设置为step的时候,只有被调试的线程会运行。

4.thread apply id1 id2 id3 commond
  thread apply all commond

第一个是让指定的线程1,2,3执行commond命令,第二个是所有线程都执行commond命令。

5.break FileName.cpp:LinuNum thread all: 

所有线程都在文件FileName.cpp的第LineNum行有断点。

6.set target-async on/ff

同步和异步。同步,gdb在输出提示符之前等待程序报告一些线程已经终止的信息。而异步的则是直接返回。

猜你喜欢

转载自blog.csdn.net/ChenYang1998/article/details/80170198