目录

常用命令

堆栈相关命令

更为详细的断点调试

gdb多进程调试

gdb多线程调试


前言

gdb 是 linux 平台下进行程序调试的最常用的工具。简单的程序调试就是加断点,然后一步一步让程序运行,直到找到 bug 。一般的程序调试起来比较简单,但是在多进程或多线程情况下调试起来就比较麻烦。

若 test.c 是你想要调试的程序,那么在编译时需要加 -g,即 gcc test.c -g -o test。完成编译后使用命令:gdb test。

常用命令

命令

命令缩写及例子

说明

list + n

l + n

显示源码第n行前后的代码,显示范围有限。

break + n

b + n

在第n行设置断点

info

i

描述程序状态

run

r

开始运行程序

display

disp

跟踪查看某个变量的值

info display

用于显示当前所有要显示值的表达式的情况

undisplay

undisplay + 编号

用于结束某个表达式值的显示

step

s

执行下一条语句,如果该语句为函数调用,则进入函数执行其中的第一条语句

next

n

执行下一条语句,如果该语句为函数调用,不会进入函数内部执行

print

p

打印内部变量的值

continue

c

继续运行,直到遇到下一个断点

start

st

开始执行程序,在main函数的第一条语句前面停下来

kill

k

终止正在调试的程序

quit

q

退出gdb

set args

set args arg1 arg2

设置运行参数

show args

show args

查看运行参数

finish

finish

一直运行到函数返回并打印函数返回时的堆栈地址和返回值及参数值等信息

堆栈相关命令

命令

例子

说明

backtrace

bt

查看堆栈信息

frame

f 1

查看栈帧

info reg

info reg/ i r

查看寄存器使用情况

info stack

info stack

查看堆栈使用情况

up/down

up/down

跳到上一层/下一层函数

这里以一个简单的程序为例,进行调试。

#include <bits/stdc++.h>
using namespace std;
#define M 5int fact(int n)             //线性递归
{if (n < 0)return 0;else if(n == 0 || n == 1)return 1;elsereturn n * fact(n - 1);
}int facttail(int n, int a)   //尾递归
{if (n < 0)return 0;else if (n == 0)return 1;else if (n == 1)return a;elsereturn facttail(n - 1, n * a);
}int facttail1(int n, int a)
{while(n > 0){a = n * a;n--;}return a;
}int main()
{//printf("%p", facttail);int a = fact(M);int b = facttail(M, 1);cout << "A:" << a <<endl;cout << "B:" << b <<endl;
}

(1)开始 gdb 调试

(2)设置断点

(3)查看栈的使用情况

更为详细的断点调试

命令

例子

说明

break + 设置断点的行号

break n

在n行处设置断点

tbreak + 行号或函数名

tbreak n/func

设置临时断点,到达后被自动删除

break + filename + 行号

break main.c:10

用于在指定文件对应行设置断点

break + <0x...>

break 0x3400a

用于在内存某一位置处暂停

break + 行号 + if + 条件

break 10 if i==3

用于设置条件断点,在循环中使用非常方便

info breakpoints/watchpoints [n]

info break

n表示断点编号,查看断点/观察点的情况

clear + 要清除的断点行号

clear 10

用于清除对应行的断点,要给出断点的行号,清除时GDB会给出提示

delete + 要清除的断点编号

delete 3

用于清除断点和自动显示的表达式的命令,要给出断点的编号,清除时GDB不会给出任何提示

disable/enable + 断点编号

disable 3

让所设断点暂时失效/使能,如果要让多个编号处的断点失效/使能,可将编号之间用空格隔开

awatch/watch + 变量

awatch/watch i

设置一个观察点,当变量被读出或写入时程序被暂停

rwatch + 变量

rwatch i

设置一个观察点,当变量被读出时,程序被暂停

catch

设置捕捉点来补捉程序运行时的一些事件。如:载入共享库(动态链接库)或是C++的异常

tcatch

只设置一次捕捉点,当程序停住以后,应点被自动删除

gdb多进程调试

命令

例子

说明

set follow-fork-mode [parent|child]

set follow-fork-mode parent or child

设置调试器的模式,mode参数可以是:

parent :fork之后调试原进程,子进程不受影响,这是缺省的方式

child :fork之后调试新的进程,父进程不受影响。

show follow-fork-mode

show follow-fork-mode

显示当前调试器的模式

set detach-on-fork [on|off]

set detach-on-fork on or off

设置gdb在fork之后是否detach进程中的其中一个,或者继续保留控制这两个进程 。

on:子进程(或者父进程,依赖于follow-fork-mode的值)会detach然后独立运行,这是缺省的mode

off:两个进程都受gdb控制,一个进程(子进程或父进程,依赖于follow-fork-mode)被调试,另外一个进程被挂起

info inferiors

info inferiors

显示所有进程

inferiors processid

inferiors 2

切换进程

detach inferiors processid

detach inferiors processid

detach 一个由指定的进程,然后从fork 列表里删除。这个进程会被允许继续独立运行。

kill inferiors  processid

kill inferiors  processid

杀死一个由指定的进程,然后从fork 列表里删除。

catch fork

catch fork

让程序在fork,vfork或者exec调用的时候中断

调试多进程时,需要设置 detach-on-fork 的值,默认值为 on,设置为 off 的含义:一个进程被调试,另外一个进程被挂起,这样就可以交替的调试进程。follow-fork-mode 的默认值为 parent,即默认调试父进程。调试代码:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>int main()
{int num = 0;pid_t pid = fork();if(pid == 0) //子进程{while(1){num++;printf("child:pid:[%d] num:[%d]\n", getpid(), num);sleep(2);}}else{while(1){num = num + 2;printf("parent:pid:[%d] num:[%d]\n", getpid(), num);sleep(2);}}return 0;
}

(1) 查看系统默认的 follow-fork-mode 和 detach-on-fork 设置follow-fork-mode 和 detach-on-fork

show follow-fork-mode
show detach-on-fork
set follow-fork-mode [parent|child]
set detach-on-fork [on|off]

(2) 设置断点并查看断点信息

(3) 运行程序并使用 info inferiors 命令 (显示GDB调试的所有进程,其中带有*的进程是正在调试的进程)

(4) 使用 inferior + [编号] 切换进程,对子进程进行调试

(5) 继续运行程序,观察子进程的输出

(6) 中断子进程运行后,开始逐步调试

(7) 再次切换回父进程完成调试

gdb多线程调试

命令

例子

说明

info threads

info threads

查询线程信息

thread + 线程号

thread 2

切换线程

thread apply [threadno] [all] + 命令

thread apply [threadno] [all] bt

线程根据相应的命令完成操作

set print thread-events

set print thread-events

控制线程开始和结束时的打印信息

show print thread-events

show print thread-events

显示线程打印信息的开关状态

调试代码:

#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <errno.h>
#include <unistd.h>/*全局变量*/
int sum = 0;
/*互斥量 */
pthread_mutex_t mutex;
/*声明线程运行服务程序*/
void* pthread_function1 (void*);
void* pthread_function2 (void*);int main (void)
{/*线程的标识符*/pthread_t pt_1 = 0;pthread_t pt_2 = 0;int ret = 0;/*互斥初始化*/pthread_mutex_init (&mutex, NULL);/*分别创建线程1、2*/ret = pthread_create( &pt_1,                  //线程标识符指针NULL,                  //默认属性pthread_function1,     //运行函数NULL);                 //无参数if (ret != 0){perror ("pthread_1_create");}ret = pthread_create( &pt_2,                  //线程标识符指针NULL,                   //默认属性pthread_function2,      //运行函数NULL);                  //无参数if (ret != 0){perror ("pthread_2_create");}/*等待线程1、2的结束*/pthread_join (pt_1, NULL);pthread_join (pt_2, NULL);printf ("main programme exit!\n");return 0;
}/*线程1的服务程序*/
void* pthread_function1 (void*a)
{int i = 0;printf ("This is pthread_1!\n");for( i=0; i<3; i++ ){pthread_mutex_lock(&mutex); /*获取互斥锁*//*临界资源*/sum++;printf ("Thread_1 add one to num:%d\n",sum);pthread_mutex_unlock(&mutex); /*释放互斥锁*//*注意,这里以防线程的抢占,以造成一个线程在另一个线程sleep时多次访问互斥资源,所以sleep要在得到互斥锁后调用*/sleep (1);}pthread_exit ( NULL );
}/*线程2的服务程序*/
void* pthread_function2 (void*a)
{int i = 0;printf ("This is pthread_2!\n");for( i=0; i<5; i++ ){pthread_mutex_lock(&mutex); /*获取互斥锁*//*临界资源*/sum++;printf ("Thread_2 add one to num:%d\n",sum);pthread_mutex_unlock(&mutex); /*释放互斥锁*//*注意,这里以防线程的抢占,以造成一个线程在另一个线程sleep时多次访问互斥资源,所以sleep要在得到互斥锁后调用*/sleep (1);}pthread_exit ( NULL );
}

(1) 设置断点并查看信息

(2) 运行程序,这里可以不设第一个断点

(3) 两个线程交替运行,观察不同线程的输出结果

(4) 使用 info threads 查看线程信息,使用 thread + [编号] 切换线程

(5) 使用 thread apply + [编号] + 命令 

锁定其他线程,只让当前线程运行

(1) 设置 set scheduler-locking on

(2)  观察线程 1 运行的情况并完成调试

其他命令

(1) thread apply ID1 ID2 IDN command: 让线程编号是ID1,ID2…等等的线程都执行command命令。

(2) thread apply all command:所有线程都执行command命令。

(3) set scheduler-locking off|on|step: 在调试某一个线程时,其他线程是否执行。在使用step或continue命令调试当前被调试线程的时候,其他线程也是同时执行的,如果我们只想要被调试的线程执行,而其他线程停止等待,那就要锁定要调试的线程,只让他运行。

off:不锁定任何线程,默认值。

on:锁定其他线程,只有当前线程执行。

step:在step(单步)时,只有被调试线程运行。

(4) set non-stop on/off:当调试一个线程时,其他线程是否运行。

(5) set pagination on/off: 在使用backtrace时,在分页时是否停止。

(6) set target-async on/ff: 同步和异步。同步,gdb在输出提示符之前等待程序报告一些线程已经终止的信息。而异步的则是直接返回。

(7) show scheduler-locking: 查看当前锁定线程的模式

参考:

https://blog.csdn.net/snow_5288/article/details/72982594

https://www.cnblogs.com/euphie/p/9781482.html

Linux gdb多进程、多线程调试相关推荐

  1. linux线程并不真正并行,多核时代:并行程序设计探讨(3)——Windows和Linux对决(多进程多线程)...

    并行程序设计探讨(3)--Windows和Linux对决(多进程多线程) 前面的博文经过分析总结,最后得出两种并行技术:多进程多线程.多机协作.对于多进程和多线程来说,最有代表性且最常见的的莫过于Wi ...

  2. GDB常用调试命令以及多进程多线程调试

    今天把所有的GDB常用的调试命令都过了一遍,尤其是多线程调试.所以先做个总结,以免忘记.以后如果有新的有用的命令会继续追加. 本文地址:(LYanger的博客:http://blog.csdn.net ...

  3. linux c多进程多线程,linux下的C\C++多进程多线程编程实例详解

    linux下的C\C++多进程多线程编程实例详解 1.多进程编程 #include #include #include int main() { pid_t child_pid; /* 创建一个子进程 ...

  4. 利用GDB进行多线程调试

    一.多线程调试 多线程调试重要就是下面几个命令: info thread 查看当前进程的线程. thread <ID> 切换调试的线程为指定ID的线程. break file.c:100 ...

  5. linux C 多进程架构,linux c 多进程多线程比较

    多进程 #include #include int main(){ pid_t pid; int result; pid = fork(); if(pid <0) { } else if (pi ...

  6. linux gdb 寄存器,x86 调试寄存器

    英文官方介绍<Intel® 64 and IA-32 Architectures Software Developer's Manual Volume 3A: System Programmin ...

  7. 多线程调试(gdb命令行和使用集成开发qtcreator查看线程状态)

    我在qtcreator中用调用的gdb找不到如何显示线程号对应的线程名字,因此需要继续学习使用gdb进行多线程调试. 1.创建多线程工程 2.启动进程并查看运行进程对应的id 3.使用gdb连接进程, ...

  8. Linux gdb调试(4):多进程与多线程调试

    一,gdb的基础知识 1>介绍: gdb是Linux环境下的代码调试工具. 2>使用:需要在源代码生成的时候加上 -g 选项. 3>开始使用: gdb binFile 4>退出 ...

  9. linux中多进程调试,linux下用gdb调试多进程

    今天来学习一下linux下gdb如何调试多进程,在学习之前我我们能先看一张表: 这张表是gdb调试的命令表,这对那些对gdb不熟的同学来说是非常有必要的. 一.多进程调试的命令 1.set follo ...

最新文章

  1. 蓝绿部署、金丝雀发布(灰度发布)、AB测试……
  2. vfast-全新的开始——荣新的第一天
  3. python进阶-第二季第一章
  4. java调用接口失败重试,httpclient接口测试中重试控制器设置
  5. android 加载更多,如何在android中实现加载更多的recyclerview
  6. 【struts2】struts2实现自定义数据类型转换器
  7. signature=94f3cd0155e1d8c8ff09aa94177adccd,研擬顆粒流與連體數值耦合方法模擬山崩產生之震動訊號...
  8. 51Nod1469 淋漓尽致子串
  9. leetcode134. 加油站
  10. php开启openssl的方法
  11. (转)MyBatis框架的学习(四)——Mapper.xml文件中的输入和输出映射以及动态sql
  12. Scrapy分布式原理及Scrapy-Redis源码解析(待完善)
  13. C++小白课本练习1
  14. 阿里高级技术专家:研发效能的追求永无止境 1
  15. android真机调试
  16. APT级全面免杀与企业纵深防御体系的红蓝对抗
  17. 原生 js 实现弹窗
  18. png图片背景转换成透明
  19. 谷歌浏览器如何截全屏长图(非常实用)
  20. VBS基础教程(收藏)

热门文章

  1. IOCP不可忽视的细节
  2. 【网络编程】之十三、ping程序实现
  3. Android Studio 构建
  4. BufferQueue 和 gralloc
  5. 没登录网页也能个性化推荐?一文详解浏览器指纹
  6. 重新复习一下JDK14的9大重磅特性
  7. 査勇:华为云在视频AI转码领域的技术实践
  8. LiveVideoStackCon 倒数计时:0
  9. 音视频技术开发周刊 | 132(FFmpeg决策委员会委员 刘歧)
  10. 技术人的少年感,和年龄无关。