【调试】GDB使用总结

火影  论坛元老 | 2024-10-22 10:05:46 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 1017|帖子 1017|积分 3051

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
启动

在shell下敲gdb下令即可启动gdb,启动后会显示下述信息,出现gdb提示符。
  1. ➜  example gdb                                
  2. GNU gdb (Ubuntu 8.1.1-0ubuntu1) 8.1.1
  3. Copyright (C) 2018 Free Software Foundation, Inc.
  4. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
  5. This is free software: you are free to change and redistribute it.
  6. There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
  7. and "show warranty" for details.
  8. This GDB was configured as "x86_64-linux-gnu".
  9. Type "show configuration" for configuration details.
  10. For bug reporting instructions, please see:
  11. <http://www.gnu.org/software/gdb/bugs/>.
  12. Find the GDB manual and other documentation resources online at:
  13. <http://www.gnu.org/software/gdb/documentation/>.
  14. For help, type "help".
  15. Type "apropos word" to search for commands related to "word".
  16. (gdb)
复制代码
测试代码
  1. #include <stdio.h>
  2. int minus(int a,int b){
  3.    printf("In minus():\n");
  4.    int c = a-b;
  5.     return c;
  6. }
  7. int sum(int a, int b) {
  8.     printf("In sum():\n");
  9.         int c = a+b;
  10.     return c;
  11. }
  12. void print(int xx, int *xxptr) {
  13.   printf("In print():\n");
  14.   printf("   xx is %d and is stored at %p.\n", xx, &xx);
  15.   printf("   ptr points to %p which holds %d.\n", xxptr, *xxptr);
  16.   int c = sum(2,3);
  17.   int d = minus(3,2);
  18. }
  19. int main(void) {
  20.   int x = 10;
  21.   
  22.   int *ptr = &x;
  23.   printf("In main():\n");
  24.   printf("   x is %d and is stored at %p.\n", x, &x);
  25.   printf("   ptr points to %p which holds %d.\n", ptr, *ptr);
  26.   
  27.   print(x, ptr);
  28.   return 0;
  29. }
复制代码
设置断点

可以在函数名和行号等上设置断点。步调运行后,到达断点就会自动停息运行。此时可以检察该时间的变量值、显示栈帧、重新设置断点或重新运行等。断点下令(break)可以简写为b。
格式

  1. break 断点
复制代码
举例

  1. (gdb) b main
  2. Breakpoint 1 at 0x758: file gdb_example.c, line 9.
复制代码
格式

  1. break 函数名
  2. break 行号
  3. break 文件名:行号
  4. break 文件名:函数名
  5. break  + 偏移量
  6. break  - 偏移量
  7. break  * 地址
复制代码
举例

  1. (gdb) b print
  2. Breakpoint 2 at 0x709: file gdb_example.c, line 4.
  3. (gdb) b gdb_example.c:5
  4. Breakpoint 3 at 0x715: file gdb_example.c, line 5.
  5. (gdb) b +3
  6. Note: breakpoint 2 also set at pc 0x709.
  7. Breakpoint 4 at 0x709: file gdb_example.c, line 4.
  8. (gdb) b *0x709
  9. Note: breakpoints 2 and 4 also set at pc 0x709.
  10. Breakpoint 5 at 0x709: file gdb_example.c, line 4.
  11. (gdb)
复制代码
上面的例子分别对print函数,gdb_example.c第5行,现在停息位置以后第3行,地址0x709设置断点。
设置好的断点可以通过info break 确认
  1. (gdb) info break
  2. Num     Type           Disp Enb Address            What
  3. 1       breakpoint     keep y   0x0000000000000758 in main at gdb_example.c:9
  4. 2       breakpoint     keep y   0x0000000000000709 in print at gdb_example.c:4
  5. 3       breakpoint     keep y   0x0000000000000715 in print at gdb_example.c:5
  6. 4       breakpoint     keep y   0x0000000000000709 in print at gdb_example.c:4
  7. 5       breakpoint     keep y   0x0000000000000709 in print at gdb_example.c:4
复制代码
显示栈帧

backtrace下令可以在遇到断点而停息执行时显示栈帧。该下令简写为bt。此外, backtrace的别名还有where和info stack(简写为info s)。
  1. backtrace
  2. bt
复制代码
显示所有栈帧

  1. backtrace N
  2. bt N
复制代码
只显示开头N个栈帧

  1. backtrace -N
  2. bt -N
复制代码
只显示最后N个栈帧

  1. backtrace full
  2. bt full
  3. backtrace full N
  4. bt full N
  5. backtrace full -N
  6. bt full -N
复制代码
举例

  1. (gdb) b 4
  2. Breakpoint 1 at 0x714: file gdb_example.c, line 4.
  3. (gdb) r
  4. Starting program: /home/zhongyi/code/example/gdb_example
  5. In main():
  6.    x is 10 and is stored at 0x7fffffffe2fc.
  7.    ptr points to 0x7fffffffe2fc which holds 10.
  8. In print():
  9.    xx is 10 and is stored at 0x7fffffffe2cc.
  10.    ptr points to 0x7fffffffe2fc which holds 10.
  11. In sum():
  12. In minus():
  13. Breakpoint 1, minus (a=3, b=2) at gdb_example.c:4
  14. 4          int c = a-b;
  15. # 显示栈帧
  16. (gdb) bt
  17. #0  minus (a=3, b=2) at gdb_example.c:4
  18. #1  0x00005555555547c0 in print (xx=10, xxptr=0x7fffffffe2fc) at gdb_example.c:17
  19. #2  0x0000555555554841 in main () at gdb_example.c:28
  20. #只显示前2个栈帧
  21. (gdb) bt 2
  22. #0  minus (a=3, b=2) at gdb_example.c:4
  23. #1  0x00005555555547c0 in print (xx=10, xxptr=0x7fffffffe2fc) at gdb_example.c:17
  24. (More stack frames follow...)
  25. # 从外向内显示2个栈帧,及其局部变量
  26. (gdb) bt full -2
  27. #1  0x00005555555547c0 in print (xx=10, xxptr=0x7fffffffe2fc) at gdb_example.c:17
  28.         c = 5
  29.         d = 21845
  30. #2  0x0000555555554841 in main () at gdb_example.c:28
  31.         x = 10
  32.         ptr = 0x7fffffffe2fc
  33. (gdb)
复制代码
显示栈帧后,就可以确认步调在何处克制,及步调的调用路径。
显示变量

格式

  1. print 变量
复制代码
举例

  1. (gdb) p x
  2. $1 = 10
  3. (gdb) p ptr
  4. $2 = (int *) 0x7fffffffe2fc
  5. (gdb)
复制代码
显示寄存器

举例

  1. (gdb) info reg
  2. rax            0xc      12
  3. rbx            0x0      0
  4. rcx            0x7ffff7af2104   140737348837636
  5. rdx            0x7ffff7dcf8c0   140737351841984
  6. rsi            0x555555756260   93824994337376
  7. rdi            0x1      1
  8. rbp            0x7fffffffe310   0x7fffffffe310
  9. rsp            0x7fffffffe2f0   0x7fffffffe2f0
  10. r8             0x7ffff7fe14c0   140737354011840
  11. r9             0x0      0
  12. r10            0x0      0
  13. r11            0x246    582
  14. r12            0x5555555545f0   93824992232944
  15. r13            0x7fffffffe3f0   140737488348144
  16. r14            0x0      0
  17. r15            0x0      0
  18. rip            0x555555554841   0x555555554841 <main+123>
  19. eflags         0x202    [ IF ]
  20. cs             0x33     51
  21. ss             0x2b     43
  22. ds             0x0      0
  23. es             0x0      0
  24. fs             0x0      0
  25. gs             0x0      0
复制代码
寄存器前加$,可以显示寄存器的内容。
  1. (gdb) p $rdi
  2. $7 = 1
  3. (gdb) p $rax
  4. $8 = 12
  5. (gdb)
复制代码
显示寄存器可以用以下格式
p/格式 变量
格式说明x显示为16进制数d显示为十进制数u显示为无符号十进制数o显示为八进制数t显示为二进制数a地址c显示为asciif浮点小数s显示为字符串i显示为机器语言(仅在显示内存的x下令中可用) 显示内存

x下令可以显示内存的内容
格式

  1. x/格式 地址
复制代码
举例

  1. (gdb) x $r12
  2.    0x5555555545f0 <_start>:     xor    %ebp,%ebp
  3. (gdb) x $r8
  4.    0x7ffff7fe14c0:      rclb   $0xf7,(%rsi,%rdi,8)
  5. (gdb)
复制代码
x/i 可以显示汇编指令。一样平常用x下令时,格式为x/NFU ADDR。此处ADDR为盼望显示的地址,N为重复次数。F为前面讲过的格式,u代表的单位如下。
单位说明b字节h半字(2字节)w字(4字节)g双字(8字节) 下面显示从rsp开始的10条指令。
  1. (gdb) x/10i $rsp
  2.    0x7fffffffe2f0:      (bad)  
  3.    0x7fffffffe2f1:      rex.W push %rbp
  4.    0x7fffffffe2f3:      push   %rbp
  5.    0x7fffffffe2f4:      push   %rbp
  6.    0x7fffffffe2f5:      push   %rbp
  7.    0x7fffffffe2f6:      add    %al,(%rax)
  8.    0x7fffffffe2f8:      lock rex.RB push %r13
  9.    0x7fffffffe2fb:      push   %rbp
  10.    0x7fffffffe2fc:      or     (%rax),%al
  11.    0x7fffffffe2fe:      add    %al,(%rax)
复制代码
显示反汇编

格式

  1. disassemble
  2. disassemble 程序计数器
  3. disassemble 开始地址 结束地址
复制代码
格式1为反汇编当前整个函数,2为反汇编步调计数器所在函数的整个函数。3为反汇编从开始地址到结束地址的部分。
  1. (gdb) disassemble
  2. Dump of assembler code for function sum:
  3.    0x0000555555554722 <+0>:     push   %rbp
  4.    0x0000555555554723 <+1>:     mov    %rsp,%rbp
  5.    0x0000555555554726 <+4>:     sub    $0x20,%rsp
  6.    0x000055555555472a <+8>:     mov    %edi,-0x14(%rbp)
  7.    0x000055555555472d <+11>:    mov    %esi,-0x18(%rbp)
  8.    0x0000555555554730 <+14>:    lea    0x1bd(%rip),%rdi        # 0x5555555548f4
  9.    0x0000555555554737 <+21>:    callq  0x5555555545b0 <puts@plt>
  10. => 0x000055555555473c <+26>:    mov    -0x14(%rbp),%edx
  11.    0x000055555555473f <+29>:    mov    -0x18(%rbp),%eax
  12.    0x0000555555554742 <+32>:    add    %edx,%eax
  13.    0x0000555555554744 <+34>:    mov    %eax,-0x4(%rbp)
  14.    0x0000555555554747 <+37>:    mov    -0x4(%rbp),%eax
  15.    0x000055555555474a <+40>:    leaveq
  16.    0x000055555555474b <+41>:    retq   
  17. End of assembler dump.
复制代码
单步执行

  1. 执行源代码中的一行:next
  2. 进入函数内部执行:step
  3. 逐条执行汇编指令:nexti,stepi
复制代码
继续运行

格式

  1. continue
  2. continue 次数
复制代码
指定次数可以忽略断点,比方,continue 5 则5次遇到断点不会克制,第6次遇到断点才会克制。
监视点

格式

  1. watch <表达式>
复制代码
<表达式>发生厘革时停息运行,<表达式>意思是常量或变量
  1. awatch <表达式>
复制代码
<表达式>被访问,改变时停息运行
  1. rwatch <表达式>
复制代码
<表达式>被访问时停息运行
举例

  1. (gdb) watch c
  2. Hardware watchpoint 2: c
  3. (gdb) c
  4. Continuing.
  5. Hardware watchpoint 2: c
  6. Old value = 21845
  7. New value = 5
  8. sum (a=2, b=3) at gdb_example.c:10
  9. 10          return c;
  10. (gdb)
复制代码
格式

删除断点和监视点
  1. delete <编号>
复制代码
<编号>指的是断点或监视点
举例

  1. (gdb) info b
  2. Num     Type           Disp Enb Address            What
  3. 1       breakpoint     keep y   0x000055555555473c in sum at gdb_example.c:9
  4.         breakpoint already hit 1 time
  5. 2       hw watchpoint  keep y                      c
  6.         breakpoint already hit 1 time
  7. (gdb) delete  2
  8. (gdb) info b
  9. Num     Type           Disp Enb Address            What
  10. 1       breakpoint     keep y   0x000055555555473c in sum at gdb_example.c:9
  11.         breakpoint already hit 1 time
  12. (gdb)
复制代码
改变变量的值

格式

  1. set variable <变量>=<表达式>
复制代码
举例
  1. (gdb) p c
  2. $1 = 5
  3. (gdb) set variable c=0
  4. (gdb) p c
  5. $2 = 0
  6. (gdb)
复制代码
生成内核转储文件

  1. (gdb) generate-core-file
  2. warning: Memory read failed for corefile section, 4096 bytes at 0xffffffffff600000.
  3. Saved corefile core.2380
复制代码
有了内核转储文件,即使退出了GDB也能检察生成转储文件时的运行历史。
  1. gcore 'pidof gdb_example'
复制代码
该下令无需克制正在运行的步调,可以直接从下令行直接生成转储文件。当需要在其他机器上单独分析问题原因时,或者是分析客户现场问题时十分有用。
条件断点

  1. break 断点
  2. if 条件
复制代码
如果条件为真,则停息运行
  1. condition 断点编号
  2. condition 断点编号 条件
复制代码
第一条指令删除指定断点编号的触发条件,第二条指令给断点添加触发条件
反复执行

  1. ignore 断点编号 次数
复制代码
在编号指定的断点,监视点忽略指定的次数
continue与ignore一样,也可以指定次数,达到指定次数前,执行到断点时不停息。
  1. continue次数
  2. step 次数
  3. stepi 次数
  4. next 次数
  5. nexti 次数
复制代码
  1. finish
  2. until
  3. until 地址
复制代码
finish 执行完当前函数后停息,until下令执行完当前函数等代码块后停息,常用于跳出循环。、
删除断点或禁用断点

  1. clear
  2. clear 函数名
  3. clear 行号
  4. clear 文件名:行号
  5. clear 文件名:函数名
  6. delete [breakpoints] 断点编号
复制代码
clear 用于删除已定义的断点
  1. disable [breakpoints]
  2. disable [breakpoints] 断点编号
  3. disable display 显示编号
  4. disable mem 内存区域
复制代码
disable 暂时禁用断点。第3种格式禁用display下令定义的自动显示,第4种格式禁用mem下令定义的内存区域。
  1. enable
  2. enable [breakpoints] 断点编号
  3. enable [breakpoints] once 断点编号
  4. enable [breakpoints] delete 断点编号
  5. enable disable display 显示编号
  6. enable  mem 内存区域
复制代码
once 使指定的断点只启用一次。delete表现在运行停息后删除断点。
断点下令

格式

  1. commands 断点编号
  2.         命令
  3.         ...
  4.         end
复制代码
步调在指定的断点处停息,就会自动执行下令。
举例

  1. (gdb) b 17
  2. Breakpoint 3 at 0x5555555547b1: file gdb_example.c, line 17.
  3. (gdb) command 3
  4. Type commands for breakpoint(s) 3, one per line.
  5. End with a line saying just "end".
  6. >p c
  7. >end
  8. (gdb) r
  9. Starting program: /home/zhongyi/code/example/gdb_example -e 'p 1'
  10. In main():
  11.    x is 10 and is stored at 0x7fffffffe2ec.
  12.    ptr points to 0x7fffffffe2ec which holds 10.
  13. In print():
  14.    xx is 10 and is stored at 0x7fffffffe2bc.
  15.    ptr points to 0x7fffffffe2ec which holds 10.
  16. In sum():
  17. Breakpoint 3, print (xx=10, xxptr=0x7fffffffe2ec) at gdb_example.c:17
  18. 17        int d = minus(3,2);
  19. $1 = 5
复制代码
上例表现在17行停息后打印c的值。
与前面的条件断点组合使用,可以在断点停息时执行复杂的动作。
举例

  1. break 17 if c==5
  2.         commands
  3.         silent
  4.         printf “x is %d\n”,x
  5.         cont
  6.         end
复制代码
常用下令及其缩略形式

下令简写形式说明backtracebt/where显示backtracebreak装备断点continuec/cont继续运行deleted删除断点finish运行到函数结束info breakpoints显示断点信息nextn执行下一行printp显示表达式runr运行步调steps一次执行一行,包括函数内部x显示内存内容untilu执行到指定行directorydir插入目录disabledis禁用断点downdo在当前栈帧中选择要显示的栈帧edite编辑文件或函数framef选择要显示的栈帧forward-searchfo向前搜索generate-core-filegcore生成内核转储helph显示帮助文档infoi显示信息listl显示函数行nextini执行下一行(以汇编代码为单位)print-objectpo显示目标信息sharedlibraryshare加载共享库的符号stepisi执行下一行 值的历史

通过print下令显示过的值会记录在内部的值历史中,这些值可以在其他表达式中使用。
举例

  1. (gdb) b 16
  2. Breakpoint 1 at 0x79f: file gdb_example.c, line 16.
  3. (gdb) b 17
  4. Breakpoint 2 at 0x7b1: file gdb_example.c, line 17.
  5. (gdb) b 29
  6. Breakpoint 3 at 0x841: file gdb_example.c, line 29.
  7. (gdb) r
  8. Starting program: /home/zhongyi/code/example/gdb_example
  9. In main():
  10.    x is 10 and is stored at 0x7fffffffe2fc.
  11.    ptr points to 0x7fffffffe2fc which holds 10.
  12. In print():
  13.    xx is 10 and is stored at 0x7fffffffe2cc.
  14.    ptr points to 0x7fffffffe2fc which holds 10.
  15. Breakpoint 1, print (xx=10, xxptr=0x7fffffffe2fc) at gdb_example.c:16
  16. 16        int c = sum(2,3);
  17. (gdb) p c
  18. $1 = 1431651824
  19. (gdb) c
  20. Continuing.
  21. In sum():
  22. Breakpoint 2, print (xx=10, xxptr=0x7fffffffe2fc) at gdb_example.c:17
  23. 17        int d = minus(3,2);
  24. (gdb) p c
  25. $2 = 5
  26. (gdb) c
  27. Continuing.
  28. In minus():
  29. Breakpoint 3, main () at gdb_example.c:29
  30. 29        return 0;
复制代码
最后的值可以使用$ 访问。
通过show values 可以显示历史中的最后10个值
举例

  1. (gdb) show values
  2. $1 = 1431651824
  3. $2 = 5
  4. $3 = 10
  5. $4 = 10
  6. (gdb)
复制代码
值的历史的访问变量和说明
变量说明$值历史中的最后一个值$n值历史的第n个值$$值历史的倒数第二个值$$n值历史的倒数第n个值$_x下令显示过的最后的地址$__x下令显示过的最后的地址的值$_exitcode调试中的步调的返回代码$bpnum最后设置的断点的编号 可以随意定义变量。变量以$开头,有英文和数字组成。
举例

  1. (gdb) set $i=0
  2. (gdb) p $i
  3. $5 = 0
  4. (gdb)
复制代码
下令历史

可以把下令保存在文件中,保存下令历史后,就可以在其他调试会话中使用。默认下令历史文件位于./.gdb_history
  1. set history expansion
  2. show history expansion
复制代码
可以使用csh风格的!字符
  1. set history filename 文件名
  2. show history filename
复制代码
可将下令历史保存到文件中,可以通过环境变量GDBHISTFILE改变默认文件。
  1. set history save
  2. show history save
复制代码
启用下令历史保存到文件和恢复的功能。
  1. set history size 数字
  2. show history size
复制代码
设置保存到下令历史中的下令数量,默认为256。
初始化文件(.gdbinit)

Linux下gdb初始化文件为.gdbinit。如果存在.gdbinit文件,GDB在启动之前将其作为下令文件运行。
顺序如下:

  • $HOME/.gdbinit
  • 运行下令行选项
  • ./.gdbinit
  • 加载通过-x选项给出的下令文件
下令定义

用define可以自定义下令,用document可以给自定义的下令加说明,利用help 命令名
可以检察定义的下令。
define格式:
  1. define 命令名
  2.         命令
  3.         …………
  4.         end
复制代码
document格式:
  1. document 命令名
  2.         说明
  3.         end
复制代码
help格式:
  1. help 命令名
复制代码
以下示例定义了名为li的下令。
举例

  1. (gdb) define li
  2. Type commands for definition of "li".
  3. End with a line saying just "end".
  4. >x/10i $rbp
  5. >end
  6. (gdb) document li
  7. Type documentation for "li".
  8. End with a line saying just "end".
  9. >list machine instruction
  10. >end
  11. (gdb) li
  12.    0x7fffffffe310:      (bad)  
  13.    0x7fffffffe311:      rex.W push %rbp
  14.    0x7fffffffe313:      push   %rbp
  15.    0x7fffffffe314:      push   %rbp
  16.    0x7fffffffe315:      push   %rbp
  17.    0x7fffffffe316:      add    %al,(%rax)
  18.    0x7fffffffe318:      xchg   %edi,(%rax,%riz,4)
  19.    0x7fffffffe31b:      idiv   %edi
  20.    0x7fffffffe31d:      jg     0x7fffffffe31f
  21.    0x7fffffffe31f:      add    %al,(%rcx)
  22. (gdb) help li
  23. list machine instruction
复制代码
还可以把各种设置写在文件中,运行调试器时读取这些文件。
  1. source 文件名
复制代码
总结

本文只是对gdb下令脚本做了一个粗浅的先容,旨在起到抛砖引玉的结果。如果大家想更深入地了解这部分知识,可以参考gdb手册的相关章节:Extending GDB (https://sourceware.org/gdb/onlinedocs/gdb/Extending-GDB.html)。
最后向大家推荐一个github上的.gdbinit文件:https://github.com/gdbinit/Gdbinit,把这个弄懂,相信gdb脚本文件就不在话下了。
文章推荐:https://blog.csdn.net/lyshark_lyshark/article/details/125846778

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

火影

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表