编译

-g

  • -g参数,添加调试信息
1
$ gcc -g test.c -o test

汇编

  • 打印出错时的汇编代码片段,其中箭头指向的是出错的指令,即 PC 寄存器指向的地址,PC 寄存器存放的是下一条执行指令
1
(gdb) disassemble 
  • gdb 默认使用 AT&T 汇编语言格式打印汇编语句,设置为 intel 汇编语言格式
1
(gdb) set disassembly-flavor intel

启动

调试可执行文件

1
$ gdb redis-server

调试正在运行的进程 👍

1
$ gdb attach <进程ID>

SIGPIPE

  • 调试过程可能会因为 SIGPIPE 停止,可使用如下命令解决:
1
(gdb) handle SIGPIPE nostop noprint pass

结束调试

  • 且不对当前进程有任何影响
1
2
(gdb) detach
(gdb) quit

命令行参数

set args

  • gdb 附加程序后,使用 run 命令之前
1
(gdb) set args ../redis.conf 
  • 清除已经设置好的命令行参数
1
(gdb) set args

show args

  • 查看命令行参数
1
(gdb) show args

流程控制

break

  • 在函数的开头设置断点
1
(gdb) break func_name
  • 在文件 main.c 的第 10 行设置断点
1
(gdb) break main.c:10
  • 当变量 counter 的值为 100 时设置断点
1
(gdb) break main.c:10 if counter == 100

tbreak

  • 设置临时断点(该断点触发一次后,就会自动被删除)
1
(gdb) tbreak func_name

run

  • 如果是通过 gdb <可执行文件> 的方式,可使用如下命令让程序运行起来:
1
(gdb) run

或者:

1
(gdb) r

continue

  • 运行到下一个断点
1
(gdb) continue

或者:

1
(gdb) c

step

  • 执行当前行,并进入函数调用
1
(gdb) step

或者:

1
(gdb) s

next

  • 执行当前行,不进入函数调用
1
(gdb) next

或者:

1
(gdb) n

until 👍

  • 让程序运行到 2774 行
1
(gdb) until 2774

finish 👍

  • 直接执行完当前函数,并回到上一层的调用处
1
(gdb) finish

watch

  • i 的值发生变化时,gdb 会中断程序的执行,并显示相关的调试信息
1
(gdb) watch i
  • 当变量满足某个条件时才中断程序的执行
1
(gdb) watch (i > 100)

查看

bt

  • 查看当前的调用栈
1
2
(gdb) backtrace
(gdb) bt

frame

  • 切换堆栈
1
2
(gdb) frame 1
(gdb) f 1

print

查看变量

  • i 是变量名
1
(gdb) print i

修改变量

1
(gdb) print i = 100

修改长度限制 👍

字符串变量的长度可能会超过默认长度,如何查看完整的字符串?

  • 查看长度限制
1
2
(gdb) show print elements
Limit on string chars or array elements to print is 200.
  • 将长度限制改为 1000
1
(gdb) set print elements 1000
  • 或者改为无限制
1
(gdb) set print elements 0

info

查看当前函数的参数

1
(gdb) info args

查看寄存器

1
(gdb) info registers

查看所有线程

1
(gdb) info threads

ptype

查看变量类型

1
(gdb) ptype i

display

  • 监视变量或内存值,每次 gdb 中断都会自动输出
1
2
# display 变量名/内存地址/寄存器名
(gdb) display $ebx
  • 查看
1
(gdb) info display
  • 清除全部被监视的变量
1
(gdb) delete display

修改

修改变量的值

  • flag 的值修改为 1
1
(gdb) set variable flag = 1

修改内存

  • 将地址为 0x1000 处的内存内容设置为 0x55
1
(gdb) set {int}0x1000 = 0x55

修改寄存器

  • EAX 寄存器的值设置为 100
1
(gdb) set $eax=100

多线程

获取所有线程的堆栈信息 👍

1
(gdb) thread apply all bt

对指定的线程执行命令

1
(gdb) thread apply <thread-id> <command>

查看当前程序中所有线程的信息

1
(gdb) info threads

切换到指定的线程

1
(gdb) thread <thread-id>

为指定的线程设置断点

1
(gdb) break <function> thread <thread-id>

为指定线程的表达式设置监视点

1
(gdb) watch <expression> thread <thread-id>

关闭调度器锁定,允许所有线程同时执行

1
(gdb) set scheduler-locking off

将程序执行流锁定在当前线程

1
(gdb) set scheduler-locking on/step
  • step 也是用来锁定当前线程,当且仅当使用 nextstep 命令做单步调试时会锁定当前线程
  • 如果使用 until、finish、return 等线程内调试命令,其他线程还是有机会运行的

多进程

查看当前值

1
(gdb) show follow-fork mode

fork 之后 gdb attach 到父进程

1
(gdb) set follow-fork parent

fork 之后 gdb attach 到子进程

1
(gdb) set follow-fork child