GDB是Unix下的一个程序调试工具,类似于windows下面的VC调试器,区别在于GDB采用全命令行控制。
使用GDB需要在编译时使用-g选项,gcc支持-g –O选项同时使用,但如果还在调试阶段,尽量不要-O2,也不要删除(strip)符号表。作用如下:
让程序按照自己定义的要求运行,不必每次改变程序
让程序在设置的断点处停住,并且检查程序的执行情况
动态改变程序的执行环境
一、启动调试
gdb <program> 启动程序进行调试
gdb ./bin/chat_server
gdb --args ./bin/chat_server -c conf/cache_server.conf
在 UNIX 下用 ps 查看正在运行的程序的 PID (进程 ID), 然后用 gdb <program> PID 格式挂接正在运行的程序。
gdb attach <pid> 调试一个已经运行服务程序
gdb ./bin/chat_server $(pgrep chat_server)
gdb <program> core 调试程序core down时候产生的core文件
gdb ./bin/chat_server core
Attach到后台进程,将操作预先输入好,避免影响程序正常运行
sudo gdb ./bin/chat_server `pgrep chat_server` <<END
b HandleAccept
c
p (char *)inet_ntoa(pstSctx->stClientAddr.sin_addr)
p ntohs(pstSctx->stClientAddr.sin_port)
quit
END
二、gdb基础命令
三、gdb常用操作补充
1. ulimit -c unlimited; 调试core文件
bt/where/info s 显示函数调用堆栈
up n 向调用链根部移动n个函数
down n 向调用链叶部移动n个函数
f n 选择函数调用链上编号为n的函数,0表示当前函数
info files 显示core文件里面的segment映射
如果core文件函数调用栈乱掉,可以参照 http://devpit.org/wiki/x86ManualBacktrace 恢复堆栈。
2. 设置观察点
watch <expr> expr 值变化时,停止程序
rwatch <expr> expr 值被读时,停止程序
awatch <expr> expr 值被读或被写时,停止程序
info watchpoints 查看当前观察点信息
3.反汇编
set disassembly-flavor intel # 设置反汇编格式
disassemble可以反汇编当前函数或者指定的函数,单独用disassemble命令是反汇编当前函数,如果disassemble命令后面跟函数名或地址则反汇编指定的函数。
4.前面讲过step命令可以一行代码一行代码地单步调试,而这里用到的si/ni命令可以一条指令一条指令地单步调试。
info registers可以显示所有寄存器的当前值。在gdb中表示寄存器名时前面要加个$,例如p $esp可以打印esp寄存器的值,如esp寄存器的值是0xbff1c3f4,所以x/20 $esp命令查看内存中从0xbff1c3f4地址开始的20个32位数。
5. p 命令内存输出格式:
? d: ?十进制
? u: ?十进制?无符号
? x: ?十六进制
? o: ?八进制
? t: ?二进制
? c: 字符
如 p/x var
6. set listsize 50 修改源代码显示行数; 此外还有set args 设置参数;set var 设置变量值
7.设置位置断点,设置断点命令b (break的简写)
b linenum
b function
b filename:linenum
b filename:function
b *address
b if <condition>
8. 查看当前运行信息
info b <breakpoints> breakpoints 为设置的断点的标号
info args/frame/locals/line filename:function
info line 配合disassemble使用可查看程序汇编代码
其中info frame 显示的当前堆栈信息比frame详细,可以先用frame num 切换堆栈,where/info s/bt 可以查看堆栈调用链
9. 条件式中断 b test if a == 10 类似 condition 4 a == 30 (4 是bk num)
10. 删除断点可以使用 clear和d(delete的简写)
clear删除断点, 使用方法和b命令类似
d [breakpoints] breakpoints 为设置的断点的标号
10. 启动和查看程序
setargs 设置程序运行参数
run运行程序,使用方式如:r <args>
List 显示程序源代码命令,使用show listsize 查看显示代码的行数
list <function/linenum/filename:function/filename:linenum/-/+> ,-向上翻动,+向下翻动
p var/expression(filename::var/function::var),打印变量值
11. 恢复运行程序和单步调试程序
continue,继续运行程序
next <count> 单步跟踪,遇到函数不进入函数
step <count> 单步跟踪,遇到函数会进入该函数
finish 直到函数运行完成,打印函数信息
until 在循环体内跟踪程序,直到整个循环结束
12. x 命令可以显示指定地址的内存数据。
格式: x/nfu [address]
? n: 显示内存单位 (组或者行)。
? f: 格式 (除了print 格式外,还有字符串s 和 汇编i)。
? u: 内存单位 (b: 1字节; h: 2字节; w: 4字节; g: 8字节)。
x/8w 0x0804843b # 按四字节(w)显示 8组内存数据
x/8i 0x0804843b # 显示8 行汇编指令
13. 进程与线程
info proc mappings # 相当于 cat /proc/{pid}/maps 查看maps内存数据
可以在 pthread_create 处设置断点,当线程创建时会生成提示信息。[New Thread 0xb7e78b70 (LWP 2933)]
info threads # 查看所有线程列表
where # 显示当前线程调用堆栈
thread num # 切换线程 [Switching to thread 1 (Thread 0xb7e796c0 (LWP 2932))]#0 0xb7fe2430 in __kernel_vsyscall ()
14. 其他零散
调试子进程。
(gdb) set follow-fork-mode child
临时进入Shell执行命令,Exit返回。
(gdb) shell
调试时直接调用函数。
(gdb) call test("abc")
使用 "--tui" 参数,可以在终端窗口上部显示一个源代码查看窗。
$ gdb --tui hello
查看命令帮助。
(gdb) help b
最后就是退出命令。
(gdb) q
和Linux Base Shell习惯一样,对于记不住的命令,可以在输入前几个字母后按Tab补全。
经验:如果某个函数的局部变量发生访问越界,有可能并不立即产生段错误,而是在函数返回时产生段错误。
参考:
《linux c 编程一站式学习》
《C 学习笔记》 by雨痕