GDB常用命令

前言

本文主要对GDB常用调试命令做一个简单总结,以期能在调试时做到灵活运用,主要参考了《GDB完全中文手册》文档。

调试准备

  1. 在编译时, 我们必须要把调试信息加到可执行文件中。 使用编译器( cc/gcc/g++) 的-g 参数可以做到这一点。如果没有-g, 你将看不见程序的函数名、 变量名, 所代替的全是运行时的内存地址。

注:内核编译的时候需要注意修改Makefile为O1,否则会乱序,不利于调试;

启动GDB的三种方式

  1. gdb [program]
    program也就是你的执行文件, 一般在当然目录下。
  2. gdb [program] [core]
    用gdb同时调试一个运行程序和core文件, core是程序非法执行后core dump后产生的文件。
  3. gdb [program] [PID]
    如果程序是一个服务程序, 可以指定这个服务程序运行时的进程ID。 gdb会自动attach上去, 并调试。

注:program应该在PATH环境变量中搜索得到
GDB启动时, 可以加上一些GDB的启动开关, 详细的开关可以用gdb -help查看。 我在下面只例举一些比较常用的参数:
-symbols file
-s file
从指定文件中读取符号表。
-se file
从指定文件中读取符号表信息, 并把他用在可执行文件中。
-core file
-c file
调试时core dump的core文件。
-directory directory
-d directory
加入一个源文件的搜索路径。 默认搜索路径是环境变量中PATH所定义的路径。

设置断点(BreakPoint)

|- -b

b 43 设置断点为43行
b function 在某个函数设置断点
b +offset 在当前行号的后面offset行停住
b -offset 在当前行号的前面offset行停住
b filename:linenum 在filename的linenum行停住
b filename:function 在源文件filename的function函数的入口处停住
b *address 在程序运行的内存地址处停住
b … if [condition] …可以是上述的参数, condition表示条件, 在条件成立时停住
注:b是bredak的缩写

i b 查看有多少个断点


设置观察点(WatchPoint)

观察点一般来观察某个表达式( 变量也是一种表达式) 的值是否有变化了, 如果有变化, 马上停住程序。

|- -watch expr

为表达式( 变量) expr设置一个观察点。 一旦表达式值有变化时, 马上停住程序。

|- -rwatch expr

当表达式( 变量) expr被读时, 停住程序。

|- -awatch expr

当表达式( 变量) 的值被读或被写时, 停住程序。

|- -info watchpoints

列出当前所设置了的所有观察点


设置捕捉点( CatchPoint)

你可设置捕捉点来补捉程序运行时的一些事件。如: 载入共享库( 动态链接库) 或是C++的异常。 设置捕捉点的格式为:

|- -catch event

当event发生时, 停住程序。 event可以是下面的内容:
1、 throw 一个C++抛出的异常。( throw为关键字)
2、 catch 一个C++捕捉到的异常。( catch为关键字)
3、 exec 调用系统调用exec时。( exec为关键字, 目前此功能只在HP-UX下有用)
4、 fork 调用系统调用fork时。( fork为关键字, 目前此功能只在HP-UX下有用)
5、 vfork 调用系统调用vfork时。( vfork为关键字, 目前此功能只在HP-UX下有用)
6、 load 或 load 载入共享库( 动态链接库)时。( load为关键字, 目前此功能只在HP-UX下有用)
7、 unload 或 unload 卸载共享库( 动态链接库)时。( unload为关键字, 目前此功能只在HP-UX下有用)

|- -tcatch event

只设置一次捕捉点, 当程序停住以后, 捕捉点被自动删除


维护停止点

上面说了如何设置程序的停止点, GDB中的停止点也就是上述的三类。在GDB中, 如果你觉得已定义好的停止点没有用了, 你可以使用delete、 clear、 disable、 enable这几个命令来进行维护。

|- -clear

清除所有的已定义的停止点。

|- -clear function

clear filename:function
清除所有设置在函数上的停止点。

|- -clear linenum

clear filename:linenum
清除所有设置在指定行上的停止点。

|- -delete [breakpoints] [range…]

删除指定的断点, breakpoints为断点号。 如果不指定断点号, 则表示删除所有的断点。 range 表示断点号的范围(如:3-7)。 其简写命令为d。
比删除更好的一种方法是disable停止点, disable了的停止点, GDB不会删除, 当你还需要时, enable即可, 就好像回收站一样。

|- -delete 3

删除第3个断点

|- -disable [breakpoints] [range…]

disable所指定的停止点, breakpoints为停止点号。 如果什么都不指定, 表示disable所有的停止点。 简写命令是dis.

|- -enable [breakpoints] [range…]

enable所指定的停止点, breakpoints为停止点号。

|- -enable [breakpoints] once range…

enable所指定的停止点一次, 当程序停止后, 该停止点马上被GDB自动disable。

|- -enable [breakpoints] delete range…

enable所指定的停止点一次, 当程序停止后, 该停止点马上被GDB自动删除。


停止条件维护

|- -condition bnum expression

修改断点号为bnum的停止条件为expression。

|- -condition bnum

清除断点号为bnum的停止条件。

|- -ignore bnum count

表示忽略断点号为bnum的停止条件count次


为停止点设定运行命令

|- -commands [bnum] … command-list … end

为断点号bnum指写一个命令列表。 当程序被该断点停住时, gdb会依次运行命令列表中的命令

|- -commands… command-list … end

为断点号bnum清除命令


恢复程序运行

|- -continue [ignore-count]

|- -c [ignore-count]

|- -fg [ignore-count]

恢复程序运行, 直到程序结束, 或是下一个断点到来。 ignore-count表示忽略其后的断点次数。 continue,c, fg三个命令都是一样的意思。


单步执行

|- -step count

单步跟踪, 如果有函数调用, 他会进入该函数。 进入函数的前提是, 此函数被编译有debug信息。 很像VC等工具中的step in。 后面可以加count也可以不加, 不加表示一条条地执行, 加表示执行后面的count条指令, 然后再停住。

|- -next count

同样单步跟踪, 如果有函数调用, 他不会进入该函数。 很像VC等工具中的step over。 后面可以加count也可以不加,不加表示一条条地执行, 加表示执行后面的count条指令, 然后再停住。

|- -set step-mode

set step-mode on
打开step-mode模式, 于是, 在进行单步跟踪时, 程序不会因为没有debug信息而不停住。 这个参数有很利于查看机器码。
set step-mod off
关闭step-mode模式。

|- -finish

运行程序, 直到当前函数完成返回。 并打印函数返回时的堆栈地址和返回值及参数值等信息。

|- -until 或 u

当你厌倦了在一个循环体内单步跟踪时, 这个命令可以运行程序直到退出循环体。

|- -stepi 或 si

|- -nexti 或 ni

单步跟踪一条机器指令! 一条程序代码有可能由数条机器指令完成, stepi和nexti可以单步执行机器指令。 与之一样有相同功能的命令是“display/i $pc” , 当运行完这个命令后, 单步跟踪会在打出程序代码的同时打出机器指令( 也就是汇编代码)

|- -set

set *(int *)0x804a02=2019
修改内存的内容

set $pc=0xfffff7fd2950
修改寄存器的内容

|- -enter

执行上次执行的命令


强制函数返回

如果你的调试断点在某个函数中, 并还有语句没有执行完。 你可以使用return命令强制函数忽略还没有执行的语句并返回。

|- -return expression

使用return命令取消当前函数的执行, 并立即返回, 如果指定了expression, 那么该表达式的值会被认作函数的返回值


强制调用函数

|- -call expr

表达式中可以是函数, 以此达到强制调用函数的目的。 并显示函数的返回值, 如果函数返回值是void, 那么就不显示。


查看栈信息

|- -bt

查看当前运行的函数调用栈

注:bt最常用,如果程序hang死,可以用bt查看程序现场;watch查看谁踏坏了变量;经常需要ni和si来查看指令级的单步。

|- -backtrace n

|- -bt n

n是一个正整数, 表示只打印栈顶上n层的栈信息。

|- -backtrace -n

|- -bt -n

-n是一个负整数, 表示只打印栈底下n层的栈信息。

|- -frame n 或 f n

n是一个从0开始的整数, 是栈中的层编号。 比如: frame 0, 表示栈顶, frame 1, 表示栈的第二层。

|- -up n

表示向栈的上面移动n层, 可以不打n, 表示向上移动一层。

|- -down n

表示向栈的下面移动n层, 可以不打n, 表示向下移动一层。

|- -frame 或 f

会打印出这些信息: 栈的层编号, 当前的函数名, 函数参数值, 函数所在文件及行号, 函数执行到的语句

|- -info frame 或 info f

这个命令会打印出更为详细的当前栈层的信息, 只不过, 大多数都是运行时的内内地址。 比如: 函数地址, 调用函数的地址, 被调用函数的地址, 目前的函数是由什么样的程序语言写成的、 函数参数地址及值、 局部变量的地址等等。

|- -info args

打印出当前函数的参数名及其值

|- -info locals

打印出当前函数中所有局部变量及其值。

|- -info catch

打印出当前的函数中的异常处理信息。


显示源代码

|- -list linenum

显示程序第linenum行的周围的源程序。

|- -list function

显示函数名为function的函数的源程序。

|- -list

显示当前行后面的源程序。

|- -list -

显示当前行前面的源程序。
一般是打印当前行的上5行和下5行, 如果显示函数是是上2行下8行, 默认是10行

|- -ptype 结构体变量名

显示结构体定义


源代码的内存

|- -info line tst.c:func

可以使用info line命令来查看源代码在内存中的地址。 info line后面可以跟“ 行号”,“ 函数名”,“ 文件名:行号”,“ 文件名:函数名”, 这个命令会打印出所指定的源码在运行时的内存地址

|- -disassemble func

可以查看源程序的当前执行时的机器码, 这个命令会把目前内存中的指令dump出来


查看运行时数据

|- -print expr 或 p expr 或 print/f expr

使用print命令( 简写命令为p), 或是同义命令inspect来查看当前程序的运行数据,其中f为格式
p bk
查看变量bk的值

p bk.year=2010
修改变量的值

p &bk
查看bk变量的地址

p/x 结构体变量
16进制查看结构体变量值

p/x *address
打印地址的数据值

p/x *(type *)address
打印地址address地址对应的符号

p/x *arrary@10
查看array数组前10个元素的值

p/x *tp->args@10
查看tp结构体指针下args数组前10个元素的值

p ‘‘f2.c’’::x
查看f2.c文件中的全局变量x

p ‘‘function’’::x
查看function函数中的变量x

注:x 按十六进制格式显示变量。
d 按十进制格式显示变量。
u 按十六进制格式显示无符号整型。
o 按八进制格式显示变量。
t 按二进制格式显示变量。
a 按十六进制格式显示变量。
c 按字符格式显示变量。
f 按浮点数格式显示变量。


查看内存

使用examine命令( 简写是x) 来查看内存地址中的值。x命令的语法如下所示:

|- -x/n/f/u addr

x/8w 0x804a028
查看0x804a028开始地址的8个字内容

x/8b 0x804a028
查看0x804a028开始地址的8个字节内容

x/8h 0x804a028
查看0x804a028开始地址的8个半字内容

x/16x 0x804a028
以16进制查看0x804a028开始地址的16个字内容

x/g 0x804a028
查看0x804a028开始地址的8个字节内容

x/20i 函数名
查看函数的指令代码


查看寄存器

|- -info registers

查看寄存器的情况。( 除了浮点寄存器)

|- -info all-registers

查看所有寄存器的情况。( 包括浮点寄存器)

|- -info registers <regname …>

查看所指定的寄存器的情况。


修改变量值

|- -print x=4

x=4这个表达式是C/C++的语法, 意为把变量x的值修改为4


显示选项

|- -gdb -tui

启动gdb,并且分屏显示源代码,使用了’-tui’选项,启动可以直接将屏幕分成两个部分,上面显示源代码,比用list方便多了。这时候使用上下方向键可以查看源代码,想要命令行使用上下键就用[Ctrl]n和[Ctrl]p.

|- -set print address on

打开地址输出,当程序显示函数信息时,GDB会显出函数的参数地址。系统默认为打开的

|- -set print address off

关闭函数的参数地址显示

|- -show print address

查看当前地址显示选项是否打开。

|- -set print array on

打开数组显示,打开后当数组显示时,每个元素占一行,如果不打开的话,每个元素则以逗号分隔。这个选项默认是关闭的。

|- -set print array off

关闭数组显示,关闭后当数组显示时,每个元素则以逗号分隔。这个选项默认是关闭的。

|- -show print array

显示数组的显示格式

|- -set print elements

这个选项主要是设置数组的,如果你的数组太大了,那么就可以指定一个来指定数据显示的最大长度,当到达这个长度时,GDB就不再往下显示了。如果设置为0,则表示不限制。

|- -show print elements

查看print elements的选项信息。

|- -set print null-stop

如果打开了这个选项,那么当显示字符串时,遇到结束符则停止显示。这个选项默认为off。

|- -set print pretty on

如果打开printf pretty这个选项,那么当GDB显示结构体时会比较漂亮

|- -set print union <on/off>

设置显示结构体时, 是否显式其内的联合体数据

|- -show print union

查看联合体数据的显示方式


参考文档

GDB完全手册.txt

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值