文章目录
- GDB常用命令
- 1 信息显示
- 1.1 显示版本信息:`show version`
- 1.2 启动时不显示信息:`gdb -q`
- 1.3 退出时不显示提示信息:`set confirm off`
- 1.4 输出信息是不暂停:`set pagination off` 或者` set height 0`
- 2 变量
- 3 字符串
- 4 函数
- 4.1 开始执行程序:`start`
- 4.2 列出可执行文件的所有函数名称:`info functions`
- 4.3 单步调试(不进入函数内部):`next(n)`
- 4.4 单步调试(进入函数):`step(s)`
- 4.5 退出正在调试的函数:`finish`
- 4.6 直接调用函数执行:`call function_name` 或者 `print function_name`
- 4.7 选择函数栈帧:`frame n(f n)`
- 4.8 打印函数堆栈帧信息:`info frame(i frame)`
- 5 断点
- 5.1 在程序地址上打断点:`b *address`
- 5.2 在程序入口处打断点
- 5.3 在文件行号上打断点:`b linenum`
- 5.4 查看已经创建的断点:`info breakpoints(i b)`
- 5.5 保存已经设置的断点:`save breakpoints file-name-to-save`
- 5.6 设置临时断点(生效一次):`tbreak(tb)`
- 5.7 设置条件断点:`break … if cond`
- 6 观察点
GDB常用命令
1 信息显示
1.1 显示版本信息:show version
1.2 启动时不显示信息:gdb -q
1.3 退出时不显示提示信息:set confirm off
1.4 输出信息是不暂停:set pagination off
或者set height 0
2 变量
2.1 设置变量的值:set var variable=expr
3 字符串
3.1 打印ASCII字符串:x/s str_name
例如:
# char str1[] = "abcd";
(gdb) x/s str1
3.2 设置字符串的值
例如,针对如下C代码:
#include <stdio.h>
int main(void)
{
char p1[] = "Sam";
char *p2 = "Bob";
printf("p1 is %s, p2 is %s\n", p1, p2);
return 0;
}
可以使用如下命令,设置字符串的值:
(gdb) set main::p1="Jil"
(gdb) set main::p2="Bill"
4 函数
4.1 开始执行程序:start
4.2 列出可执行文件的所有函数名称:info functions
4.3 单步调试(不进入函数内部):next(n)
4.4 单步调试(进入函数):step(s)
4.5 退出正在调试的函数:finish
4.6 直接调用函数执行:call function_name
或者 print function_name
例如,如下C函数:
int func(int a)
{
int i = a * 2;
return i;
}
可以使用如下方法直接调用:
(gdb) call func(2)
$1 = 4
(gdb) print func(3)
$2 = 6
4.7 选择函数栈帧:frame n(f n)
(gdb) bt
#0 func1 (a=10) at test.c:5
#1 0x0000000000400560 in func2 (a=10) at test.c:11
#2 0x0000000000400586 in func3 (a=10) at test.c:18
#3 0x000000000040059e in main () at test.c:24
(gdb) f 2
4.8 打印函数堆栈帧信息:info frame(i frame)
- 例如
Breakpoint 1, func (a=1, b=2) at a.c:5
5 printf("c is %d\n", c);
(gdb) i frame
Stack level 0, frame at 0x7fffffffe590:
rip = 0x40054e in func (a.c:5); saved rip = 0x400577
called by frame at 0x7fffffffe5a0
source language c.
Arglist at 0x7fffffffe580, args: a=1, b=2
Locals at 0x7fffffffe580, Previous frame's sp is 0x7fffffffe590
Saved registers:
rbp at 0x7fffffffe580, rip at 0x7fffffffe588
5 断点
5.1 在程序地址上打断点:b *address
当调试汇编程序,或者没有调试信息的程序时,经常需要在程序地址上打断点,方法:b *address
。例如:
0000000000400522 <main>:
400522: 55 push %rbp
400523: 48 89 e5 mov %rsp,%rbp
400526: 8b 05 00 1b 00 00 mov 0x1b00(%rip),%eax # 40202c <he+0xc>
40052c: 85 c0 test %eax,%eax
40052e: 75 07 jne 400537 <main+0x15>
400530: b8 7c 06 40 00 mov $0x40067c,%eax
400535: eb 05 jmp 40053c <main+0x1a>
(gdb) b *0x400522
5.2 在程序入口处打断点
当调试没有调试信息的程序时,直接运行 start
命令是没有效果的。如果不知道main在何处,那么可以在程序入口处打断点。先通过 readelf 获得入口地址,然后使用如下方法在程序的地址上打断点。
$ strip a.out
$ readelf -h a.out
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x400440
Start of program headers: 64 (bytes into file)
Start of section headers: 4496 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 9
Size of section headers: 64 (bytes)
Number of section headers: 29
Section header string table index: 28
(gdb) start
Function "main" not defined.
(gdb) b *0x400440
(gdb) r
5.3 在文件行号上打断点:b linenum
如果要在当前文件中的某一行打断点,直接b linenum
即可,例如:
(gdb) b 7
可以通过指定(部分)路径,来区分相同的文件名:
(gdb) b a/file.c:6
注意:通过行号进行设置断点的一个弊端是,如果你更改了源程序,那么之前设置的断点就可能不是你想要的了。
5.4 查看已经创建的断点:info breakpoints(i b)
5.5 保存已经设置的断点:save breakpoints file-name-to-save
在gdb中,可以使用如下命令将设置的断点保存下来:
(gdb) save breakpoints file-name-to-save
下此调试时,可以使用如下命令批量设置保存的断点:
(gdb) source file-name-to-save
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y 0x00000000005a7af0 in gdb_main at /home/xmj/project/binutils-trunk/g
2 breakpoint keep y 0x00000000005a6bd0 in captured_main at /home/xmj/project/binutils-tr
3 breakpoint keep y 0x00000000005a68b0 in captured_command_loop at /home/xmj
5.6 设置临时断点(生效一次):tbreak(tb)
在使用gdb时,如果想让断点只生效一次,可以使用“tbreak”命令(缩写为:tb)。例如:
(gdb) tb a.c:15
Temporary breakpoint 1 at 0x400500: file a.c, line 15.
5.7 设置条件断点:break … if cond
gdb可以设置条件断点,也就是只有在条件满足时,断点才会被触发,命令是“ break … if cond ”。
#include <stdio.h>
int main(void)
{
int i = 0;
int sum = 0;
for (i = 1; i <= 200; i++)
{
sum += i;
}
printf("%d\n", sum);
return 0;
}
以上面程序为例:
(gdb) start
Temporary breakpoint 1 at 0x4004cc: file a.c, line 5.
Starting program: /data2/home/nanxiao/a
Temporary breakpoint 1, main () at a.c:5
5 int i = 0;
(gdb) b 10 if i==101
Breakpoint 2 at 0x4004e3: file a.c, line 10.
(gdb) r
Starting program: /data2/home/nanxiao/a
Breakpoint 2, main () at a.c:10
10 sum += i;
(gdb) p sum
$1 = 5050
6 观察点
6.1 设置观察点:watch(wa)
gdb可以使用“ watch ”命令设置观察点,也就是当一个变量值发生变化时,程序会停下来。
6.2 设置观察点只针对特定线程生效:watch expr thread threadnum
gdb可以使用“ watch expr thread threadnum ”命令设置观察点只针对特定线程生效,也就是只有编号为 threadnum 的线程改变了变量的值,程序才会停下来,其它编号线程改变变量的值不会让程序停住。例如:
(gdb) watch a thread 2 # a is a variable
Hardware watchpoint 2: a
6.3 设置读观察点:rwatch(rw)
gdb可以使用“ rwatch ”命令设置读观察点,也就是当发生读取变量行为时,程序就会暂停住。例如:
(gdb) rw a # a is a variable
Hardware read watchpoint 2: a
6.4 设置读写观察点:awatch(aw)
gdb可以使用“ awatch ”命令设置读写观察点,也就是当发生读取变量或改变变量值的行为时,程序就会暂停住。需要注意的是 awatch 命令只对硬件观察点才生效。例如:
(gdb) aw a
Hardware access (read/write) watchpoint 1: a