core dump:
当一个进程要被终止时,可以选择把进程的用户空间内存数据全部保存在磁盘上,文件名通常是core,这叫做core dump(核心转储)。
ulimit -c //查看是否为0
ulimit -c unlimited //如果为0
这样在程序崩溃以后会在当前目录生成一个core.xxxx的文件
生成了core.xxx文件以后
gdb ./应用程序 core.xxxx // 就会恢复现场到你的程序崩溃的那一刻
(gdb)bt //这个命令会列出程序崩溃时的堆栈信息,一层一层会有标号 #0 #1 #2 .......
如果你要查看某一层的信息,你需要在切换当前的栈,一般来说,程序停止时,最顶层的栈就是当前栈,如果你要查看栈下面层的详细信息,首先要做的是切换到你想看的栈。
(gdb)f N //N是你想要切换的栈的标号,达到后可以用 ‘p 变量’ 查看变量的值,以查找异常出现的原因
info args
打印出当前函数的参数名及其值。
info locals
打印出当前函数中所有局部变量及其值。
info catch
打印出当前的函数中的异常处理信息。
(1) 前提条件: 可执行文件必须包含调试信息 gcc -g
(2) 启动gdb调试: gdb 文件名
启动时如果需要带有参数:
gdb --args myexe param1 param2 param3 ...
启动时指定代码搜索路径:
gdb -d /search/code
进入后,查看当前代码搜索路径:
show dir
设置代码搜索路径:
dir 目录1:目录2:目录3
其中的 $cdir 叫做编译目录,是代码在编译时记录到程序中的。
$cwd 表示当前的调试目录,可以通过 cd 命令来修改。
要注意这个 cd 修改的是 gdb 会话中的当前目录,不会影响启动 gdb 前文件系统中的目录位置。
查看gdb会话中的当前目录:pwd
替换前代码搜索路径:
set substitute from_path to_path
(3) 查看代码命令
当前文件:
list 行号(函数名)
指定文件:
list 文件名:行号(函数名)
(4) 设置断点
当前文件:
break
在进入指定函数时停住。C++中可以使用class::function或function(type,type)格式来指定函数名。
指定文件:
b 文件名:行号(函数名)
设置条件断点:
b 行号 if value==23
监控某一个条件,然后设置断点,如果i不等于10的时候,就设置断点: watch i != 10
查看断点信息:
info b
删除所有的断点,输入N,则单独删除标号为N的断点:
delete (N)
清除N上面的所有的断点: clear N
(5) 开始调试
只运行一行代码:start
继续停靠在下一断点处: continue -- c
直接停在断点处: run -- r
(6) 单步调试
进入到函数体: step -- s
跳出函数体: finish(如果有循环处有断点,需要将断点删掉)
不进入函数体,输入k就是一次走k步:next -- n(k)
(7) 追踪变量
优化打印格式:set print pretty on
自动打印变量的值: display 变量名
取消变量的追踪: undisplay 编号
获取编号: info display
显示一个变量的类型: whatis val
更详细的方式显示变量var的类型:ptype var // 会打印出var的结构定义
手动打印变量的值: print -- p var
打印完整的长字符串(打印字符串的时候,有长度限制):set print element 0
以16进制显示var的值(): p /x var // x 16进制、 d 10进制、 t 二进制、c 按字符格式显示变量、 f 按浮点数
数组: print *a@10 // 如果a是一个数组,这样显示数据的10个元素的值
修改运行时变量的值:print var=10
(8) 跳出循环:u(untill)
(9) 执行上一步命令:回车
(10) 退出gdb:quit -- q
(11) gdb中执行shell命令:shell cmd 或者 !cmd
(1)info threads
查看当前调试环境中包含多少个线程,并打印出各个线程的相关信息,包括线程编号(ID)、线程名称等。
(2)thread id
将线程编号为 id 的线程设置为当前线程。
(3)thread apply id... command
id... 表示线程的编号;command 代指 GDB 命令,如 next、continue 等。整个命令的功能是将 command 命令作用于指定编号的线程。当然,如果想将 command 命令作用于所有线程,id... 可以用 all 代替。
(4)break location thread id
在 location 指定的位置建立普通断点,并且该断点仅用于暂停编号为 id 的线程。
(5)set scheduler-locking off|on|step
使用 GDB 调试多线程程序时,默认的调试模式为:一个线程暂停运行,其它线程也随即暂停;一个线程启动运行,其它线程也随即启动。
一些场景中,我们可能只想让某一特定线程运行,其它线程仍维持暂停状态。要想达到这样的效果,就需要借助 set scheduler-locking 命令。 此命令可以帮我们将其它线程都“锁起来”,使后续执行的命令只对当前线程或者指定线程有效,而对其它线程无效。
off:不锁定线程,任何线程都可以随时执行;
on:锁定线程,只有当前线程或指定线程可以运行;
step:当单步执行某一线程时,其它线程不会执行,同时保证在调试过程中当前线程不会发生改变。但如果该模式下执行 continue、until、finish 命令,则其它线程也会执行,并且如果某一线程执行过程遇到断点,则 GDB 调试器会将该线程作为当前线程。
(6)show scheduler-locking
查看各个线程锁定的状态
(7)thread apply all bt
查看所用线程堆栈信息
(1)set follow-fork-mode
其中 mode 为设置调试的进程:可以是child,也可以是parent。当 mode 为 parent 时,程序在调用 fork 后调试父进程,子进程不会受到影响。当 mode 为 child 时,程序在调用 fork 后调试子进程,父进程不会受到影响。
(2)show follow-fork-mode
查看 GDB 中设置的 follow-fork-mode
(3)set detach-on-fork
在GDB中调试多进程时,可以只调试一个进程,也可以同时调试两个进程,这个和 GDB 中的 detach-on-fork 的设置有关。mode 可以为 on,也可以为off。当 mode 为 on 时,表示程序只调试一个进程(可以是父进程、子进程),这是 GDB 的默认设置。当 mode 为 off 时,父子进程都在gdb的控制之下,其中一个进程正常的调试,另一个会被设置为暂停状态。
(4)show detach-on-fork
查看 GDB 中设置的 detach-on-fork
(5)info inferiors
查看当前调试的所有的 inferior。
GDB 将每一个被调试程序的执行状态记录在一个名为 inferior 的结构中。一般情况下一个 inferior 对应一个进程,每个不同的 inferior 有不同的地址空间。inferior 有时候会在进程没有启动的时候就存在。
(6)inferior
表示切换到 id 为 num 的 inferior。
inferior 2 --> 切换到 2 号进程。
(1) 可能是你打断点的输入有问题,如将main.cpp
写成了mian.cpp
(2) 动态库中的函数,需要加载之后才能知道符号信息。所以,没加载动态库之前,断点设置成函数名,加载之后,可以断在具体的代码位置。
可以将重复的命令写入一个cmd.gdb
文件中,比如:
set args codegen.json
set print pretty on
然后在gdb命令行中执行:
source cmd.gdb
set logging file gdb.out ## 将gdb输出重定向到gdb.out
set logging on ## 打开日志记录
p mystruct ## 打印结构体变量
set logging off ## 关闭日志记录
objdump -h helloword
参考:gdb调试常用实用命令和core dump文件的生成