跟着耗子叔学gdb

gdb能够解决的问题:
1、启动你的程序,可以按照你的自定义的要求随心所欲的运行程序。
2、可让被调试的程序在你所指定的调置的断点处停住。(断点可以是条件表达式)
3、当程序被停住时,可以检查此时你的程序中所发生的事。
4、动态的改变你程序的执行环境。

gdb如何使用:
编译生成执行文件:(Linux 下)
hchen/test> cc -g tst.c -o tst
使用 GDB 调试:
hchen/test> gdb tst ---- 启动GDB

gdb常用命令:(gdb)
l   <--------------------- 命令相当于list,从第一行开始例出原码。
break  n   <--------------------- -设置断点,在源程序第n行处或跟函数名。
info break <--------------------- 查看断点信息。
r   <--------------------- 运行程序,run 命令简写。
n   <--------------------- 单条语句执行,next 命令简写。
c   <--------------------- 继续运行程序,continue 命令简写。
p i   <--------------------- 打印变量i 的值,print 命令简写。
bt <--------------------- 查看函数堆栈。
finish <--------------------- 退出函数。
q <--------------------- 退出gdb。

gdb下运行程序可以设置哪些参数
1、程序运行参数。
set args 可指定运行时参数。(如:set args 10 20 30 40 50)
show args 命令可以查看设置好的运行参数。
2、运行环境。
path <dir> 可设定程序的运行路径。
show paths 查看程序的运行路径。
set environment varname [=value] 设置环境变量。如:set env USER=hchen
show environment [varname] 查看环境变量。
3、工作目录。
cd <dir> 相当于shell 的cd 命令。
pwd 显示当前的所在目录。
4、程序的输入输出。
info terminal 显示你程序用到的终端的模式。
使用重定向控制程序输出。如:run > outfile
tty 命令可以指写输入输出的终端设备。如:tty /dev/ttyb


调试已运行程序
1、在UNIX 下用ps 查看正在运行的程序的PID(进程ID),然后用gdb <program> PID
格式挂接正在运行的程序。
2、先用gdb <program>关联上源代码,并进行gdb,在gdb 中用attach 命令来挂接进程
的PID。并用detach 来取消挂接的进程。


设置断点
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>
...可以是上述的参数,condition 表示条件,在条件成立时停住。比如在循环境
体中,可以设置break if i==100,表示当i 为100 时停住程序。
查看断点时,可使用info 命令,如下所示:(注:n 表示断点号)
info breakpoints [n]
info break [n]


设置观察点:
观察点一般来观察某个表达式(变量也是一种表达式)的值是否有变化了,如果有变化,使用watch命令,传递给该命令是一个待估值的表达式。这表明设置观察点的变量必须在当前的范围内。所以,为了给一个非全局变量设置观察点,必须在该局部变量所在的范围内设置一个端点。gdb运行起来此程序后,并在程序执行到该端点之后,设置观察点。
马上停住程序。我们有下面的几种方法来设置观察点:
watch <expr>
为表达式(变量)expr 设置一个观察点。一量表达式值有变化时,马上停住程序。
rwatch <expr>
当表达式(变量)expr 被读时,停住程序。
awatch <expr>
当表达式(变量)的值被读或被写时,停住程序。
info watchpoints
列出当前所设置了的所有观察点。
注:测试上述例子,你将会看到,打印出代码行并不与观察点改变的代码行一致。这是由于出发观察点的存储指令,是强制执行观察点所在的行语句,随后跳转到下一行,进行改变消息的输出。


设置捕捉点:
你可设置捕捉点来补捉程序运行时的一些事件。如:载入共享库(动态链接库)或是
C++的异常。设置捕捉点的格式为:
catch <event>
当 event 发生时,停住程序。event 可以是下面的内容:
1、throw 一个C++抛出的异常。(throw 为关键字)
2、catch 一个C++捕捉到的异常。(catch 为关键字)
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 即可,就好像回收站一样。
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 自动删除。


停止条件维护:
前面在说到设置断点时,我们提到过可以设置一个条件,当条件成立时,程序自动停止,这
是一个非常强大的功能,这里,我想专门说说这个条件的相关维护命令。一般来说,为断点设置
一个条件,我们使用if关键词,后面跟其断点条件。并且,条件设置好后,我们可以用condition
命令来修改断点的条件。(只有break 和watch 命令支持if,catch 目前暂不支持if)
condition <bnum> <expression>
修改断点号为bnum 的停止条件为expression。
condition <bnum>
清除断点号为bnum 的停止条件。
还有一个比较特殊的维护命令ignore,你可以指定程序运行时,忽略停止条件几次。
ignore <bnum> <count>
表示忽略断点号为bnum 的停止条件count 次。


为停止点设定运行命令:
我们可以使用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 命令恢复程序的运行直到程序结束,或下一个断点
到来。也可以使用step 或next 命令单步跟踪程序。
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” ,当运行完这个命
令后,单步跟踪会在打出程序代码的同时打出机器指令(也就是汇编代码)





线程调试:
如果你程序是多线程的话,你可以定义你的断点是否在所有的线程上,或是在某个特定的线
程。GDB 很容易帮你完成这一工作。
break <linespec> thread <threadno>
break <linespec> thread <threadno> if ...
linespec 指定了断点设置在的源程序的行号。threadno 指定了线程的ID,注意,
这个ID 是GDB 分配的,你可以通过“info threads”命令来查看正在运行程序中的线程信息。
如果你不指定thread <threadno>则表示你的断点设在所有线程上面。你还可以为某线程指
定断点条件。如:
(gdb) break frik.c:13 thread 28 if bartab > lim
当你的程序被GDB 停住时,所有的运行线程都会被停住。这方便你你查看运行程序的
总体情况。而在你恢复程序运行时,所有的线程也会被恢复运行。那怕是主进程在被单步调试时。


查看栈信息:
当程序被停住了,你需要做的第一件事就是查看程序是在哪里停住的。当你的程序调用了一
个函数,函数的地址,函数参数,函数内的局部变量都会被压入“栈”(Stack)中。你可以用
GDB 命令来查看当前的栈中的信息。
下面是一些查看函数调用栈信息的GDB 命令:
backtrace
bt
打印当前的函数调用栈的所有信息。如:
(gdb) bt
#0 func (n=250) at tst.c:6
#1 0x08048524 in main (argc=1, argv=0xbffff674) at tst.c:30
#2 0x400409ed in __libc_start_main () from /lib/libc.so.6
从上可以看出函数的调用栈信息:__libc_start_main --> main() --> func()
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,表示向下移动一层。
上面的命令,都会打印出移动到的栈层的信息。如果你不想让其打出信息。你可以使
用这三个命令:
select-frame <n> 对应于 frame 命令。
up-silently <n> 对应于 up 命令。
down-silently <n> 对应于 down 命令。
查看当前栈层的信息,你可以用以下GDB 命令:
frame 或 f
会打印出这些信息:栈的层编号,当前的函数名,函数参数值,函数所在文件及行号,
函数执行到的语句。
info frame
info f
这个命令会打印出更为详细的当前栈层的信息,只不过,大多数都是运行时的内内地
址。比如:函数地址,调用函数的地址,被调用函数的地址,目前的函数是由什么样的程序语言
写成的、函数参数地址及值、局部变量的地址等等。如:
(gdb) info f
Stack level 0, frame at 0xbffff5d4:
eip = 0x804845d in func (tst.c:6); saved eip 0x8048524
called by frame at 0xbffff60c
source language c.
Arglist at 0xbffff5d4, args: n=250
Locals at 0xbffff5d4, Previous frame's sp is 0x0
Saved registers:
ebp at 0xbffff5d4, eip at 0xbffff5d8
info args
打印出当前函数的参数名及其值。
info locals
打印出当前函数中所有局部变量及其值。
info catch
打印出当前的函数中的异常处理信息。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值