总结下gdb调试流程,当日志用。
流程:
1)带着调试选项编译(加-g),构建调试对象a.out($g++ -Wall -o2 -g ./a.cpp,如果使用到TSD等还需要加编译选项-lpthread)
2.1)启动gdb(开始运行指定程序并调试$gdb ./aout、attach到正在运行的进程并调试$gdb -p `pidof a.out`,gdb -tui分屏显示源代码)
2.2)source ./mygdbinit (载入gdb命令脚本文件mygdbinit,等效$gdb --commonds=./.mygdbinit)
2.3)开始gdb(run:直接运行、start:设置main断点再运行,start 10 20 30:发送3个参数给执行程序的main函数)
3.1)设置断点(一般<函数、行、地址、下行、偏移量、汇编机器指令行等>断点、内存断点、条件断点等:b,watch,awatch,rwatch,注意区别:b fun和b *fun的不同)
3.2)显示所有断点(info b)
3.3)删除断点(delete 断点编号、clear 详细断点、delete:删除所有断点,等)
4.1)显示栈/栈帧(bt、bt N、bt -N、bt full、bt full N、bt full -N等,注:一个进程对应call-stack调用栈,一个函数对应stack-frame栈帧,显示栈帧:info frame,)
4.2)显示汇编代码(显示指定函数的反汇编代码:disas main、disas funname,)
5.1)显示值(pc命令行、ebp栈底指针、esp栈顶指针,以及各种寄存器值,struct结构变量值、Json结构变量值、一般变量variable值,class/struc结构对象指针this,再特殊的结构变量可以自己写gdb命令脚本来显示等)
5.2)显示指定程序地址的源代码(list <*addr>:x/i $pc,list *$pc等)
5.3)显示指定行货函数的源代码(list filename:lineNum,list filename:funname,多文件时必须加文件名)
5.4)列出指定区域的代码(list line1Num, line2Num)
5.5)显示main函数的参数列表(show args)
5.6)显示info命令的其他使用(显示寄存器:info reg,显示三个寄存器的value:info r rbp rsp rip,显示当前函数的栈帧信息:info frame,显示当前调用文件的信息:info source,显示当前运行进程的信息:info proc,显示所有gdb设置:info set,显示当前所有的线程:info threads,显示所有的type名:info types,显示程序的输入参数列表信息:info args、显示当前代码块内部的局部变量:info local,显示所有自动显示设置:info desplay,info files、info proc mapping等)
5.7)显示当前绝对路径(pwd)
5.8)显示可执行文件的所有内存段起始范围(info file)
5.9)addr2line(由代码命令行地址 得到 代码命令行源代码)
6.1)改变变量值(set:修改指定variable的值)
6.2)修改main函数的参数列表(set args 11 12 13)
7)继续执行(next、step、nexti、stepi,jump、return、call、continue、finish、until:代码级别执行,汇编级别执行,进入callee内部执行、跳跃式执行finish/until:untile addr执行到"addr"后暂停)
8.1)查找gdb命令(complete:列出所有gdb命令,complete a:列出所有a开头的gdb命令等)
8.2)gdb命令行查看(ctrl-n看次新gdb命令、ctrl-p逐个看gdb的历史命令)
8.3)在当前文件查找表达式(search a:在当前文件向下查找指定变量a或者表达式a,注:reverse-search a:是向上查找)
8.4)将当前目录下的dir1子目录放入被搜索目录群中(dir dir1)
8.5)进入dir1(cd dir1)
9.1)讲一个信号发送给正在运行的程序(single 0 等效于 continue)
10.1)附着到指定进程(attach 1920、attach `pidof ./other.out`)
10.2)切换到指定线程(thread 20167或者t 20167)
11)终止一个正在调试程序(kill命令)
注:
1)在带着调试选项(-g)编译时,在需要查看变量详细数值时,不要加优化选项,如-o2等。
如果加了优化现象进行编译,可能在gdb调试时显示值时出现
2)对于上面的mygdbinit简单的一个示例如下所示:
#mygdbinit
b 'main.cpp':main #文件名要用单引号括起来''
commands
silent
printf "hello worl" #此处打印一句话,还可以显示信息、设置变量值等等各种gdb命令操作,如下
printf "rbp=%p\n", $rbp #64位的时rbp,32位的机器可能是ebp
printf "rsp=%p\n", $rsp
printf "rip=%p\n", $rip #显示当前命令行的存储地址
continue
end
3)虽然nm、objdump、strace、pstack、pstree、ptrace、top、ps、ulimit、env MALOC_CHECK_=1、flint、valgrind、mtrace、lsof、pidstat、perf(record,top、report、list等)等等,这些虽然不是gdb命令,但是都是优化程序、调试程序的好工具,后续会增加文章进行简介。
4)应该漏掉的其他的gdb流程。
5)如果熟悉了以上流程,最明显的一个效果是:发现以前加printf-->编译---->运行---->信息不够再加printf/或者设置新的变量值--->再编译-->再运行,这样的操作是很快被放弃。
(完)