文章目录

  • 在GDB下, 我们无法print宏定义,因为宏是预处理的。
  • 一、GDB调试多进程和多线程的基础指令
  • 一、GDB调试多线程
  • 1.gcc -g gbd.c -o my_debug -lpthread
  • 2.list [行号]
  • 3.info b
  • 4.r
  • 5.delete [断点号]
  • 6.n
  • 7.p [变量名]
  • 8.bt
  • 9.thread apply all bt,thread apply [编号…] [命令]
  • 10.info threads,thread+线程编号
  • 11.set scheduler-locking on
  • 11. c
  • 12.finish
  • 13.q
  • 二、GDB调试多进程
  • 1.show follow-fork-mode,set follow-fork-mode
  • 2.show detach-on-fork,set detach-on-fork off
  • 3.info inferiors,inferior+进程编号
  • 4. maint info program-spaces
  • 5.detach inferior [进程编号]
  • 6.kill inferior [进程编号]
  • 7.remove-inferior [进程编号]
  • 8.set schedule-multiple
  • 9.set print interior-events on/off
  • 三、参考

在GDB下, 我们无法print宏定义,因为宏是预处理的。

一、GDB调试多进程和多线程的基础指令

在多线程编程时,当我们需要调试时,有时需要控制某些线程停在断点,某些线程继续执行。有时需要控制线程的运行顺序。有时需要中断某个线程,切换到其他线程。这些都可以通过gdb实现。

下图为多线程与多进程调试的通用常用命令,应该熟练掌握下面几种命令的使用。

GDB多进程和多线程的调试方法:简单_多线程


1>介绍: gdb是Linux环境下的代码调试工具。

2>使用:需要在源代码生成的时候加上 -g 选项.

3>开始使用: gdb binFile

4>退出:ctrl + d 或 quit

5>调试过程中的常用命令:

list/l 行号:显示binFile源代码,接着上次的位置往下列,每次列10行。
list/l 函数名:列出某个函数的源代码。
r或run:运行程序。
s或step:进入函数调用
breaktrace(bt):查看各级函数调用及参数
info(i) locals:查看当前栈帧局部变量的值
info break :查看断点信息。
finish:执行到当前函数返回,然后挺下来等待命令
print§:打印表达式的值,通过表达式可以修改变量的值或者调用函数
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调试多线程

多线程调试的主要任务是准确及时地捕捉被调试程序线程状态的变化的事件,并且GDB针对根据捕捉到的事件做出相应的操作,其实最终的结果就是维护一个叫thread list的链表。

下面我们以以下多线程的程序为例,在gdb模式下测试各种命令。

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
int count = 0;
void *pthread_run(void *arg)
{
	int i = 0;
	while(i < 100)
	{
		i++;
		count += i;
	}
	return NULL;
}
int main()
{
	pthread_t pth1;//主线程
	pthread_t pth2;//主线程
	pthread_create(&pth1,NULL,&pthread_run,NULL);创建线程1
	pthread_create(&pth2,NULL,&pthread_run,NULL);创建线程2
	pthread_join(pth1,NULL);//等待线程1
	pthread_join(pth2,NULL);//等待线程2
	printf("count: %d\n",count);
	return 0;
}

以上代码中,主线程main创建了两个子线程分别是thread1和thread2,所以线程的总数为3个。

在多线程编程时,当我们需要调试时,有时需要控制某些线程停在断点,有些线程继续执行。有时需要控制线程的运行顺序。有时需要中断某个线程,切换到其他线程。这些都可以通过gdb实现。 
GDB默认支持调试多线程,跟主线程,子线程block在create thread。

1.gcc -g gbd.c -o my_debug -lpthread

  • 照例我们先编译代码,一定要记得加-g选项,与多进程不同的是,多线程编译时要加-lpthread

2.list [行号]

  • list [行号]:表示列出第几行附近的代码,默认显示10行,可以摁下l选项顺次列出(list可缩写为l)
  • GDB多进程和多线程的调试方法:简单_多线程_02


3.info b

  • info break

  • 查看断点信息。break [行号],表示在程序的第几行设置断点(break可简写为b)
  • GDB多进程和多线程的调试方法:简单_GDB_03

  • b还可以:

  • filename:linenum 制定个文件的行号,filename:function 制定文件中的函数;

  • break test.c:10,break test.c:main

  • 下面的.c文件主要为了说明在哪打断点

1 /**************************************
  2 *文件说明:thread.c
  3 *作者:段晓雪
  4 *创建时间:2017年06月10日 星期六 15时24分05秒
  5 *开发环境:Kali Linux/g++ v6.3.0
  6 ****************************************/
  7 
  8 #include<stdio.h>
  9 #include<pthread.h>
 10 
 11 void* thread1(void* arg)
 12 {
 13     printf("i am thread1,my tid is %u\n",pthread_self());
 14     return NULL;
 15 }
 16 
 17 void* thread2(void* arg)
 18 {
 19     printf("i am thread2,my tid is %u\n",pthread_self());
 20     return NULL;
 21 }
 22 
 23 int main()
 24 {
 25     pthread_t tid1,tid2;
 26     pthread_create(&tid1,NULL,thread1,NULL);//创建线程1
 27     pthread_create(&tid2,NULL,thread2,NULL);//创建线程2
 28 
 29     pthread_join(tid1,NULL);//等待线程1
 30     pthread_join(tid2,NULL);//等待线程2 
 31 
 32     return 0;
 33 }
  • 在线程1中打断点
  • GDB多进程和多线程的调试方法:简单_多进程_04


  • 在线程2打断点
  • 点设置在19行(线程2中),由于线程1已经运行完毕,所以可以调试的线程只有两个,正在运行的为线程2。
  • GDB多进程和多线程的调试方法:简单_GDB_05


4.r

  • 即run,表示运行程序。上面设置了断点,因此会在第一个断点处停住
  • GDB多进程和多线程的调试方法:简单_GDB_06


5.delete [断点号]

  • 表示删除单个断点。delete 1-10:删除一个断点的集合,表示删除1到10所有的断点
  • GDB多进程和多线程的调试方法:简单_多进程_07


6.n

  • 即next,单步调试模式,表示单条语句执行
  • GDB多进程和多线程的调试方法:简单_多线程_08


7.p [变量名]

  • 打印变量的值,p为printf的缩写。
  • GDB多进程和多线程的调试方法:简单_多线程_09


8.bt

  • 查看函数的堆栈信息
  • GDB多进程和多线程的调试方法:简单_多进程_10


9.thread apply all bt,thread apply [编号…] [命令]

  • thread apply all bt:让所有线程都打印堆栈信息。
  • thread apply ID command :让ID线程执行命令command。
  • thread apply all command :让所有线程执行命令command。
  • GDB多进程和多线程的调试方法:简单_GDB_11


  • thread apply [编号…] [命令]:可以让多个线程同时执行某条命令。
    如:让2,3线程同时向下执行一步。也可以使用thread apply all [命令],让所有线程执行某个调试命令。
  • GDB多进程和多线程的调试方法:简单_多线程_12


10.info threads,thread+线程编号

  • 显示当前可调试的所有线程,gdb为每一个线程分配一个ID号。*表示正在调试的线程。thread [线程ID]:切换到当前要调试的线程ID。
  • GDB多进程和多线程的调试方法:简单_GDB_13


  • thread+线程编号:和多进程类似,可以使用thread+线程编号切换当前正在调试的线程。
    所以,thread 后*号到了编号为3的线程的前面,表示当前调试的就是该线程
  • GDB多进程和多线程的调试方法:简单_多进程_14


11.set scheduler-locking on

-可以设置scheduler-locking参数(默认值为off),控制是多个线程同时运行还是只运行某个线程,它的取值和意义如下

GDB多进程和多线程的调试方法:简单_多进程_15


GDB多进程和多线程的调试方法:简单_GDB_16

11. c

  • continue,与C/C++中的continue完全一致。
  • GDB多进程和多线程的调试方法:简单_多线程_17


12.finish

  • 退出当前函数(本例中为pthread_run)
  • GDB多进程和多线程的调试方法:简单_GDB_18


13.q

  • 即quit,表示退出gdb模式
  • GDB多进程和多线程的调试方法:简单_多线程_19


二、GDB调试多进程
  • 在Linux(CentOS6.5)默认设置下,调试多进程程序时gdb只会调试父进程,为了可以对父子进程都做到调试,我们需要做一些设置。
  • 设置follow-fork-mode 的值为child,表示只调试的子进程,再查看当前调试进程发现变成了新产生出来的进程,即子进程。follow-fork-mode(默认值是parent)和detach-on-fork(默认值是on)结合使用
  • 4种组合的意义分别如下:
  • GDB多进程和多线程的调试方法:简单_多线程_20


1.show follow-fork-mode,set follow-fork-mode

  • 查看当前调试的fork模式,如下图,默认为父进程,如果想设置为子进程,可以使用set follow-fork-mode child
  • GDB多进程和多线程的调试方法:简单_GDB_21


  • GDB多进程和多线程的调试方法:简单_多进程_22


2.show detach-on-fork,set detach-on-fork off

  • 查看detach-on-fork的模式。
  • 设置为on表示只调试父子进程(与1的设置有关)中的一个;
  • off表示父子进程都在gdb的控制之下,其中一个进程正常调试另一个进程会被设置为暂停状态
  • GDB多进程和多线程的调试方法:简单_GDB_23


3.info inferiors,inferior+进程编号

  • info inferiors:显示gdb调试的所有进程。inferior [进程编号]:可以切换到特定的inferiors进行调试。其中*代表正在调试的进程。

GDB多进程和多线程的调试方法:简单_GDB_24

  • inferior+进程编号:即info inferiors后显示在第一列的号码)来切换当前正在调试的进程
  • GDB多进程和多线程的调试方法:简单_GDB_25


4. maint info program-spaces

显示当前gdb一共管理了多少地址空间

GDB多进程和多线程的调试方法:简单_多进程_26

5.detach inferior [进程编号]

  • detach掉某一进程的编号,但是这个进程还存在,让它自由运行完,detach掉的进程会显示null

6.kill inferior [进程编号]

  • kill掉某进程,但是此进程还存在,可再次使用run等命令执行它,被kill掉的进程会显示null

7.remove-inferior [进程编号]

  • 删除某一个inferior。如果该inferior正在运行,则不能删除,因此删除之前必须先kill或detach掉

8.set schedule-multiple

  • 设置为off表示只有当前的inferior会被执行,设置为on,表示所有执行状态的inferior都会被执行
  • GDB多进程和多线程的调试方法:简单_多进程_27


9.set print interior-events on/off

  • 用来打开和关闭inferior状态的提示信息
  • GDB多进程和多线程的调试方法:简单_多进程_28