使用gdb调试多线程多进程程序

来源:互联网 发布:金元证券软件下载 编辑:程序博客网 时间:2024/05/18 18:21

GDB的基本介绍

GDB是GUN开源组织发布的一个强大的UNIX下的程序调试工具。或许,平时大家更加习惯图形界面的调试,比如VS上的IDE调试;但是如果我们在UNIX或Linux下做软件,我们呢就更加需要熟练GDB这个调试工具。

一般来说,GDB主要能够完成以下的几个功能:

①启动你的程序,可以按照你自己的要求随性所欲的运行程序;

②可以让被调试的程序在你自己所定的位置的断点处挺住;

③当程序被停住时,可以检查此时你的程序中所发生的事情;

④动态的改变你程序的执行环境。

GDB调试使用的是DEBUG版本的,所以我们在生产可执行文件时,我们需要在命令的尾部加上 -g,这样就可以生成的是DEBUG版本下的可执行文件。

调试代码的基本命令

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

GDB调试多进程

在默认情况下是调试多进程程序时GDB会默认调试主进程,但是GDB支持多进程的分别与同步调试。即GDB支持同时调试多个进程,只需要设置follow-fork-mode(默认为parent)和detach-on-fork(默认为on)即可。我们还可以使用catch fork指令,如果fork异常,会停止程序。

follow-fork-modedetach-on-fork说明parenton只调试主进程(GDB默认)childon只调试子进程parentoff同时调试两个进程,gdb跟主进程,子进程block(阻塞)在fork位置childoff同时调试两个进程,gdb跟子进程,主进程block在fork位置
设置方法: set follow-fork-mode[parent|child] set detach-on-fork[on|off]

显示:show follow-fork-mode show detach-on-fork


下面通过代码来演示


调试步骤:

只调试父进程


只调试子进程(与上面的对比起来看)


下面呢我们开始直接调试两个进程(父进程运行调试,子进程阻塞等待)


最后我们进行子进程运行调试,父进程阻塞等待


GDB调试多线程

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

gdb调试一般有两种模式:all-stop模式和no-stop模式(gdb7.0之前不支持no-stop模式)。

1.all-stop模式

在这种模式下,当你的程序在gdb由于任何原因而停止,所有的线程都会停止,而不仅仅是当前的线程。一般来说,gdb不能单步所有的线程。因为线程调度是gdb无法控制的。无论什么时候当gdb停止你的程序,它都会自动切换到触发断点的那个线程。

2.no-stop模式(网络编程常用)

顾名思义,启动不关模式。当程序在gdb中停止,只有当前的线程会被停止,而其他线程将会继续运行。这时候step,next这些命令就只对当前线程起作用。

如果需要打开no-stop模式,可以向~/.gdbinit添加配置文件:


gdb支持的命里有两种类型:前台的(同步的)和后台(异步 )的。区别很简单,同步的在输出提示符之前会等待程序report一些线程已经终止的信息,异步则是直接返回。所以我们需要set target-async 1。set pagination off不要出现 Type <return> to continue 的提示信息 。最后一步是打开。

下面看一下gdb调试多线程常用命令:

命令作用info threads显示所有可调试的线程thread ID切换到指定线程,gdb为每一个线程分配一个ID(与tid不同),编号一般从1开始breakfilename:linenum thread all在所有线程相应行设置断点,注意如果主线程不会执行到该行,并且启动all-stop模式,主线程执行n或s会切换过去set scheduler-locking off|on\step默认off,执行s或c其它线程也同步执行。on,只有当前相称执行。step,只有当前线程执行show scheduler-locking显示当前模式thread apply all command每个线程执行同意命令,如bt。或者thread apply 1 3 bt,即线程1,3执行bt。

通过代码来演示:


调试步骤:

开始调试


然后开始运行代码

单步调试


切换到其他线程


再切换到其他线程调试


设置core文件

core的意思是核心,dumped的意思就是抛出,转储,core dumped就是核心转储的意思。当一个进程异常退出前,该进程会抛出当时该程序进程的内存详细情况存储在硬盘上,文件名通常是core,这就叫core dump。

进程异常终止通常是因为代码存在BUG,比如非法内存访问导致段错误,事后可以用调试器检查core文件以查清错误原因,这叫做事后调试。

uname -a 查看机器参数

ulimit -a 查看默认参数

ulimit -c 1024 设置core文件大小为1024

ulimit -c unlimit 设置core文件大小为无限

ulimit -c unlimited 生成core文件,也可以是指定大小,然后使用gdb ./main core启动,bt查看调用栈即可。

eg1(可以快速定位出问题的位置)

gdb a.out core.xxx

where

eg2 (在 gdb 中使用)

(gdb) core-file core.xxx





原创粉丝点击