前置条件:编译生成执行码时带上 -g,如果使用Makefile,通过给CFLAGS指定-g选项,否则调试时没有符号信息。
gdb program //最常用的用gdb启动程序,开始调试的方式
gdb --args program args //带参数启动或者 set args 参数,主要参数没有加“参数”
gdb -x /home/local/gdbinit --args grogram args //带自定义gdbinit脚本启动
gdb program core //用gdb查看core dump文件,跟踪程序core的原因
gdb attach pid //用gdb调试已经开始运行的程序,指定pid即可
如果systemd接管了core文件:
coredumpctl list 或者coredumpctl list --since=todey
coredumpctl info PID查看核心转储 或者coredumpctl gdb PID
有时候程序会剔除符号表,可以通过以下命令:
gdb -e /bin/a.out -c core.1234 -s ./debug/
或者在gdb状态下输入symbol目录
或者把符号表拷贝到lib目录(也有可能是bin目录),然后gdb直接运行
导入环境变量和显示环境变量:set environment和show environment
-batch选项。比如:打印$pid进程所有线程的堆栈并退出。
gdb -ex "set pagination 0" -ex "thread apply all bt" -batch -p $pid
run/r //运行程序
continue/c //中断后继续运行到下一个断点
step/s //单步执行,进入函数
si //单步执行汇编指令
next/n //单步执行,不进入函数
return //函数未执行完,忽略未执行的语句,返回
finish //函数执行完毕返回
call //调佣某一个函数
list/l //显示源码,①、list [起始行],[结束行]: ;②、list [行号]: ;
③、list [文件名]:[行号]/[起始行],[结束行]
call //调用某一个函数
whatis //查看变量类型
pwd //当前的工作目录
set directory //设置gdb的工作目录
help/h 命令 //查看指定命令的使用方法
quit //退出gdb调试
break/b //break [行号];break [函数名];break [行号]/[函数名] if[条件]
tbreak //设置临时断点,到达后删除,用法同上
condition 断点号 //修改对应断点的条件
info b //查看所设断点
delete/d //删除断点, delete/d [断点符号],如果不带编号则视为删除所有断点,
编号可以通过info b查
disable 断点号 断点号 //禁止一个多个断点,如果不带编号视为禁止全部编号
enable 断点号 断点号 //使能一个多个断点,如果不带编号视为使能全部编号
ignore 断点号 num //忽略对应断点num次
commond 断点号 //断点触发时,执行命令,一般用于打印变量
(gdb) command 1
Type commands for breakpoint(s) 1, one per line.
End with a line saying just "end".
>print x
>end
(gdb)
print/p //打印值,还可以跟函数返回p add(3,5),也可以打印寄存器的值 p $pc;
设置:
set print elements N //指定打印的长度,对长字符串特别有用。
set print element 0 //输出完整的字符串
set print pretty //设置GDB打印结构的时候,每行一个成员,并且有相应的缩进,缺省是关闭的
p /x xxx //16进制显示
p str@str_len
堆栈:
bt/info stack // 显示堆栈信息,bt N显示开头的N个栈帧,bt -N显示最后N个栈帧
frame/f N //显示第N层栈帧
info f/frame //列出栈帧信息,包含程序运行时死掉的PC指针、函数入口变量在栈中的位置、
接口中临时变量的地址、非法地址错误的起始值、连续多次输入可以查看每一层frame信息
info locals //列出程序异常处的局部变量及其值,还有在栈中的编译
info args //打印出当前函数的参数名及其值,还有在栈中的编译
info variables //列出所有的局部变量(按照文件顺序逐一列举)
info line:文件名:函数名 //展示文件中某函数的入口地址和结束地址(动态库则是偏移)
info registers //查看寄存器信息,i r t0 at//仅仅查看t0和at两个寄存器的值
info sym addr //打印符合信息
scope for:函数名 //查看函数中各个变量在栈中可能偏移值
disassemble 函数名 //查看函数的汇编代码
只能在程序启动后设置,现在main处设置断点,让程序启动后暂停在main处。
watch //为表达式(变量)expr设置一个观察点。一量表达式值有变化时,马上停住程序。
rwatch //当表达式(变量)expr被读时,停住程序。
awatch //当表达式(变量)的值被读或被写时,停住程序。
info watchpoints //列出当前所设置了的所有观察点。
经验:观察某个变量是否变化,被读或者被写,由于变量只在某一个作用域,可以获取变量的地址,然后观察。
比如:观察examined_rows变量神马时候被修改
(1).p &examined_rows,得到地址
(2).watch *(ha_rows *) 0x7ffec8005e28,则可以观察这个变量的变化情况
格式: x /nfu <addr> x 是 examine 的缩写
a.n表示要显示的内存单元的个数
b.f表示显示方式, 可取如下值
(1).x 按十六进制格式显示变量。
(2).d 按十进制格式显示变量。
(3).u 按十进制格式显示无符号整型。
(4).o 按八进制格式显示变量。
(5).t 按二进制格式显示变量。
(6).a 按十六进制格式显示变量。
(7).i 指令地址格式
(8).c 按字符格式显示变量。
(9).f 按浮点数格式显示变量。
c.u表示一个地址单元的长度
(1).b表示单字节,
(2).h表示双字节,
(3).w表示四字节,
(4).g表示八字节
比如:x/3xh buf
表示从内存地址buf读取内容,3表示三个单位,x表示按十六进制显示,h表示以双字节为一个单位。
info threads //查看线程
thread/t thread_no //切换到线程号
thread apply all command //所有线程都执行命令打印栈桢
比如:thread apply all bt //所有线程都打印栈桢
(1)线程锁
show scheduler-locking
set scheduler-locking on
set scheduler-locking off
默认是off,当程序继续运行的时候如果有断点,那么就把所有的线程都停下来,直到你指定某个线程继续执行(thread thread_no apply continue).
但是如果直接在当前线程执行continue的话,默认是会启动所有线程。这种模式有一种副作用,如果多个线程都断在同一个函数,这时候调试会出问题。
这个时候需要打开线程锁,但打开线程锁,意味着其它线程不能运行了。
(2)non-stop模式(7.0以后的版本支持)
set target-async 1
set pagination off
set non-stop on
gdb启动了不停模式,除了断点有关的线程会被停下来,其他线程会执行。
(1).singal 发送信号
假定你的程序已将一个专用的 SIGINT(键盘输入,或CTRL-C;信号2)信号处理程序设置成采取某个清理动作,
要想测试该信号处理程序,你可以设置一个断点并使用如下命令:
(gdb) signal 2
(2).handle 拦截信号
Handle命令可控制信号的处理,他有两个参数,一个是信号名,另一个是接受到信号时该作什么。几种可能的参数是:
* nostop 接收到信号时,不要将它发送给程序,也不要停止程序。
* stop 接受到信号时停止程序的执行,从而允许程序调试;显示一条表示已接受到信号的消息(禁止使用消息除外)
* print 接受到信号时显示一条消息
* noprint 接受到信号时不要显示消息(而且隐含着不停止程序运行)
* pass 将信号发送给程序,从而允许你的程序去处理它、停止运行或采取别的动作。
* nopass 停止程序运行,但不要将信号发送给程序。
比如:
handle SIGPIPE stop print //截获SIGPIPE信号,程序停止并打印信息
handle SIGUSR1 nostop noprint //忽略SIGUSR1信号
在调试器中运行以下命令记录信息:
set logging file mybacktrace.txt
set logging on
你可能会发现关闭分页有帮助,对于长的回溯,这样可以节省时间
set pagination off
现在运行回溯:
thread apply all bt full
参考文章:https://www.percona.com/blog/2011/08/26/getting-mysql-core-file-on-linux/?