GDB Breakpoint
Table of Contents
1. GDB Breakpoint
1.1. software breakpoint
插入 software breakpoint 时, gdb 会把断点处的指令替换为会触发 trap 的指令, 例如 x86 上的 INT3 (0xcc), 以及 riscv 上的 ebreak. 同时记下原来的旧指令.
gdb 会用 ptrace catch 住 INT3 触发的 SIGTRAP, 从而实现断点的功能.
1.1.1. example
#include <stdio.h> void foo() {} int main(int argc, char** argv) { printf("%p\n", &foo); printf("%x\n", *((int*)foo)); foo(); printf("%p\n", &foo); printf("%x\n", *((int*)foo)); }
0x5648755ee149 fa1e0ff3 0x5648755ee149 fa1e0ff3
$> gdb ./a.out (gdb) r Starting program: /home/sunway/download/a.out 0x555555555149 fa1e0ff3 0x555555555149 fa1e0ff3 [Inferior 1 (process 234451) exited normally] (gdb) b foo Breakpoint 1 at 0x555555555149: file test.c, line 3. (gdb) r Starting program: /home/sunway/download/a.out 0x555555555149 fa1e0fcc Breakpoint 1, foo () at test.c:3 3 void foo() {} # 注意在 gdb 中用 x 显示的并非真实的内存数据, gdb 在显示时把 0xcc 替换成为原始的 # 0xf3 (gdb) x foo 0x555555555149 <foo>: 0xfa1e0ff3 (gdb) delete 1 (gdb) r Starting program: /home/sunway/download/a.out 0x555555555149 fa1e0ff3 0x555555555149 fa1e0ff3
gdb 需要 shadow 软件断点修改的内存, 参考 gdb 源码中的 `breakpoint shadow`
ps. 新版本的 gdb 使用 `b foo` 时会跳过函数的 prolog, 导致断点并没有设置在 &foo, 通过 `b *foo` 可以禁止 gdb 的这个行为
1.2. hardware breakpoint
参考 riscv trigger
1.3. misc
https://github.com/scottt/debugbreak
利用这个库在代码中直接插入 INT3, 从而不需要从 gdb 中设断点
Backlinks
GDB (GDB > GDB Breakpoint): GDB Breakpoint
GDB Target Arch (GDB Target Arch > backtrace > insert breakpoint): 可以看到 native debug 时 breakpoint 是通过写内存实现 (xfer_partial) 的 (参考 breakpoint)
ebreak (RISC-V Debug Module > debug with debug module > breakpoint > ebreak): 另外, gdb native debug 时 ebreak 需要触发 trap 而不是进入 debug mode (类似于 x86 的 int3, 参考 GDB Breakpoint), 这个通过 dcsr 可以配置