GDB常用命令

  • Post author:
  • Post category:其他


目录



前言

本文主要对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



版权声明:本文为jasonactions原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。