GDB调试使用的命令
1、目前线上问题出现内存泄露, 怎样使用shell脚本 执行gdbattach 后 break bt quit等快速执行呢?
2、多进程 多线程一般会用到那些命令?
对于第一个问题:
以前文章有:gdb快速打印线程堆栈
目前可以参考脚本:
############################################################################## # 帮助信息 ############################################################################## help # 列出命令分类 help running # 查看某个类别的帮助信息 help run # 查看命令 run 的帮助 help info # 列出查看程序运行状态相关的命令 help info line # 列出具体的一个运行状态命令的帮助 help show # 列出 GDB 状态相关的命令 help show commands # 列出 show 命令的帮助 ############################################################################## # 断点 ############################################################################## break main # 对函数 main 设置一个断点,可简写为 b main break 101 # 对源代码的行号设置断点,可简写为 b 101 break basic.c:101 # 对源代码和行号设置断点 break basic.c:foo # 对源代码和函数名设置断点 break *0x00400448 # 对内存地址 0x00400448 设置断点 info breakpoints # 列出当前的所有断点信息,可简写为 info break delete 1 # 按编号删除一个断点 delete # 删除所有断点 clear # 删除在当前行的断点 clear function # 删除函数断点 clear line # 删除行号断点 clear basic.c:101 # 删除文件名和行号的断点 clear basic.c:main # 删除文件名和函数名的断点 clear *0x00400448 # 删除内存地址的断点 disable 2 # 禁用某断点,但是不删除 enable 2 # 允许某个之前被禁用的断点,让它生效 rbreak {regexpr} # 匹配正则的函数前断点,如 ex_* 将断点 ex_ 开头的函数 tbreak function|line # 临时断点 hbreak function|line # 硬件断点 ignore {id} {count} # 忽略某断点 N-1 次 condition {id} {expr} # 条件断点,只有在条件生效时才发生 condition 2 i == 20 # 2号断点只有在 i == 20 条件为真时才生效 watch {expr} # 对变量设置监视点 info watchpoints # 显示所有观察点 catch exec # 断点在exec事件,即子进程的入口地址 ############################################################################## # 运行程序 ############################################################################## run # 运行程序 run {args} # 以某参数运行程序 run < file # 以某文件为标准输入运行程序 run < <(cmd) # 以某命令的输出作为标准输入运行程序 run <<< $(cmd) # 以某命令的输出作为标准输入运行程序 set args {args} ... # 设置运行的参数 show args # 显示当前的运行参数 continue # 继续运行,可简写为 c 或 cont step # 单步进入,碰到函数会进去(Step in) step {count} # 单步多少次 next # 单步跳过,碰到函数不会进入(Step Over) next {count} # 单步多少次 finish # 运行到当前函数结束(Step Out) until # 持续执行直到代码行号大于当前行号(跳出循环) until {line} # 持续执行直到执行到某行 CTRL+C # 发送 SIGINT 信号,中止当前运行的程序 attach {process-id} # 链接上当前正在运行的进程,开始调试 detach # 断开进程链接 kill # 杀死当前运行的函数 ############################################################################## # 栈帧 ############################################################################## bt # 打印 backtrace (命令 where 是 bt 的别名) frame # 显示当前运行的栈帧 up # 向上移动栈帧(向着 main 函数) down # 向下移动栈帧(远离 main 函数) info locals # 打印帧内的相关变量 info args # 打印函数的参数 ############################################################################## # 代码浏览 ############################################################################## list 101 # 显示第 101 行周围 10行代码 list 1,10 # 显示 1 到 10 行代码 list main # 显示函数周围代码 list basic.c:main # 显示另外一个源代码文件的函数周围代码 list - # 重复之前 10 行代码 list *0x22e4 # 显示特定地址的代码 cd dir # 切换当前目录 pwd # 显示当前目录 search {regexpr} # 向前进行正则搜索 reverse-search {regexp} # 向后进行正则搜索 dir {dirname} # 增加源代码搜索路径 dir # 复位源代码搜索路径(清空) show directories # 显示源代码路径 ############################################################################## # 浏览数据 ############################################################################## print {expression} # 打印表达式,并且增加到打印历史 print /x {expression} # 十六进制输出,print 可以简写为 p print array[i]@count # 打印数组范围 print $ # 打印之前的变量 print *$->next # 打印 list print $1 # 输出打印历史里第一条 print ::gx # 将变量可视范围(scope)设置为全局 print 'basic.c'::gx # 打印某源代码里的全局变量,(gdb 4.6) print /x &main # 打印函数地址 x *0x11223344 # 显示给定地址的内存数据 x /nfu {address} # 打印内存数据,n是多少个,f是格式,u是单位大小 x /10xb *0x11223344 # 按十六进制打印内存地址 0x11223344 处的十个字节 x/x &gx # 按十六进制打印变量 gx,x和斜杆后参数可以连写 x/4wx &main # 按十六进制打印位于 main 函数开头的四个 long x/gf &gd1 # 打印 double 类型 help x # 查看关于 x 命令的帮助 info locals # 打印本地局部变量 info functions {regexp} # 打印函数名称 info variables {regexp} # 打印全局变量名称 ptype name # 查看类型定义,比如 ptype FILE,查看 FILE 结构体定义 whatis {expression} # 查看表达式的类型 set var = {expression} # 变量赋值 display {expression} # 在单步指令后查看某表达式的值 undisplay # 删除单步后对某些值的监控 info display # 显示监视的表达式 show values # 查看记录到打印历史中的变量的值 (gdb 4.0) info history # 查看打印历史的帮助 (gdb 3.5) ############################################################################## # 目标文件操作 ############################################################################## file {object} # 加载新的可执行文件供调试 file # 放弃可执行和符号表信息 symbol-file {object} # 仅加载符号表 exec-file {object} # 指定用于调试的可执行文件(非符号表) core-file {core} # 加载 core 用于分析 ############################################################################## # 信号控制 ############################################################################## info signals # 打印信号设置 handle {signo} {actions} # 设置信号的调试行为 handle INT print # 信号发生时打印信息 handle INT noprint # 信号发生时不打印信息 handle INT stop # 信号发生时中止被调试程序 handle INT nostop # 信号发生时不中止被调试程序 handle INT pass # 调试器接获信号,不让程序知道 handle INT nopass # 调试器不接获信号 signal signo # 继续并将信号转移给程序 signal 0 # 继续但不把信号给程序 ############################################################################## # 线程调试 ############################################################################## info threads # 查看当前线程和 id thread {id} # 切换当前调试线程为指定 id 的线程 break {line} thread all # 所有线程在指定行号处设置断点 thread apply {id..} cmd # 指定多个线程共同执行 gdb 命令 thread apply all cmd # 所有线程共同执行 gdb 命令 set schedule-locking ? # 调试一个线程时,其他线程是否执行,off|on|step set non-stop on/off # 调试一个线程时,其他线程是否运行 set pagination on/off # 调试一个线程时,分页是否停止 set target-async on/off # 同步或者异步调试,是否等待线程中止的信息 ############################################################################## # 进程调试 ############################################################################## info inferiors # 查看当前进程和 id inferior {id} # 切换某个进程 kill inferior {id...} # 杀死某个进程 set detach-on-fork on/off # 设置当进程调用fork时gdb是否同时调试父子进程 set follow-fork-mode parent/child # 设置当进程调用fork时是否进入子进程 ############################################################################## # 汇编调试 ############################################################################## info registers # 打印普通寄存器 info all-registers # 打印所有寄存器 print/x $pc # 打印单个寄存器 stepi # 指令级别单步进入,可以简写为 si nexti # 指令级别单步跳过,可以简写为 ni display/i $pc # 监控寄存器(每条单步完以后会自动打印值) x/x &gx # 十六进制打印变量 info line 22 # 打印行号为 22 的内存地址信息 info line *0x2c4e # 打印给定内存地址对应的源代码和行号信息 disassemble {addr} # 对地址进行反汇编,比如 disassemble 0x2c4e
set disassemble-next-line on:自动反汇编后面要执行的代码 si: maint info program-spaces:打印当前所有被调试的进程信息 用“display /i $pc” :命令显示当程序停止时,将要执行的汇编指令;取消显示可以用undisplay命令。 “disas /m fun”(disas是disassemble命令缩写)命令将函数代码和汇编指令映射起来 info line 13 只想查看某一行所对应的地址范围 set print elements number-of-elements-- set print elements 0 set print elements unlimited 打印大数组的内容, p array[60]@10 打印了array数组第60~69个元素的值 set print array-indexes on 打印数组的索引下标 “set print pretty on”命令,这样每行只会显示结构体的一名成员,而且还会根据成员的定义层次进行缩进: 用“bt full”命令显示各个函数的局部变量值 info locals 只是想打印当前函数局部变量的值 想查看进程的内存映射信息,可以使用“info proc mappings”命令(i是info命令缩写) 可以用"i files"(还有一个同样作用的命令:“i target”)命令,它可以更详细地输出进程的内存信息,包括引用的动态链接库等等, whatis xxx 或者 ptype xxx 打印变量的类型和所在文件 info variables xxx 查看定义该变量的文件: gdb中使用“x”命令来打印内存的值,格式为“x/nfu addr”。含义为以f格式打印从addr开始的n个长度单元为u的内存值。参数具体含义如下: a)n:输出单元的个数。 b)f:是输出格式。比如x是以16进制形式输出,o是以8进制形式输出,等等。 c)u:标明一个单元的长度。b是一个byte,h是两个byte(halfword),w是四个byte(word),g是八个byte(giant word)。 以16进制格式打印数组前a16个byte的值:(gdb) x/16xb a 可以显式地指定文件名(上下文): (gdb) p 'static-1.c'::var $1 = 1 (gdb) p 'static-2.c'::var $2 = 2 list(简写为l)命令来显示源代码以及行号 使用“watch a”命令以后,当a的值变化:由0变成1,由1变成2,程序都会停下来。 此外也可以使用“watch *(data type*)address”这样的命令, 使用“watch expr thread threadnum”命令设置观察点只针对特定线程生效,也就是只有编号为threadnum的线程改变了变量的值, 程序才会停下来,其它编号线程改变变量的值不会让程序停住 可以使用“rwatch”命令设置读观察点,也就是当发生读取变量行为时,程序就会暂停住 使用“awatch”命令设置读写观察点,也就是当发生读取变量或改变变量值的行为时, 当gdb启动时,会读取HOME目录和当前目录下的的配置文件,执行里面的命令。这个文件通常为“.gdbinit”。 这里给出了本文档中介绍过的,可以放在“.gdbinit”中的一些配置: # 打印STL容器中的内容 python import sys sys.path.insert(0, "/home/xmj/project/gcc-trunk/libstdc++-v3/python") from libstdcxx.v6.printers import register_libstdcxx_printers register_libstdcxx_printers (None) end # 保存历史命令 set history filename ~/.gdb_history set history save on # 退出时不显示提示信息 set confirm off # 按照派生类型打印对象 set print object on # 打印数组的索引下标 set print array-indexes on # 每行打印一个结构体成员 set print pretty on
对于第二个:
看以前问题文章
进程:
set follow-fork-mode child catch exec
Catch Point真是个好东西,支持很多有用的事件:
- 常规的C++异常事件
- 系统调用事件(可直接指定系统调用号)
- 动态库的加载/卸载事件
- exec/fork/vfork
- …
2.2 set detach-on-fork on
只调试父进程或子进程的其中一个(根据follow-fork-mode来决定),这是默认的模式。
2.3 set detach-on-fork off
父子进程都在gdb的控制之下,其中一个进程正常调试(根据follow-fork-mode来决定),另一个进程会被设置为暂停状态。
1.2 set follow-fork-mode parent
gdb只跟踪父进程,不跟踪子进程,这是默认的模式。
1.3 set follow-fork-mode child
gdb在子进程产生以后只跟踪子进程,放弃对父进程的跟踪。
如果想让父子进程都同时运行,可以使用“set schedule-multiple on”
show follow-fork-mode set follow-fork-mode child show detach-on-fork set detach-on-fork off
gdb调试多进程时,如果想要在进程间进行切换,那么就需要在fork调用前设置: set detach-on-fork off ,
然后使用 info inferiors 来查看进程信息,得到的信息可以看到最前面有一个进程编号,使用 inferior num 来进行进程切换。
那么为什么要使用 set detache-on-fork off 呢?它的意思是在调用fork后相关进程的运行行为是怎么样的,是detache on/off ?
也就是说分离出去独立运行,不受gdb控制还是不分离,被阻塞住。这里还涉及到一个设置 set follow-fork-mode [parents/child] ,
就是fork之后,gdb的控制落在谁身上,如果是父进程,那么分离的就是子进程,反之亦然。如果detache-on-fork被off了,
那么未受控的那个进程就会被阻塞住,进程状态为T,即处于调试状态。
| r | 运行调试 | display | 显示变量追踪 |
| n | 下一步 | watch |
监控变量,当变量发生修改时,打印显示。删除对应监控变量, 可以先 info watch,然后 delete 对应的号码。 |
| c | 继续运行 | info registers / register <reg> | 查看寄存器 |
| ctrl + c | 中断信号 | info win |
窗口切换fs cmd fs src |
| c/continue | 中断后继续运行 | display | 追踪查看具体变量值。 |
| s | 进入一个函数 | undisplay | 取消追踪观察变量。 |
| finish | 退出函数 | i watch | 显示观察点。 |
| l | 列出代码行 | thread apply all bt | 显示线程所有堆栈 |
| b | 断点 显示断点列表 info b 删除断点 delete 清除断点 clear |
info threads | 查看多个线程 |
| until | 跳至行号 until number |
thread <thread id> | 调试某个线程。 |
| p | 打印 打印数组信息 p *array@len p/x 按十六进制格式显示变量 |
attach | 绑定进程调试 attach -p pid |
| bt/backtrace | 堆栈bt <-n> -n表一个负整数,表示只打印栈底下n层的栈信息。 |
detach | 取消绑定调试进程 |
| f/frame | 进入指定堆栈层 f number |
disassemble | 看二进制数据 disassemble func |
| x | 查看内存 | focus | 显示源码界面 |
查看源代码
- list(l):查看最近十行源码
- list fun:查看fun函数源代码
- list file:fun:查看flie文件中的fun函数源代码
设置断点与观察断点
- break 行号/fun设置断点。
- break file:行号/fun设置断点。
- break if<condition>:条件成立时程序停住。
- info break(缩写:i b):查看断点。
- watch expr:一旦expr值发生改变,程序停住。
- delete n:删除断点。
多线程下:
thread apply ID1 ID2 IDN command:让线程编号是ID1,ID2…等等的线程都执行command命令。
thread apply all command:所有线程都执行command命令。
set scheduler-locking off|on|step:在调式某一个线程时,其他线程是否执行。在使用step或continue命令调试当前被调试线程的时候,其他线程也是同时执行的,如果我们只想要被调试的线程执行,而其他线程停止等待,那就要锁定要调试的线程,只让他运行。
off:不锁定任何线程,默认值。
on:锁定其他线程,只有当前线程执行。
step:在step(单步)时,只有被调试线程运行。
set non-stop on/off:当调式一个线程时,其他线程是否运行。
set pagination on/off:在使用backtrace时,在分页时是否停止。
set target-async on/ff:同步和异步。同步,gdb在输出提示符之前等待程序报告一些线程已经终止的信息。而异步的则是直接返回。
show scheduler-locking:查看当前锁定线程的模式
gdb调试时可以使用以下方式打印变量,
- x
- whatis
- ptype
- info
| 命令 | 作用 |
|---|---|
| whatis variable | 查看变量的类型 |
| ptype variable | 查看变量详细数据结构信息 |
| info variables var | 查看定义该变量的文件,不支持局部变量 |
打印字符串
| 命令 | 作用 |
|---|---|
| x/s str | 打印字符串str |
| set print elements 0 | 打印不限制字符串长度/或不限制数组长度 |
| call printf("%s\n", xxx) | 这是打印出的字符串不会含有多余的转义字、符 |
| printf("%s\n", xxx) |
打印数组
| 命令 | 作用 |
|---|---|
| print *array@10 | 打印从数组开头连续10个元素的值 |
| print array[60]@10 | 打印第60~69个元素 |
| set print array-indexes on | 打印数组元素时,同时打印数组下标 |
| *(float *)(addr)@num 打印地址值 | 将addr转换成float*类型,并打印num个值 |
打印指针/结构体
| 命令 | 作用 |
|---|---|
| print ptr | 查看该指针指向的类型及指针地址 |
| print *(struct xxx *)ptr | 查看指向的结构体内容 |
打印指定内存地址的值
使用x命令来打印内存的值,格式为x/nfu addr,以f格式打印从addr开始的n个长度单元为u的内存值。
- n:输出单元的个数
- f : 输出格式,如x表示以16进制输出,o表示以8进制数处,默认x
- u:一个单元的长度,b表示1byte,h表示2byte(half word),w表示4byte,g表示8byte(giant word)。
| 命令 | 作用 |
|---|---|
| x/8xb | 16进制形式打印8byte |
| x/8xw | 16进制形式打印8个单字(word) |
| x/10sg | 字符串形式打印10个双字 |
打印局部变量
| 命令 | 作用 |
|---|---|
| info locals | 打印当前函数局部变量 |
| backtrace full | 打印当前栈帧各个函数的局部变量,缩写bt f |
| bt full n | 从内到外显示n个栈帧及其局部变量 |
| bt full -n | 从外到内显示n个栈帧及其局部变量 |
设置打印格式
| 命令 | 作用 |
|---|---|
| set print pretty on | 每行只显示结构体的一名成员 |
| set print null-stop | 不显示'\000\ |

浙公网安备 33010602011771号