文章目录
GDB官网参考
一、GDB配置文件
当gdb启动时,会读取HOME
目录和当前目录下的的配置文件,执行里面的命令。配置文件名通常为.gdbinit
,一些常用配置如下所示:
# 打印STL容器中的内容
python
import sys
sys.path.insert(0, "/home/xmj/project/gcc-trunk/libstdc++-v3/python")
from libstdcxx.v6.printers import register_libstdcxx_printers
register_libstdcxx_printers (None)
end
# 保存历史命令
set history filename ~/.gdb_history
set history save on
# 退出时不显示提示信息
set confirm off
# 按照派生类型打印对象
set print object on
# 打印数组的索引下标
set print array-indexes on
# 每行打印一个结构体成员
set print pretty on
gdb支持的脚本文件分为两种:一种是只包含gdb自身命令的脚本,例如.gdbinit
文件,当gdb在启动时,就会执行.gdbinit
文件中的命令;此外,gdb还支持其它一些语言写的脚本文件(比如python)。
gdb用set script-extension
命令来决定按何种格式来解析脚本文件。它可以取3个值:
off
:所有的脚本文件都解析成gdb的命令脚本;soft
:根据脚本文件扩展名决定如何解析脚本。如果gdb支持解析这种脚本语言(比如python),就按这种语言解析,否则就按命令脚本解析;strict
:根据脚本文件扩展名决定如何解析脚本。如果gdb支持解析这种脚本语言(比如python),就按这种语言解析,否则不解析;
写一个脚本文件(gdb.py
),但内容是一个gdb命令,不是真正的python脚本。用途是退出gdb时不提示:
# gdb.py
set confirm off
然后在gdb中按顺序执行以下命令:
# 查看script-extension的值,默认值是soft
show script-extension
# 因为soft会按照pyhton语言解析gdb.py文件,但是这个文件实质上是一个gdb命令脚本,所以解析会出错
set script-extension off
# 正确解析gdb.py文件,配置生效
source gdb.py
二、启动程序/挂载进程
gdb [-tui] [execut_file] [| tee log_file]
,启动gdb
-tui
选项,启动可以直接将屏幕分成两个部分,上面显示源代码;
tee
命令可以将gdb调试时显示的所有信息输出到指定的文件中。gdb attach pid
,调试正在运行的进程// 查找所有正在运行的进程,筛选出名字中带有luarocks的,在筛选结果中剔除名字中带有auto的 // 找出筛选结果的第二列,作为gdb attach 后面跟的参数 gdb attach `ps -ef | grep "luarocks" | grep -v "auto" | awk '{print $2}'`
run
,简写r
:运行被调试的程序。如果此前没有下过断点,则执行完整个程序;如果有断点,则程序暂停在第一个可用断点处start
,开始调试,停在第一行代码处gdb -args ./a.out arg1 arg2 ...
,启动时设置被调试程序的参数
set args <value1 value2 ...>
,修改发送给程序的参数(run后面跟的参数)## 也可以采用以下方式设置被调试程序的参数 gdb ./a.out set args arg1 arg2 ... ## 还可以 gdb ./a.out start arg1 arg2 ...
三、改变变量和控制流程
set var <assignment>
,修改指定变量的值# assignment的语法跟随调试语言本身(= 、:=) set var i = 10 # 也可以只用set,但可能会存在变量名(i)与gdb参数冲突的情况(print、args) # 所以最好还是用set var set i=10
set <reg-name = expr>
,修改该指定寄存器中的值,如set $pc = 100
、set $r1 = 0
set [*|*(type*)|{type}]address = value
,修改指定地址处的值,如给存储地址在address,变量类型为type的变量赋值# 根据地址修改字符串的值 (gdb) p &p1 $1 = (char (*)[4]) 0x80477a4 (gdb) set {char [4]} 0x80477a4 = "Ace" # 根据地址修改变量的值,有三种方式可选择 (gdb) p &i $2 = (int *) 0x8047a54 (gdb) set *0x8047a54 = 8 (gdb) set *(int *)0x8047a54 = 8 (gdb) set {int}0x8047a54 = 8
- 使用修改指定地址处的值,修改二进制文件中的指令,永久生效。
# 缺省情况下,gdb是以只读方式加载程序的。可以通过以下命令行选项指定为可写 gdb -write ./a.out # 或者 (gdb) set write on (gdb) file ./a.out # 将函数fun-name的每一行源码与其汇编指令和指令的具体值对应显示 disassemble /mr fun-name # 修改二进制代码(注意大小端和指令长度) # 如将0x0000000120000760处的指令改为:andi $r0,$r0,0x0 set *0x0000000120000760=0x03400000 set variable *(int*)0x0000000120000760=0x03400000 set {int}0x0000000120000760=0x03400000
next
,简写n
:执行一行源程序代码,此行代码中的函数调用也一并执行,(gdb) n
,(gdb) n line-number
step
,简写s
:执行一行源程序代码,如果此行代码中有函数调用,则进入该函数,(gdb) s
,(gdb) s line-number
没带调试信息的函数无法step
进入(如系统库函数),但执行set step-mode on
即可。continue
,简写c
:继续执行被调试程序,直至下一个断点或程序结束,(gdb) c
,(gdb) c line-number
until [line-number]
,简写u [line-number]
:可以指定程序运行到某一行停下来,如当前程序停在第10行,使用(gdb) u 23
,则快速执行完中间代码,在23行停下来finish
,执行完当前函数的所有语句,然后正常退出该函数return [expression]
,立即结束当前正在执行的函数,不再执行函数的后面语句,并返回,expression是函数返回的值
四、打印表达式(变量)信息
-
print[/f|等] [var|ptr|addr]
,简写p[/f|等] [var]
:显示指定变量的值,(gdb) p [var]
,(gdb) p [&var]
,(gdb) p [ptr]
,(gdb) p [*ptr]
,(gdb) p/x [var]
,参考自print打印。
其中f
表示显示方式, 可取如下值:
x
按十六进制格式显示变量
d
按十进制格式显示变量
u
按十六进制格式显示无符号整型
o
按八进制格式显示变量
t
按二进制格式显示变量
a
按十六进制格式显示变量
c
按字符格式显示变量
f
按浮点数格式显示变量
s
按字符串格式显示变量
打印数组前n个元素p *arr@n
,打印数组下标从m开始的n个元素p arr[m]@n
-
set print <opt>
,以指定的格式显示输出变量的值,在查看表达式(变量)信息时使用
set print address [on|off]
,打开地址输出,当程序显示函数信息时,GDB会显出函数的参数地址
set print array [on|off]
,打开数组显示,打开后当数组显示时,每个元素占一行,如果不打开的话,每个元素则以逗号分隔
set print elements [num|unlimited]
,指定数组显示的最大长度,,当到达这个长度时,GDB就不再往下显示了。如果设置为0,则表示不限制
set print null-stop [on|off]
,如果打开了这个选项,那么当显示字符串时,遇到结束符则停止显示。这个选项默认为off
set print union [on|off]
,设置显示结构体时,是否显式其内的联合体数据。
set print object [on|off]
,在C++中,如果一个对象指针指向其派生类,如果打开这个选项,GDB会自动按照虚方法调用的规则显示输出,如果关闭这个选项的话,GDB就不管虚函数表了
set print pretty [on|off]
,控制结构体输出格式,打开则会以如下形式显示:$1 = { next = 0x0, flags = { sweet = 1, sour = 1 }, meat = 0x54 "Pork" }
-
x /nfu <addr>
,查看指定内存中存放的值,addr
是个地址之,也可以用p *addr
,但是一次只能查看一个字节,没有x
好用
1)n
表示要显示的内存单元的个数
2)f
同上面print
指令中的f作用一样
3)u
表示一个地址单元的长度,可取如下值:
b
表示单字节
h
表示双字节
w
表示四字节
g
表示八字节 -
display [var]
,设置想要跟踪的变量,自动显示
display/[n]i $pc
,每次回到gdb命令行时,显示当前要执行的汇编指令,n为显示条数
info display
,简写i display
:显示所有跟踪变量
undisplay [varnum|varnum1-varnum2]
,取消禁用指定编号/范围的变量跟踪显示,(gdb) undisplay 1
disable display [varnum|varnum1-varnum2]
,禁用指定编号/范围的变量跟踪显示,(gdb) disable display 2-4
enable display [varnum|varnum1-varnum2]
,启用指定编号/范围的变量跟踪显示
delete display [varnum|varnum1-varnum2]
,删除指定编号/范围的变量跟踪显示 -
whatis [var]
和ptype [var]
,显示一个变量的类型
五、永久/条件/一次/自动断点操作
-
break
,简写b
:
b
,在下一条命令处停止运行
b [函数名]
,在某个函数的开始处设置断点,(gdb) b main
b [行号]
,在当前文件的指定行,(gdb) b 10
b [文件名:函数名/行号]
,指定文件的指定行
b [*address]
,在程序运行的内存地址处打断点
以上任意b命令 [if <cond>]
,cond
为true
时,指定位置打断点,(gdb) b 10 if i==12
-
rbreak [REGEX|FILE:REGEX].
,REGEX
是正则表达式,程序中函数的函数名只要满足REGEX
条件,rbreak
命令就会其内部的开头位置打断点。如在所有函数上面打断点(gdb) rbreak .
,在main.c
文件中的所有函数上面打断电(gdb) rbreak main.c:.
-
tbreak
,简写tb
,临时断点,只生效一次,如(gdb) tb main.c:10
-
watch
,一般来观察某个表达式(变量也是表达式)或内存地址的值是否发生了变化,如果发生变化则程序立即暂停,自动断点
watch [exp|*addr]
,为exp
设置一个观察点,如果其值变化,程序暂停,(gdb) watch a
,(gdb) watch *(int *) 0xffffff318c
rwatch [exp|*addr]
,exp
被读时,程序暂停
awatch [exp|*addr]
,exp
的值被读或被写时,程序暂停
info watchpoints
,列出当前所设置的所有观察点 -
ignore N COUNT
,让N
断点执行COUNT
后停下,也就是前COUNT - 1
次该断点不会起效(gdb) b lj_BC_JLOOP Breakpoint 3 at 0x12003b020 (gdb) ignore 3 316 Will ignore next 316 crossings of breakpoint 3.
-
info breakpoints
,简写i b
:查看所有断点信息 -
disable [break-num]
,禁用某一个断点 -
enable [break-num]
,启用某一个断点 -
delete [break-num]
,简写d [break-num]
:删除某一个断点 -
save breakpoints [file-name]
,将设置的断点保存下来,等需要时(退出gdb再进入也ok),使用命令source [file-name]
批量设置被保存的断点,保存和使用的[file-name]
一致既可
六、查看源码及其编译后的相关信息
list
命令,简写l
l
,显示当前行后面的代码
l [-]
,继当前显示向前再显示10行
l [行号]
,显示10行,指定行号处于中间位置
l [fun-name]
,显示指定函数名的上下文backtrace
,简写bt
:查看当前程序的调用堆栈
info frame
,简写i f
:查看当前栈帧信息
frame [num]
,简写f [num]
:切换到其他堆栈处,通常与bt
一起使用,(gdb) f 2
。也可以用up [num]
和down [num]
向上或向下选择函数堆栈帧,其中n是层数show args
,查看发送给程序的参数(run
后面跟的参数)info registers
,简写i r
:查看除了浮点寄存器以外的寄存器
info register [reg-name]
,简写i r [reg-name]
:查看指定寄存器reg-name
info all-registers
,简写: 查看所有的寄存器包括浮点寄存器
p $reg-name
,可以查看寄存器的值info break
,简写i b
:查看所有断点信息info functions
查看所有的函数info watchpoints
,查看当前设置的所有观察点info signals info handle
,查看有哪些信号正在被gdb检测info line [currLineNum]
,查看源代码在内存中的地址info threads
,查看线程信息,只会输出线程的简短信息,通常只是一层栈(gdb) info threads Id Target Id Frame * 1 Thread 0xfff7c3ce70 (LWP 26956) "sysbench" main (argc=2, argv=0xffffff33b8) at sysbench.c:1405
info source
,查看当前所在的源代码文件信息,文件名称,程序语言等info files
,查看当前可执行文件的一些信息,如程序入口地址、各个段的内存布局等info frame
,查看当前函数栈的一些详细信息(gdb) info frame Stack level 0, frame at 0xffffff2d40: pc = 0xaaaab00e4c in sb_histogram_print (sb_histogram.c:321); saved pc = 0xaaaab85948 called by frame at 0xffffff2d40 source language c. Arglist at 0xffffff2d40, args: h=0xaaaae46020 Locals at 0xffffff2d40, Previous frame's sp is 0xffffff2d40 Saved registers: gp at 0xffffff2d28, s8 at 0xffffff2d30, ra at 0xffffff2d38, pc at 0xffffff2d38
七、反汇编相关
b *fun-name
,在函数的第一条汇编指令打断点- 自动反汇编后面要执行的代码
set disassemble-next-line auto
,当前代码没有源码(没有调试信息)时,自动反汇编执行到的每一行代码
set disassemble-next-line on
,不管是否有源码,都自动反汇编执行到的每一行代码
set disassemble-next-line off
,关闭自动反汇编功能 display /[n]i $pc
,显示当前要执行的汇编指令,n为显示条数disassemble [/r] fun-name
,查看函数fun-name的反汇编代码
/r
参数,以16进制显示每条汇编指令的值,下面指令都可以使用
disassemble /m fun-name
,将函数的每一行源码与其汇编指令对应显示
disassemble addr
:将addr所在函数的指令全部反汇编
disassemble addr1, addr2
:反汇编[addr1, addr2)
处的指令,常与info line [currLineNum]
配合使用
八、多进程与多线程
调试多进程常用命令。
set follow-fork-mode [child|parent]
,设置调试哪个进程
child
,调试子进程
parent
,调试父进程set detach-on-fork [off|on]
,GDB在fork之后是否断开(detach)某个进程的调试
off
,同时调试父进程和子进程
on
,只调试父进程set schedule-multiple on
,让父子进程都同时运行info inferiors
,查看所有进程信息inferiors <pid>
,切换到指定进程
调试多线程。用gdb调试多线程程序时,一旦程序断住,所有的线程都处于暂停状态。此时当你调试其中一个线程时(比如执行“step”,“next”命令),所有的线程都会同时执行。
-
set print thread-events off
,当有线程产生和退出时,就不会打印提示信息 -
show scheduler-locking
, 查看控制其他线程执行的设置 -
set scheduler-locking [off|on|step]
on
,表示调试线程执行时,其余线程锁定,阻塞等待
off
,表示不锁定其他线程,也是默认值
step
,表示在step(单步)调试时,只有当前线程运行,其它线程不会执行,但是用其它命令(比如"next")调试线程时,其它线程也许会执行 -
info threads
,查看所有线程的信息 -
thread <tid>
,切换到指定线程 -
break <line> thread <tid>
,在line行为指定tid的线程打断点 -
break <line> thread all
,在line行为所有的线程打断点 -
thread apply <tid> <gdb_cmd>
,让tid线程执行gdb_cmd命令
九、其它常用命令
-
Enter键
,复制上一条命令 -
help [cmd]
,指定命令帮助提示,(gdb) help list -
quit
,简写q
,退出GDB调试环境 -
info macro
,查看这个宏在哪些文件里被引用了,以及宏定义是什么样的
macro
,查看宏展开的样子
gcc -g
编译生成的程序,是不包含预处理器宏信息; 如果想在gdb中查看宏信息,可以使用gcc -g3
进行编译 -
set logging xxx
组合可以将调试信息输出到指定文件,下面将gdb调试的过程记录到thread_info.txt
文件中:set height 0 ##设置在文件中的起始位置 set logging file thread_info.txt ##指定输出文件 set logging on ##此命令之后的所有调试信息将输出到thread_info.txt文件 ## 开始gdb调试,会将过程记录 set logging off ##关闭到指定文件的输出 ## 在启动gdb的时候加入tee命令也可以保存调试信息,不过这就没有上面的方式灵活 gdb ./a.out | tee log_file
-
info sharedlibrary regex
,显示程序加载的共享链接库信息,其中regex可以是正则表达式,意为显示名字符合regex的共享链接库。如果没有regex,则列出所有的库(gdb) info sharedlibrary From To Syms Read Shared Object Library 0x000000fff7fd2540 0x000000fff7feafd8 Yes /lib64/ld.so.1 0x000000fff7ef28f0 0x000000fff7f4e56c Yes /lib/loongarch64-linux-gnu/libm.so.6 0x000000fff7ed90b0 0x000000fff7eda064 Yes /lib/loongarch64-linux-gnu/libdl.so.2 0x000000fff7e91a90 0x000000fff7eb9300 Yes (*) /lib/loongarch64-linux-gnu/libgcc_s.so.1 0x000000fff7cfd040 0x000000fff7df7af8 Yes /lib/loongarch64-linux-gnu/libc.so.6 (*): 带“*”表示库缺少调试信息.
-
stack 20
,查看栈内20个值
vmmap
,查看映射状况 peda带有
readelf
,查看elf
文件中各个段的起始地址peda
带有
parseheap
,显示堆状况 peda带有