编译
调试信息
要想用gdb编译,必须用编译参数 -g 和 -ggdb 让 gcc 生成调试信息:
-g:该选项可以利用操作系统的原生格式(native format)生成调试信息,GDB 可以直接利用这个信息,其它调试器也可以使用这个调试信息;
-ggdb:为GDB 生成专用的更为丰富的调试信息,但是此时就不能用其他的调试器来进行调试了。
gcc优化
gcc提供了大量优化等级,用来对编译时间、目标文件大小、执行效率三个维度进行不同的取舍和平衡。
命令 | 说明 |
---|
-O0 | 最少的优化(默认的编译选项),可以最大程度上配合产生代码调试信息,可以在任何代码行打断点 |
-O 或 -O1 | 有限优化,编译时占用稍微多的时间和相当大的内存,减少代码生成尺寸、缩短执行时间,去除无用的 inline 和无用的 static 函数、死代码消除等,在影响到调试信息的地方均不进行优化,在适当的代码体积和充分的调试之间平衡,代码编写阶段最常用的优化等级 |
-O2 | 高度优化,在 -O1 的基础上,采用几乎所有的目标配置支持的优化算法,用以提高目标代码的运行速度,但会牺牲部分编译速度,调试信息不友好,有可能会修改代码和函数调用执行流程 |
-O3 | 最大程度优化,在 -O2 的基础上,采取很多向量化算法,提高代码的并行执行程度,利用现代CPU中的流水线,Cache等,目标:拼命提高运行速度,那怕增加目标代码的大小 |
-Os | 相当于 -O2.5,在-O2的基础之上,尽量的降低目标代码的大小 |
编译总结
要想编译出调试用的可自行文件,编译时必需要调试参数 -g 或-ggdb;优化最好只用-O0,或-O1,再之上的就很不利于调试了,无足够的编译信息,由于优化代码的执行顺序也变了。
运行&退出
运行启动gdb的方式有:
(1) gdb program program为要执行的二进制文件;
进入gdb后,运行命令:set args [args] 添加运行参数,在用命令run直接运行程序;
(2) gdb pid pid为正在运行程序的进程id,gdb将attach到正在运行的程序;
或者先运行gdb:gdb, 再用命令 attach pid 进行调试。
(3) gdb program core 通过core文件查看调试程序;
通过方式(1)进入gdb后,可以通过 set args 指定程序运行的参数,show args 查看当前运行命令参数。
gdb退出
在命令行键入:quit,然后回车。
常用命令详解
断点命令
命令 | 说明 |
---|
break function | 在指定函数的进入点设置中断点, c++可以用class::function或function(type,type)格式来指定函数名 |
break filename:function | 在源文件filename中的function函数入口点设置中断点 |
break filename:linenum | 在源文件filename的linenum行处设置中断点 |
break args if cond | cond为真时, 在 break args 设置的断点处触发中断 |
tbreak args | 只会生效一次的中断点 |
info break [n] | 查看断点 |
clear [args] | args 为(文件名)行号或函数名,无参数表示清除所有 |
delete [args] | args 为断点号,无参数表示删除所有 |
disable [args] | args 为断点号,无参数表示disable所有 |
enable [args] | args 为断点号,无参数表示enable所有 |
condition bnum expr | 修改断点号为 bnum 的停止条件为 expr |
condition bnum | 清除断点号为 bnum 的停止条件 |
ignore bnum count | 忽略断点号为 bnum 的停止条件 count 次 |
观察点命令
命令 | 说明 |
---|
watch expr | 设置观察点,在变量或表达式expr的值有变化时,马上停住程序 |
rwatch expr | 在变量或表达式expr的值被读时,马上停住程序 |
awatch expr | 在变量或表达式expr的值被读或写时,马上停住程序 |
info watchpoints | 列出当前设置的所有观察点 |
多线程相关命令
命令 | 说明 |
---|
info threads | 查看线程 |
threads threadNo | 进入指定的线程 |
break [args] thread threadNo | 指定某线程中的断点 |
break [args] thread threadNo if cond | 指定某线程中的条件断点 |
set scheduler-locking on/step/off | 锁定当前线程/单步锁定当前线程/解除锁定 |
show scheduler-locking | 显示当前线程锁定模式 |
操作变量内存相关命令
命令 | 说明 |
---|
file::variable | 文件中的某个全局变量 |
function::variable | 函数中的某个局部变量 |
数组名@len | len 要查看的长度 |
whatis value | 显示变量value的值和类型 |
ptype value | 显示变量value的类型 |
set [var] value = xx | 设置变量的值,如: set nval=54 将把54保存到nval变量中,[var] 告诉gdb 之后操作的是变量 |
print x = 4 | 修改变量x的值为4 |
examin(x)/nfu addr | 查看内存, 如: x/3uh 0x54320 表示,从内存地址 0x54320 读取内容,h 表示以双字节为一个单位,3 表示三个单位,u 表示按十六进制显示 |
栈相关命令
命令 | 说明 |
---|
backtrace(bt) | 查看函数调用栈信息 |
frame(f) num | 查看第num层栈信息 |
info args | 打印当前函数的参数名及值 |
info locals | 打印当前函数的所有局部变量及值 |
多进程相关命令
命令 | 说明 |
---|
set follow-fork-mode parent/child | 调试父进程/子进程 |
show follow-fork-mode | 查看当前调试的fork的模式 |
detach-on-fork on/off | 只调试父进程或子进程其中一个,需要根据follow-fork-mode决定/父子进程都在gdb的控制之下,其中一个进程正常调试,需要根据follow-fork-mode决定,另一个进程会被设置为暂停状态 |
info inferiors | 显示GDB调试的所有inferior(每一个被调试程序的执行状态记录在一个名为inferior的结构中,一般情况下一个inferior对应一个进程),GDB会为他们分配ID,其中带有*的进程是正在调试的inferior |
set schedule-multiple on/off | 只有当前inferior会执行/全部是执行状态的inferior都会执行 |
set follow-exec-mode new/same | 在执行exec的inferior上控制子进程/新建一个inferior给执行起来的子进程,而父进程的inferior仍然保留 |
show follow-exec-mode | 查看follow-exec-mode设置的模式 |
set print inferior-events on/off | 打开/关闭inferior状态的提示信息 |
show print inferior-events | 查看print inferior-events设置的状态 |
其他调试命令
命令 | 说明 |
---|
run | 运行你的程序 |
quit | 退出gdb |
continue© | 继续执行直到下一个停止点 |
step(s) | 单步调试下一步,会进入函数 |
next(n) | 单步调试下一步,不会进入函数 |
ni/si | 下一条指令,进入函数/不进入函数 |
finish | 运行程序,直到当前函数完成返回。并打印函数返回时的堆栈地址和返回值及参数值等信息 |
until(u) | 执行一行程序,若此时程序是在 for/while/do loop 循环的最后一行,则一直执行到循环结束后的第一行程序后停止 |
set/show args | 设置/显示运行参数 |
print§ value | 打印变量value |
list | 列出产生执行文件的源代码的一部分 |
ctrl + c | 在当前位置停止执行正在执行的程序,断点在当前行 |
info line ars | args:行号,函数名,文件名:行号,文件名:函数名; 打印出所指定的源码在运行 |
时的内存地址 | |
disassemble | 查看代码的汇编 |
其他信息
对应的pdf文档可在我的博客免费下载,同时也提供gdb的官方手册的pdf下载。