/*
* 查看栈信息
*/
backtrace [-n][n]
n 表示只打印栈顶上n层的栈信息。
-n 表示只打印栈底上n层的栈信息。
不加参数,表示打印所有栈信息。
bt // 打印当前的函数调用栈的所有信息
bt full
backtrace <n>
bt <n>
n是一个正整数,表示只打印栈顶上n层的栈信息。
backtrace <-n>
bt <-n>
-n表一个负整数,表示只打印栈底下n层的栈信息
/*
* info
*/
info line // 查看源代码在内存中的地址。
info line后面可以跟"行号","函数名","文件名:行号","文件名:函数名",这个命令会打印出所指定的源码在运行时的内存地址
(gdb) info line tst.c:func
Line 5 of "tst.c" starts at address 0x8048456 <func+6> and ends at 0x804845d <func+13>.
info f // 这个命令会打印出更为详细的当前栈层的信息,只不过,大多数都是运行时的内内地址。
info args // 打印出当前函数的参数名及其值。
info locals // 打印出当前函数中所有局部变量及其值。
info catch // 打印出当前的函数中的异常处理信息。
info terminal // 显示你程序用到的终端的模式
info registers
info break
info signals
info handle
info threads
/*
* 查看某一层的信息
*/
frame <n>
f <n>
n是一个从0开始的整数,是栈中的层编号。比如:frame 0,表示栈顶,frame 1,表示栈的第二层。
up <n>
表示向栈的上面移动n层,可以不打n,表示向上移动一层。
down <n>
表示向栈的下面移动n层,可以不打n,表示向下移动一层。
/*
* 显示寄存器
*/
info reg可以显示寄存器内容。
在寄存器名之前加$可以显示寄存器内容,
p $寄存器:显示寄存器内容
p/x $寄存器:十六进制显示寄存器内容。
用x命令可以显示内容内容,"x/格式 地址"。
x $pc:显示程序指针内容
x/i $pc:显示程序指针汇编。
x/10i $pc:显示程序指针之后10条指令。
x/128wx 0xfc207000:从0xfc20700开始以16进制打印128个word。
x/10w $esp // 显示栈里的10个数据,其中左边第一列是栈地址。
x/s 0x080484f0 // 栈中字符串格式的内存地址(指针)
x/s $rdi
x/5i 0x0804844a // 显示出这个地址开始的指令
x/10g $rsp // 显示栈中的数值,g 代表 giant words.
/*
* x : 查看内存
*/
examine 命令(简写是 x )来查看内存地址中的值。
x/<n/f/u> <addr>
n、f、u是可选的参数。
n 是一个正整数,表示显示内存的长度,也就是说从当前地址向后显示几个地址的内容。
f 表示显示的格式,参见上面。如果地址所指的是字符串,那么格式可以是s,如果地十是指令地址,那么格式可以是i。
u 表示从当前地址往后请求的字节数,如果不指定的话,GDB默认是4个bytes。u参数可以用下面的字符来代替,b表示单字节,h表示双字节,w表示四字节,
g表示八字节。当我们指定了字节长度后,GDB会从指内存定的内存地址开始,读写指定字节,并把其当作一个值取出来。
<addr>表示一个内存地址。
n/f/u三个参数可以一起使用。
命令:x/3uh 0x54320 表示,从内存地址0x54320读取内容,h表示以双字节为一个单位,3表示三个单位,u表示按十六进制显示。
x /nfu 0x<addr>:查看内存地址中的值。
n表示要显示的内存单元的个数
f表示显示方式, 可取如下值
x 按十六进制格式显示变量。
d 按十进制格式显示变量。
u 按十进制格式显示无符号整型。
o 按八进制格式显示变量。
t 按二进制格式显示变量。
a 按十六进制格式显示变量。
i 指令地址格式
c 按字符格式显示变量。
f 按浮点数格式显示变量。
u表示一个地址单元的长度
b表示单字节,
h表示双字节,
w表示四字节,
g表示八字节
可以用来查看当前汇编代码:
x/5i $pc
x/5ih $pc
char *c = "hi";
(gdb) p c
$1 = 0x075f4688 "hi"
(gdb) x/s 0x075f4688
0x075f4688: "hi"
(gdb) p (char *)0x075f4688
$3 = 0x075f4688 "hi"
(gdb) p *(char *)0x075f4688='H' // 将第一个字符改为大写
$4 = 72 'H'
(gdb) p c
$5 = 0x075f4688 "Hi"
/*
* disassemble
*/
disassemble
disassemble 程序计数器 :反汇编pc所在函数的整个函数。
disassemble addr-0x40,addr+0x40:反汇编addr前后0x40大小。
disassemble function-name
/*
* 监视点
*/
要想找到变量在何处被改变,可以使用watch命令设置监视点watchpoint。
watch <表达式>:表达式发生变化时暂停运行
awatch <表达式>:表达式被访问、改变是暂停执行
rwatch <表达式>:表达式被访问时暂停执行
info watchpoints 列出当前所设置了的所有观察点
watch counter>15 // 当counter>15的时候程序终止
/*
* 设置捕捉点(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 <libname> 载入共享库(动态链接库)时。(load为关键字,目前此功能只在HP-UX下有用)
7、unload 或 unload <libname> 卸载共享库(动态链接库)时。(unload为关键字,目前此功能只在HP-UX下有用)
tcatch <event>
只设置一次捕捉点,当程序停住以后,应点被自动删除。
/*
* 带有命令行参数
*/
gdb binary-operation
set args 6
使用两种方法输入命令行参数
1)run 命令行参数
2)set args 命令行参数
/*
* list:显示程序中的代码,常用使用格式有:
*/
list
输出从上次调用list命令开始往后的10行程序代码。
list -
输出从上次调用list命令开始往前的10行程序代码。
list n
输出第n行附近的10行程序代码。
list function
输出函数function前后的10行程序代码。
/*
* layout : 显示源码窗口
*/
可以使用"layout src"命令,或者按Ctrl-X再按A(重复按一遍则可以关闭),就会出现一个窗口可以查看源代码。
也可以使用 -tui参数,这样进入gdb里面后就能直接打开代码查看窗口。
窗口相关命令 功能
info win 显示窗口的大小
layout next 切换到下一个布局模式
layout prev 切换到上一个布局模式
layout src 只显示源代码
layout asm 只显示汇编代码
layout split 显示源代码和汇编代码
layout regs 增加寄存器内容显示
focus cmd/src/asm/regs/next/prev 切换当前窗口
refresh 刷新所有窗口
tui reg next 显示下一组寄存器
tui reg system 显示系统寄存器
update 更新源代码窗口和当前执行点
winheight name +/- line 调整name窗口的高度
tabset nchar 设置tab为nchar个字符
/*
* condition:设置断点在一定条件下才能生效。
*/
前面在说到设置断点时,提到过可以设置一个条件,当条件成立时,程序自动停止,这是一个非常强大的功能,
一般来说,为断点设置一个条件,我们使用if关键词,后面跟其断点条件。并且,条件设置好后,
我们可以用condition命令来修改断点的条件。
(只有break和 watch命令支持if,catch目前暂不支持if)
condition 断点号 条件表达式
* cont/continue:使程序在暂停在断点之后继续运行。使用格式:
cont
跳过当前断点继续运行。
cont n
跳过n次断点,继续运行。
当n为1时,cont 1即为cont。
condition <bnum> <expression>
修改断点号为bnum的停止条件为expression。
condition <bnum>
清除断点号为bnum的停止条件。
ignore <bnum> <count>
指定程序运行时,忽略断点号为bnum的停止条件count次。
/*
* ptype and whatis :显示数据类型
*/
* 和whatis类似,用于显示数据类型,但是它还可以显示typedef定义的类型等。使用格式:
ptype 变量或表达式
* whatis 命令可以显示某个变量的类型
"(gdb) whatis p
type = int *
/*
* set:设置程序中变量的值。
*/
set 变量=表达式
set 变量:=表达式
set prompt $把gdb的提示符设为$.
set args 可指定运行时参数。(如:set args 10 20 30 40 50)
show args 命令可以查看设置好的运行参数。
"(gdb)set args –b –x
"(gdb) show args
set width 70 // 设置gdb的列宽,以下为将屏幕设置为70列
gdb a.out core
where // 查看导致崩溃的原因
(gdb) set $epc = 0xbfc00000 // 修改寄存器
(gdb) set {unsigned int}0x8048a51=0x0 // 修改内存
set print address // 地址输出
set print address on
set print address off
show print address // 查看当前地址显示选项是否打开
打开地址输出,当程序显示函数信息时,GDB会显出函数的参数地址。系统默认为打开的,如:
(gdb) frame
#0 set_quotes (lq=0x34c78 "<<", rq=0x34c88 ">>") // print address on
(gdb) f
#0 set_quotes (lq="<<", rq=">>") at input.c:530 // print address off
set print array // 数组显示
set print array on
set print array off
show print array
打开数组显示,打开后当数组显示时,每个元素占一行,如果不打开的话,每个元素则以逗号分隔。这个选项默认是关闭的。
set print elements <number-of-elements> // 更改打印字符串的长度
show print elements // 查看print elements的选项信息
这个选项主要是设置数组的,如果你的数组太大了,那么就可以指定一个<number-of-elements>来指定数据显示的最大长度,
当到达这个长度时,GDB就不再往下显示了。如果设置为0,则表示不限制。
set print elements 300 ; 300 char
set print elements 0 ; set unlimted
set print null-stop <on/off>
如果打开了这个选项,那么当显示字符串时,遇到结束符则停止显示。这个选项默认为off。
set print pretty on
set print pretty off
show print pretty // 查看GDB是如何显示结构体的
如果打开printf pretty这个选项,那么当GDB显示结构体时会比较漂亮。
set print sevenbit-mains <on/off>
show print sevenbit-mains // 查看字符显示开关是否打开
设置字符显示,是否按"\nnn"的格式显示,如果打开,则字符串或字符数据按\nnn显示,如"\065"。
set print union <on/off>
show print union // 查看联合体数据的显示方式
设置显示结构体时,是否显式其内的 union 联合体数据
set print object <on/off>
show print object // 查看对象选项的设置
在C++中,如果一个对象指针指向其派生类,如果打开这个选项,GDB会自动按照虚方法调用的规则显示输出,
如果关闭这个选项的话,GDB就不管虚函数表了。这个选项默认是off。
set print static-members <on/off>
show print static-members // 查看静态数据成员选项设置
这个选项表示,当显示一个C++对象中的内容是,是否显示其中的静态数据成员。默认是on。
set print vtbl <on/off>
show print vtbl // 查看虚函数显示格式的选项
当此选项打开时,GDB将用比较规整的格式来显示虚函数表时。其默认是关闭的。
用不带任何参变量的'set'命令可以显示所有可以设置的变量的值
/*
* show
*/
show命令用来显示gdb自身的状态。
使用'set'命令可以改变绝大多数由'show'显示的信息
show radix // 显示基数
show version // 显示gdb的版本号
show copying // 显示版权信息
show warranty // 显示担保信息
path <dir> 设定程序的运行路径。
show paths 查看程序的运行路径。
tty 指写输入输出的终端设备。如:tty /dev/ttyb
/*
* display
*/
你可以设置一些自动显示的变量,当程序停住时,或是在你单步跟踪时,这些变量会自动显示。相关的GDB命令是display。
display <expr>
display/<fmt> <expr>
display/<fmt> <addr>
expr是一个表达式,fmt表示显示的格式,addr表示内存地址
格式i和s同样被display支持
display/i $pc // $pc 是GDB的环境变量,表示着指令的地址,/i 则表示输出格式为机器指令码,也就是汇编。
// 于是当程序停下后,就会出现源代码和机器指令码相对应的情形,这是一个很有意思的功能。
undisplay <dnums...>
delete display <dnums...>
删除自动显示,dnums意为所设置好了的自动显式的编号。如果要同时删除几个,编号可以用空格分隔,
如果要删除一个范围内的编号,可以用减号表示(如:2-5)
disable display <dnums...>
enable display <dnums...>
disable和enalbe不删除自动显示的设置,而只是让其失效和恢复。
info display
查看display设置的自动显示的信息。GDB会打出一张表格,向你报告当然调试中设置了多少个自动显示设置,
其中包括,设置的编号,表达式,是否enable。
delete display num // num 为前面变量前的编号,不带num时清除所有。
disable display num // num 为前面变量前的编号,不带num时去使能所有
(gdb) display a // 在每个断点或是每执行一步时显示该叙述值
display *node@10 // 数组
/*
* print 显示数据
*/
(print 指令可简写为 p)
print <expr>
print /<f> <expr>
<expr>是表达式,是被调试的程序中的表达式,<f>是输出的格式,比如,如果要把表达式按16进制的格式输出,那么就是/x。
在表达式中,有几种GDB所支持的操作符,它们可以用在任何一种语言中,
"@"是一个和数组有关的操作符,
"::"指定一个在文件或是函数中的变量,
"{<type>} <addr>"表示一个指向内存地址<addr>的类型为type的一个对象。
(gdb) print a => 显示 a 变量的内容.
(gdb) print sizeof(a) => 显示 a 变量的长度.
(gdb) print (a=10) => 将变量 a 的值设定为 10. // 更改变量值:
(gdb) print find_entry(1,0) // 对程序中函数的调用
(gdb) print *table_start // 数据结构和其他复杂对象
$8={e=reference=’\000’,location=0x0,next=0x0}
(gdb)print $1 ($1为历史记录变量,在以后可以直接引用 $1 的值) // 值的历史成分
x 按十六进制格式显示变量。
d 按十进制格式显示变量。
u 按十六进制格式显示无符号整型。
o 按八进制格式显示变量。
t 按二进制格式显示变量。
a 按十六进制格式显示变量。
c 按字符格式显示变量。
f 按浮点数格式显示变量。
print variable // 查看变量
print *array@len // 查看数组(array是数组指针,len是需要数据长度)
print(p) // 查看运行时的变量以及表达式。
print(p) array // 查看数组,
print(p) array[1], // 查看数组第2个元素。
print(p) *array@len // 查看动态内存。
print(p) x=5 // 改变运行时数据。
print xxx // 打印变量
p /x xxx // 16进制显示
p str@str_len // 打印字符串
printf "%2.2s/n",(char*)0x120100fa0
/*
* 数组
*/
p *array@len
p *node@10
/*
* 函数的调用
*/
call name 调用和执行一个函数
(gdb) call gen_and_sork( 1234,1,0 )
(gdb) call printf("abcd")
$1=4
finish 结束执行当前函数,显示其返回值(如果有的话)
/*
* 执行程序
*/
要想运行准备调试的程序,可使用run命令,在它后面可以跟随发给该程序的任何参数,
包括标准输入和标准输出说明符(<和>)和外壳通配符(*、?、[、])在内。
如果你使用不带参数的run命令,gdb就再次使用你给予前一条run命令的参数,这是很有用的。
利用set args 命令就可以修改发送给程序的参数,而使用show args 命令就可以查看其缺省参数的列表。
/*
* 设置临时断点
*/
* tbreak :设置临时断点,在设置之后只起作用一次。使用格式:
tbreak 要设置临时断点的行号
/*
* 断点(breakpoint)
*/
break命令(可以简写为b)可以用来在调试的程序中设置断点,该命令有如下四种形式:
break line-number 使程序恰好在执行给定行之前停止。
break function-name 使程序恰好在进入指定的函数之前停止。
break line-or-function if condition 如果condition(条件)是真,程序到达指定行或函数时停止。
break routine-name 在指定例程的入口处设置断点
如果该程序是由很多原文件构成的,你可以在各个原文件中设置断点,而不是在当前的原文件中设置断点,其方法如下:
(gdb) break filename:line-number // b single_link.c:300
(gdb) break filename:function-name // b single_link.c:init
要想设置一个条件断点,可以利用break if命令,如下所示:
(gdb) break line-or-function if expr
(gdb) break 46 if testsize==100
从断点继续运行:countinue 命令
break <function>
在进入指定函数时停住,C++中可以使用class::function或function(type, type)格式来指定函数名。
break <linenum>
在指定行号停住。
break +offset / break -offset
在当前行号的前面或后面的offset行停住,offiset为自然数。
break filename:linenum
在源文件filename的linenum行处停住。
break filename:function
在源文件filename的function函数的入口处停住。
break *address
在程序运行的内存地址处停住。
break
break命令没有参数时,表示在下一条指令处停住。
break ... if <condition>
"..."可以是上述的break <linenum>、break +offset / break –offset中的参数,condition表示条件,在条件成立时停住。
比如在循环体中,可以设置break if i=100,表示当i为100时停住程序。
break *ADDRESS
在地址ADDRESS上设置断点,这个命令允许你在没有调试信息的程序中设置断点
hbreak ARGS
设置一个由硬件支持的断点。这个命令的主要目的是用于对EPROM/ROM程序的调试 因为这条命令可以在不改变代码的情况下设置断点。
这可以同SPARCLite DSU一起使用。当程序访问某些变量和代码时,DSU将设置"陷井"。
注意:你只能一次使用一个断点,在新设置断点时,先删除原断点
rbreak REGEX
在所有满足表达式REGEX的函数上设置断点。这个命令在所有相匹配的函数上设置无条件断点,当这个命令完成时显示所有被设置的断点信息。
这个命令设置的断点和break命令设置的没有什么不同。当调试C++程序时这个命令在重载函数上设置断点时非常有用。
查看断点时,可使用info命令,如info breakpoints [n]、info break [n](n表示断点号)。
/*
* 断点的管理
*/
1. 显示当前gdb的断点信息:
"(gdb) info break
2.删除指定的某个断点:
"(gdb) delete breakpoint 1
该命令将会删除编号为1的断点,如果不带编号参数,将删除所有的断点
"(gdb) delete breakpoint
3.禁止使用某个断点
"(gdb) disable breakpoint 1
该命令将禁止断点 1,同时断点信息的 (Enb)域将变为 n
4.允许使用某个断点
"(gdb) enable breakpoint 1
该命令将允许断点 1,同时断点信息的 (Enb)域将变为 y
5.清除原文件中某一代码行上的所有断点
"(gdb)clean number
注:number 为原文件的某个代码行的行号
/* info breakpoints */
*Breakpoint Numbers*----断点号
*Type*----断点类型(断点或是观察点)
*Disposition*---显示断点的状态
*Enabled or Disabled*---使能或不使能。'y'表示使能,'n'表示不使能。
*Address*----地址,断点在你程序中的地址(内存地址)
*What*---地址,断点在你程序中的行号。
如果断点是条件断点,此命令还显示断点所需要的条件。带参数N的'info break'命令只显示由N指定的断点的信息。
此命令还显示断点的运行信息(被执行过几次),这个功能在使用'ignore' 命令时很有用。你可以'ignore'一个断点许多次。使用这个命令可以查看断点
被执行了多少次。这样可以更快的找到错误。
/* maint info breakpoints */
显示所有的断点,无论是你设置的还是gdb自动设置的。
/* 断点的含义 */
breakpoint:断点,普通断点
watchpoint:普通观察点
longjmp:内部断点,用于处理'longjmp'调用
longjmp resume:内部断点,设置在'longjmp'调用的目标上
until:'until'命令所使用的内部断点
finish:finish'命令所使用的内部断点
/*
* 断点菜单
*/
在 C++中,可能会重复出现同一个名字的函数若干次(函数重载),在这种情况下,break <function>不能告诉GDB要停在哪个函数的入口。
这时可以使用break <function(type)>也就是把函数的参数类型告诉GDB,以指定一个函数。
否则的话,GDB会给你列出一个断点菜单供你选择你所需要的断点。
你只要输入你菜单列表中的编号就可以了。
(gdb) b main::test
[0] cancel
[1] all
[2] file:main.cpp; line number:77
[3] file:main.cpp; line number:160
[4] file:main.cpp; line number:175
[5] file:main.cpp; line number:153
[6] file:main.cpp; line number:146
[7] file:main.cpp; line number:135
> 2 4 6
Breakpoint 1 at 0xb26c: file main.cpp, line 77.
Breakpoint 2 at 0xb344: file main.cpp, line 175.
Breakpoint 3 at 0xafcc: file main.cpp, line 146.
Multiple breakpoints were set.
Use the "delete" command to delete unwanted
breakpoints.
(gdb)
可见,GDB列出了所有test的重载函数,你可以选一下列表编号就行了。0表示放弃设置断点,1表示所有函数都设置断点。
/*
* commands
*/
* commands:设置在遇到断点后执行特定的指令。使用格式有:
commands
设置遇到最后一个遇到的断点时要执行的命令
commands n
设置遇到断点号n时要执行的命令
注意,commands后面跟的是断点号,而不是断点所在的行号。
在输入命令后,就可以输入遇到断点后要执行的命令,每行一条命令,在输入最后一条命令后输入end就可以结束输入。
/*
* 为停止点设定运行命令
*/
GDB提供 command 命令来设置停止点的运行命令。也就是说,当运行的程序被停止住时,可以让其自动运行一些别的命令,
这很有利行自动化调试。
对基于GDB的自动化调试是一个强大的支持。详细如下:
commands [bnum]
... command-list ...
end
为断点号bnum指写一个命令列表。当程序被该断点停住时,gdb会依次运行命令列表中的命令。
例如:
break foo if x>0
commands
printf "x is %d\n",x
continue
end
断点设置在函数foo中,断点条件是x>0,如果程序被断住后,也就是,一旦x的值在foo函数中大于0,GDB会自动打印出x的值,
并继续运行程序。
如果你要清除断点上的命令序列,那么只要简单的执行一下commands命令,并直接在打个end就行了。
/*
* continue
*/
程序被停住后用continue命令恢复程序的运行直到程序结束,或下一个断点到来。也可以使用step或next命令单步跟踪程序。
continue [ignore-count]
c [ignore-count]
fg [ignore-count]
恢复程序运行,直到程序结束,或是下一个断点到来。
ignore-count表示忽略其后的断点次数。continue,c,fg三个命令都是一样的意思。
step <count>
单步跟踪,有函数调用时进入该函数。进入函数的前提是,此函数被编译有debug信息。
后面可以加count也可以不加,不加表示一条条地执行,加表示执行后面的count条指令,然后再停住。
next <count>
单步跟踪,有函数调用不会进入该函数。后面可以加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" ,当运行完这个命令后,
单步跟踪会在打出程序代码的同时打出机器指令(也就是汇编代码)
/*
* 单步执行
*/
* next:继续执行语句,但是跳过子程序的调用。使用格式:
next
执行一条语句
next n
执行n条语句
* nexti:单步执行语句,但和next不同的是,它会跟踪到子程序的内部,但不打印出子程序内部的语句。使用格式同上。
* step:与next类似,但是它会跟踪到子程序的内部,而且会显示子程序内部的执行情况。使用格式同上。
* stepi:与step类似,但是比step更详细,是nexti和step的结合。使用格式同上。
单步执行有两个命令next和step,两者的区别是next遇到函数不会进入函数内部,step会执行到函数内部。
如果需要逐条汇编指令执行,可以分别使用nexti和stepi。
s : Step Into (单步跟踪进入)
n : Step Over (单步跟踪)
"si"命令用于执行一条汇编代码——区别于"s"执行一行C代码
/*
* 维护停止点
*/
delete、clear、disable、enable这几个命令来进行维护。
clear // 清除所有的已定义的停止点。
clear <function>
clear <filename:function> // 清除所有设置在函数上的停止点。
clear <linenum>
clear <filename:linenum> // 清除所有设置在指定行上的停止点。
/*
* 命令的历史
*/
为了允许使用历史命令,可使用 set history expansion on 命令 (gdb) set history expansion on
当你用GDB的print查看程序运行时的数据时,你每一个print都会被GDB记录下来。
GDB会以$1, $2, $3 .....这样的方式为你每一个print命令编上号。
于是,你可以使用这个编号访问以前的表达式,如$1。这个功能所带来的好处是,
如果你先前输入了一个比较长的表达式,如果你还想查看这个表达式的值,你可以使用历史记录来访问,省去了重复输入。
/*
* -g 等级
*/
如果不打开-g或者-ggdb(GDB专用)调试开关,GCC编译时不会加入调试信息,因为这会增大生成代码的体积。GCC采用了分级调试,
通过在-g选项后附加数字1、2或3来指定在代码中加入调试信息量。
默认的级别是2(-g2),此时调试信息包括扩展的符号表、行号、局部或外部变量信息。
级别3(- g3)包含级别2中的调试信息和源代码中定义的宏。
级别1(- g1)不包含局部变量和与行号有关的调试信息,只能用于回溯跟踪和堆栈转储之用。
[ 回溯跟踪指的是监视程序在运行过程中的函数调用历史,
堆栈转储则是一种以原始的十六进制格式保存程序执行环境的方法,两者都是经常用到的调试手段。] 。
/*
* GDB的启动:
*/
1、 gdb <program>
2、 gdb <program> core
用gdb同时调试一个运行程序和core文件,core是程序非法执行后core dump后产生的文件。
3、 gdb <program> <进程ID>
如果你的程序是一个服务程序,那么你可以指定这个服务程序运行时的进程ID。gdb会自动attach上去,并调试他。
program应该在PATH环境变量中搜索得到。
make <make-args> 不退出GDB就重新编译程序
/*
* 调试已运行的程序
*/
两种方法:
1.在UNIX下用ps查看正在运行的程序的PID(进程ID),然后用gdb <program> PID格式挂接正在运行的程序。
2.先用gdb <program>关联上源代码,并进行gdb,在gdb中用attach命令来挂接进程的PID。并用detach来取消挂接的进程。
/*
* 原文件的搜索
*/
search text:该命令可显示在当前文件中包含text串的下一行。
Reverse-search text:该命令可以显示包含text 的前一行。
/*
* UNIX接口
*/
"shell 命令可启动UNIX外壳,CTRL-D退出外壳,返回到 gdb.
/*
* GDB环境变量
*/
你可以在GDB的调试环境中定义自己的变量,用来保存一些调试程序中的运行数据。要定义一个GDB的变量很简单只需。使用GDB的set命令。
GDB的环境变量和UNIX一样,也是以$起头。如:
set $foo = *object_ptr
使用环境变量时,GDB会在你第一次使用时创建这个变量,而在以后 的使用中,则直接对其賦值。环境变量没有类型,
你可以给环境变量定义任一的类型。包括结构体和数组。
show convenience
该命令查看当前所设置的所有的环境变量。
这是一个比较强大的功能,环境变量和程序变量的交互使用,将使得程序调试更为灵活便捷。例如:
set $i = 0
print bar[$i++]->contents
于是,当你就不必,print bar[0]->contents, printbar[1]->contents地输入命令了。
输入这样的命令后,只用敲回车,重复执行上一条语句,环境变量会自动累加,从而完成逐个输出的功能。
/*
* 改变程序的执行
*/
一旦使用GDB挂上被调试程序,当程序运行起来后,你可以根据自己的调试思路来动态地在GDB中更改当前被调试程序的运行线路
或是其变量的值,这个强大的功能能够让你更好的调试你的程序,比如,你可以在程序的一次运行中走遍程序的所有分支。
/*
* 修改变量值
*/
修改被调试程序运行时的变量值,在GDB中很容易实现,使用GDB的print命令即可完成。如:
(gdb) print x=4
x=4这个表达式是C/C++的语法,意为把变量x的值修改为4,如果你当前调试的语言是Pascal,那么你可以使用Pascal的语法:x:=4。
在某些时候,很有可能你的变量和GDB中的参数冲突,如:
(gdb) whatis width
type = double
(gdb) p width
$4 = 13
(gdb) set width=47
Invalid syntax in expression.
因为,set width是GDB的命令,所以,出现了"Invalid syntax inexpression"的设置错误,此时,你可以使用set var命令来告诉GDB,
width不是你GDB的参数,而是程序的变量名,如:
(gdb) set var width=47
另外,还可能有些情况,GDB并不报告这种错误,所以保险起见,在你改变程序变量取值时,最好都使用set var格式的GDB命令。
/*
* 跳转执行
*/
一般来说,被调试程序会按照程序代码的运行顺序依次执行。GDB提供了乱序执行的功能,也就是说,GDB可以修改程序的执行顺序,
可以让程序执行随意跳跃。这个功能可以由GDB的jump命令来完:
jump <linespec>
指定下一条语句的运行点。<linespce>可以是文件的行号,可以是file:line格式,可以是+num这种偏移量格式。
表式着下一条运行语句从哪里开始。
jump <address>
这里的<address>是代码行的内存地址。
注意,jump命令不会改变当前的程序栈中的内容,所以,当你从一个函数跳到另一个函数时,
当函数运行完返回时进行弹栈操作时必然会发生错误,
可能结果还是非常奇怪的,甚至于产生程序Core Dump。所以最好是同一个函数中进行跳转。
熟悉汇编的人都知道,程序运行时,有一个寄存器用于保存当前代码所在的内存地址。所以,jump命令也就是改变了这个寄存器中的值。
于是,你可以使用"set $pc"来更改跳转执行的地址。如:
set $pc = 0x485
/*
* 强制函数返回
*/
如果你的调试断点在某个函数中,并还有语句没有执行完。你可以使用return命令强制函数忽略还没有执行的语句并返回。
return
return <expression>
使用return命令取消当前函数的执行,并立即返回,如果指定了<expression>,那么该表达式的值会被认作函数的返回值。
/*
* 强制调用函数
*/
call <expr>
表达式中可以一是函数,以此达到强制调用函数的目的。并显示函数的返回值,如果函数返回值是void,那么就不显示。
另一个相似的命令也可以完成这一功能——print,print后面可以跟表达式,所以也可以用他来调用函数,print和call的不同是,
如果函数返回void,call则不显示,print则显示函数返回值,并把该值存入历史数据中。
在不同语言中使用GDB支持下列语言:C, C++, Fortran, PASCAL, Java, Chill,assembly, 和 Modula-2。
一般说来,GDB会根据你所调试的程序来确定当然的调试语言,比如:发现文件名后缀为".c"的,GDB会认为是C程序。
文件名后缀为 ".C, .cc, .cp, .cpp, .cxx, .c++"的,GDB会认为是C++程序。
而后缀是".f, .F"的,GDB会认为是Fortran程序,还有,后缀为如果是".s, .S"的会认为是汇编语言。
也就是说,GDB会根据你所调试的程序的语言,来设置自己的语言环境,并让GDB的命令跟着语言环境的改变而改变。比如一些GDB命令需
要用到表达式或变量时,这些表达式或变量的语法,完全是根据当前的语言环境而改变的。例如C/C++中对指针的语法是*p,而在
Modula-2中则是p^。并且,如果你当前的程序是由几种不同语言一同编译成的,那到在调试过程中,GDB也能根据不同的语言自动地切换
语言环境。这种跟着语言环境而改变的功能,真是体贴开发人员的一种设计。
下面是几个相关于GDB语言环境的命令:
show language
查看当前的语言环境。如果GDB不能识为你所调试的编程语言,那么,C语言被认为是默认的环境。
info source
查看当前文件的程序语言。
如果GDB没有检测出当前的程序语言,那么你也可以手动设置当前的程序语言。使用set language命令即可做到。
当set language命令后什么也不跟的话,你可以查看GDB所支持的语言种类: