一、启动
1、gdb <program>
当以gdb <program>
方式启动gdb后,gdb会在PATH路径和当前目录中搜索<program>
的源文件。如要确认gdb是否读到源文件,可使用l或list命令,看看gdb是否能列出源代码。
使用(gdb)r或run命令运行程序。
2、调试在线进程
(1)启动gdb时链接目标进程
在启动gdb的时候,通过参数-p指定目标进程,就可以进入调试状态。刚链接成功后,程序是暂停运行状态,你可以进行设置断点等操作,然后输入(gdb) c 命令继续运行。命令如下:
>gdb -p <PID>:PID是进程ID,可以通过`>ps aux | grep <程序名> `获得。
或者直接 >gdb -p `pidof <程序名>` 也可以。
(2)gdb中链接目标进程:
(gdb) attach <PID>
(3)断开链接:
(gdb) detach
二、信息显示
1、栈信息
不管是操作转储文件还是用gdb设置断点进行调试,都可以输入(gdb)bt打印栈内容进行查看。一般的当机BUG,看下当机的位置,然后看下源代码基本就可以解决了。但是很多情况下简单的(gdb)bt还查不到问题,这时候就要涉及到比较复杂的操作。下面罗列了一些对栈的操作:
(gdb) bt:显示所有栈帧,backtrace。
(gdb) bt 10:显示前面10个栈帧。
(gdb) bt -10:显示后面10个栈帧。
(gdb) bt full:显示栈帧以及局部变量。
(gdb) bt full 10:显示前面10个栈帧以及局部变量。
(gdb) bt full -10:显示后面10个栈帧以及局部变量。
(gdb) frame <栈帧编号>:进入指定的栈帧中,然后可以查看当前栈帧中的局部变量,以及栈帧内容等信息。
(gdb) info frame <栈帧编号>:可以查看指定栈帧的详细信息。
(gdb) up:进入上层栈帧。
(gdb) down:进入下层栈帧。
2、变量
调试BUG过程中查看变量信息是很有帮助的操作,查看方式如下:
(gdb) p <变量名>
(gdb) set variable <变量> = <表达式>:将变量的值设定为指定表达式的值。例如 set variable x=10
(gdb) print <变量> = <表达式>:查看并修改变量
3、寄存器
对于调试来说寄存器中的值也很重要,可以查看到当前正在执行的指令的地址等。具体操作罗列如下:
(gdb) `info reg`:显示所有寄存器。可以简写为:i r。如果要查看具体的寄存器可以这样:`i $ebx`
(gdb) `p $eax`:显示eax寄存器内容。
(gdb) `p/c $eax`:用字符显示eax寄存器内容
反斜杠后面的是显示格式,可使用的格式见下表:该表在显示内存内容的x命令中也是通用的。
格式 | 说明 |
---|---|
x | 显示为十六进制数 |
d | 显示为十进制数 |
u | 显示为无符号十进制数 |
o | 显示为八进制数 |
t | 显示为二进制数 |
a | 显示为地址 |
c | 显示为字符(ASCII) |
f | 显示为浮点小数 |
s | 显示为字符串 |
i | 显示为机器语言(仅在显示内存的x命令中可用) |
4、内存
可以查看具体内存地址中的内容,比如:目前执行的汇编指令,以及栈中内容等。
(gdb) `x $pc`:显示程序指针指向位置的内容。
(gdb) `x/i $pc`:显示程序当前位置的汇编指令。
(gdb) `x/10i $pc`:显示程序当前位置开始往后的10条汇编指令。
(gdb) `disassem $pc`:反汇编当前函数。简写为:`disas $pc`。
5、源代码
(gdb) `list <linenum>`:显示程序第linenum行的周围的源程序。
(gdb) `list <function> `:显示函数名为function的函数的源程序。
(gdb) list :显示当前行后面的源程序。
(gdb) list - :显示当前行前面的源程序。
6、显示格式
(gdb)set print pretty on:如果打开printf pretty这个选项,那么当gdb显示结构体时会比较漂亮。
(gdb)set print array on:打开数组显示,打开后当数组显示时,每个元素占一行,如果不打开的话,每个元素则以逗号分隔。
三、断点
1、设置断点
(gdb) break <函数名>:对当前正在执行的文件中的指定函数设置断点。可简写为:(gdb) b <函数名>
(gdb) break <行号>:对当前正在执行的文件中的特定行设置断点。可简写为:(gdb) b <行号>
(gdb) break <文件名:行号>:对指定文件的指定行设置断点。最常用的设置断点方式。可简写为:(gdb) b <文件名:行号>
(gdb) break <文件名:函数名>:对指定文件的指定函数设置断点。可简写为:(gdb) b <文件名:函数名>
(gdb) break <+/-偏移量>:当前指令行+/-偏移量出设置断点。可简写为:b <+/-偏移量>
(gdb) break <*地址>:指定地址处设置断点。可简写为:b <*地址>
(gdb) tbreak <函数名>:设置临时断点,只生效一次。可简写为:(gdb) tb <函数名>
2、 查看、删除断点
(gdb) info break :显示所有断点以及监视点。可简写为:(gdb) i b
(gdb) delete <编号>:删除编号指向的断点或者监视点。可简写为:(gdb) d <编号>
(gdb) clear <行号>:删除改行的断点。
(gdb) clear <文件名:行号>:删除改行的断点。
3、设置无效、有效断点:
(gdb) disable <断点编号> : 当前断点设置为无效。
(gdb) enable <断点编号>:当前断点设置为有效。
4、条件断点
在调试程序过程中,有时候我们只想在某个条件下停止程序,然后进行单步调试,而条件断点就是为此而设计。下面是条件断点的操作方式:
(gdb) b <断点> if <条件表达式> : 例如:b main.cpp:8 if x=10 && y=10
(gdb) condition <断点编号>:删除该断点的条件。
(gdb) condition <断点编号> <条件表达式>:修改断点条件。例如:condition 1 x=10 && y=10
5、监视点
可以监视某个变量,在变量被访问或者被修改时程序会在当前点进入断点。删除,查看监视点的方式与断点相同。设置监视点方式如下:
(gdb) watch <表达式>:表达式发生变化时暂停。
(gdb) awatch <表达式>:表达式访问或者改变时暂停。
(gdb) rwatch <表达式>:表达式被访问时暂停。
(gdb) info watchpoints:列出当前所设置的所有观察点。
6、断点命令
每次断点发生时候,想要查看的变量很多时,如果每个变量都手动print则需要浪费很多时间。断点命令可以在断点发生时批量执行gdb命令。下面是断点命令的设置方式:
(gdb) commands <断点编号>
(gdb) >print x
(gdb) >print y
(gdb) >end
首先输入gdb命令commands <断点编号>然后回车,这时候会出现>提示符。出现>提示符后可以输入断点发生时需要执行的gdb命令,每行一条,全部输入完成后输入end结束断点命令。
四、其他
1、强制函数返回
如果你的调试断点在某个函数中,并还有语句没有执行完。你可以使用return命令强制函数忽略还没有执行的语句并返回。
return
return <expression>
使用return命令取消当前函数的执行,并立即返回,如果指定了,那么该表达式的值会被认作函数的返回值。
2、强制调用函数
call <expr>
表达式中可以一是函数,以此达到强制调用函数的目的。并显示函数的返回值,如果函数返回值是void,那么就不显示。
另一个相似的命令也可以完成这一功能——print,print后面可以跟表达式,所以也可以用他来调用函数,print和call的不同是,如果函数返回void,call则不显示,print则显示函数返回值,并把该值存入历史数据中。