gdb调试命令
# 重要说明
(1) 使用GCC进行编译时,需在编译选项中加入"-g"参数
cc -g main.c -o main
g++ -g main.cpp -o main
(2) 使用GCC进行编译时,为了能使指令与源代码对应上,编译选项中不要加入启用优化的"-O"参数
(3) 使用gdb调试前,要先进入待调试模块所在目录(使得能正确关联到源代码文件)
(4) 进入gdb调试状态,直接回车表示"重复上一次命令"
(5) 按上下方向键可以浏览和选择以前输入过的命令
(6) gdb中,输入命令时,可以不用打全命令,只用打命令的前几个字符就可以了,当然,命令的前几个字符应该要标志着一个唯一的命令。
在Linux下,你可以敲击两次TAB键来补齐命令的全称,如果有重复的,那么gdb会把其列出来
(7) 可从这儿下载最新的gdb [http://www.gnu.org/software/gdb/download/]
# 调试进程
gdb test // 调试当前目录下的名为test的可执行程序 输入r,运行程序
gdb -p PID // 勾住目标进程进行调试 PID为目标进程ID,可通过ps -ux来查看当前运行的进程
attach 2146 // 附加到PID为2146的进程上
detach 2146 // 释放对PID为2146进程的调试
q // 结束gdb调试 [quit]
# 启动额外参数
-se symbolfile // 从指定文件中读取符号表信息,并用在可执行文件中
-c corefile // 调试core dump的core文件
如:gdb gamesvrd.0 -c /data/corefile/core_gamesvrd.0_11833_1358767740 // 需要进入gamesvrd.0的目录
-d directory // 加入一个源文件的搜索路径 默认搜索路径是环境变量中PATH所定义的路径
若当前调试进程的可执行文件目录中有名为.gdbinit文件,在启动调试时会执行该脚本(下面为一个文件内容示例)
--------------
b YXSCubeData.cpp : 2653
c
--------------
# 调试
0. 程序参数
set args -b -x // 修改发送给程序的参数,将-b和-x参数发送给程序
show args // 显示程序当前的参数
1. 设置断点 [break]
b worker.cpp : 45 // 在worker.cpp文件的45行处设置一个断点
b 45 // 在当前文件的45行处设置一个断点
b worker.cpp : CWorker::DoWork // 在worker.cpp文件的DoWork函数起始处设置一个断点
------------------
若有命名空间,还应带上命名空间 b worker.cpp : MYPRJ::CWorker::DoWork
若函数被重载,还应带上参数类型 b worker.cpp : CWorker::DoWork(bool)
------------------
b +5 // 在距离当前位置的后5行处设置一个断点
b -6 // 在距离当前位置的前6行处设置一个断点
b ... if <条件> // 条件断点
例:b worker.cpp : 45 if workerNum==5
例:b worker.cpp : CWorker::DoWork if workerNum==5
2. 查看断点 [info breakpoints]
i b // 查看当前所有断点(每个断点都有一个编号)
3. 禁用/启用断点
disable 1 // 禁用编号为1的断点
enable 1 // 启用编号为1的断点
disable // 禁用所有断点
enable // 启用所有断点
4. 删除断点 [delete breakpoints]
d 1 // 删除编号为1的断点
d // 删除所有断点
5. 调试执行控制
r // 调试启动进程 [run]
k // 结束当前调试的进程 [kill]
c // 继续运行 [continue] 相当于vc中的F5
ctrl+c // 暂停程序运行
n // 单步执行 [next] 相当于vc中的F10
n 2 // 2为步进数目
s // step into到函数内部 相当于vc中的F11
finish/fin // step out出函数 相当于vc中的shift+F11
u // 当你厌倦了在一个循环体内单步跟踪时,这个命令可以运行程序直到退出循环体 [until]
u 145 //执行至145行代码停下
6. 查看变量 [print]
p nSum // 打印nSum变量的值
p /fmt nSum // 按指定格式打印nSum变量的值
------------------
fmt为以下值
x 十六进制 d 十进制
u 无符号数 o 八进制
t 二进制 a 十六进制打印【地址】
c 字符格式 f 浮点数 s 字符串
------------------
p h@10 // 查看数组h的前10个值
p *bar // 查看指针bar所指对象内容
whatis nSum // 查看变量nSum的类型
ptype foo // 查看foo的类型定义
w exp // 查看表达式exp的值 [watch]
7. 修改变量
p x=4 // 将x的值修改为4
8. 查看内存
x/<n/f/u> <addr>
n、f、u是可选的参数。
n 是一个正整数,表示显示内存的长度,也就是说从当前地址向后显示几个地址的内容。
f 表示显示的格式,参见【6.查看变量fmt的说明】。如果地址所指的是字符串,那么格式可以是s,如果地址是指令地址,那么格式可以是i。
u 表示从当前地址往后请求的字节数,如果不指定的话,GDB默认是4个bytes。
u参数可以用下面的字符来代替,b表示单字节,h表示双字节,w表示四字节,g表示八字节。
当我们指定了字节长度后,GDB会从指内存定的内存地址开始,读写指定字节,并把其当作一个值取出来。
如:x/3uh 0x54320EED
// 从内存地址0x54320EED读取内容,h表示以双字节为一个单位,3表示三个单位,u表示按十六进制显示。
9. 其他调试信息查看
bt // 查看堆栈调用 [backtrace]
-------------------------------------------------
有时我们通过bt命令,看到的堆栈信息是错乱的(一堆的???),如下:
针对这种情况,可以采用以下方法来查看堆栈:
(1) 从ebp获取函数调用堆栈的head指针
(2) 显示堆栈的heard指针内存块的内容
(3) 对当前函数返回地址执行info symbol命令,打印出当前函数栈帧信息(含函数名)
## 完整的例子:
-------------------------------------------------
frame 3 // 跳转到函数堆栈中索引为3的函数上下文
i reg // 显示寄存器信息 [info]
i func // 显示所有的函数名
i local // 显示当前函数的所有局部变量的信息
i prog // 显示调试程序的执行状态
10. 代码载入 [程序必须被断点断住]
Ctrl+ x Ctrl + a // 将代码载入到命令行中进行调试
l // 载入当前代码行的前后各4行代码 [list]
l 45 // 显示当前文件按第45行的周围代码
l worker.cpp : 70 // 显示work.cpp第70行的周围代码
l worker.cpp : sum // 显示work.cpp中sum函数的周围代码
l CWorker::DoWork(bool) // 显示函数名为CWorker::DoWork(bool)的函数的代码
l 0xabcd1234 // 查看地址为0xabcd1234的周围的代码
11. 多线程
i threads // 显示线程信息
thread 2 // 切换到线程表中索引为2的线程
b foo 2 // 在函数foo设置断点,并且只在索引为2的线程中命中
12. 强制操作
call A(1,2) // 强制调用函数A,并输出其返回值
return // 使用return命令取消当前函数的执行,并立即返回
return exp // 如果指定了exp,那么该表达式的值会被认作函数的返回值
参考
更详细请参考:用GDB调试程序(一) 用GDB调试程序(二) 用GDB调试程序(三)