跟着耗子叔学gdb

    xiaoxiao2026-06-22  1

    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 打印出当前的函数中的异常处理信息。  
    转载请注明原文地址: https://ju.6miu.com/read-1310776.html
    最新回复(0)