gdb 调试函数

1. 列出函数名字

使用 info functions 命令可以列出可执行文件的所有函数名称。此命令也支持正则表达式,如:info functions regex 只会列出符合正则表达式的函数名称。

1
2
3
4
5
6
7
8
9
10
11
(gdb) info functions printf*
All functions matching regular expression "printf*":

File ../stdio-common/printf_fphex.c:
int __printf_fphex(_IO_FILE *, const struct printf_info *, const void * const *);

File argp-fmtstream.c:
ssize_t __argp_fmtstream_printf(struct argp_fmtstream *, const char *, ...);

File argp-help.c:
static void print_header(const char *, const struct argp *, struct pentry_state *);

2. 是否进入带调试信息的函数

使用 gdb 调试遇到函数时,使用 step(缩写为 s) 命令可以进入函数(函数必须有调试信息)。

可以使用 next(缩写为 n)不进入函数,gdb 会等函数执行完,再显示下一行要执行的程序代码

3. 进入不带调试信息的函数

有些函数不带调试信息,所以 step(缩写为 s)无法进入。可以执行:set step-mode on 命令,这样 gdb 使用 step 命令可以进入函数。可以使用调试汇编程序的办法去调试函数。

4. 退出正在调试的函数

当单步调试一个函数时,如果不想继续跟踪下去,有两种方式退出。

第一种用 finish 命令,这样函数会继续执行完,并且打印返回值,然后等待输入接下来的命令

第二种用 return 命令,这样函数不会继续执行下面的语句,而是直接返回。注意是不执行。也可以用:return expression 命令指定函数的返回值。

5. 直接执行函数

可以使用 callprint 命令直接调用函数执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// code 
int global = 1;

int func(void) {
return (++global);
}

int main(void) {
printf("%d\n", global);
return 0;
}

// gdb 调试
Breakpoint 1, main () at main_01.cpp:10
10 printf("%d\n", global);
(gdb) call func()
$2 = 2
(gdb) print func()
$3 = 3

6. 打印函数堆栈帧信息

使用 info frame (缩写:i frame)命令显示函数堆栈帧信息。会输出指令寄存器的值,局部变量地址以及值等信息,可以对照当前寄存器的值和函数的汇编指令看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
(gdb) i frame
Stack level 0, frame at 0x7fffffffd5a0:
rip = 0x555555554662 in func (main_01.cpp:5); saved rip = 0x55555555468e
called by frame at 0x7fffffffd5b0
source language c++.
Arglist at 0x7fffffffd590, args: a=1, b=2
Locals at 0x7fffffffd590, Previous frame's sp is 0x7fffffffd5a0
Saved registers:
rbp at 0x7fffffffd590, rip at 0x7fffffffd598
(gdb) disassemble func
Dump of assembler code for function func(int, int):
0x000055555555464a <+0>: push %rbp
0x000055555555464b <+1>: mov %rsp,%rbp
0x000055555555464e <+4>: sub $0x20,%rsp
0x0000555555554652 <+8>: mov %edi,-0x14(%rbp)
0x0000555555554655 <+11>: mov %esi,-0x18(%rbp)
0x0000555555554658 <+14>: mov -0x14(%rbp),%eax
0x000055555555465b <+17>: imul -0x18(%rbp),%eax
0x000055555555465f <+21>: mov %eax,-0x4(%rbp)
=> 0x0000555555554662 <+24>: mov -0x4(%rbp),%eax
0x0000555555554665 <+27>: mov %eax,%esi
0x0000555555554667 <+29>: lea 0xb6(%rip),%rdi # 0x555555554724
0x000055555555466e <+36>: mov $0x0,%eax
0x0000555555554673 <+41>: callq 0x555555554520 <printf@plt>
0x0000555555554678 <+46>: nop
0x0000555555554679 <+47>: leaveq
0x000055555555467a <+48>: retq
End of assembler dump.