gdb基础学习笔记

0. 前言

自古调试分两派,printf直接输出派 和 gdb调试派。

printf派直观暴力,但不全面。

gdb派全面却麻烦。

但为了更深入全面的学习,有必要了解gdb这款强大的调试工具。

1. gdb调试前准备

1
gcc -g -o hello hello.c

使用gcc编译时,一定要加上参数-g,不然生成的可执行文件hello不能调试,使用(gdb) file hellogdb hello时,会报错:No symbol table is loaded. Use the "file" command.

(这个结论尚且不准确。)

2. gdb指令

指令可Tab键补全,可上下键翻阅。

示例源程序如下:

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
#include<stdio.h>

int fun(int a, int b) {
int val = 0;
if (a > b) {
val = a + b;
} else {
val = a - b;
}
return val;
}

int main() {
printf("hello gdb!\n");

int i;
for (i=0; i<10; i++) {
printf("what is gdb? %d\n", i);
}

int a = 1, b=3;
printf("%d\n", fun(a, b));

return 0;
}

file

格式:

  • file <可执行文件名>,加载要调试的可执行文件。

示例:

1
2
(gdb) file hello1
Reading symbols from hello1...done.

list

格式:

  • list <linenum>,显示程序第linenum行周围的源程序
  • list <function> ,显示函数名为function的函数的源程序
  • list,显示当前行周围的源程序(10行),多次list,会自动向后显示源程序
  • list -,向前显示源程序

简写:l

示例:

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
29
30
31
32
33
34
(gdb) l
warning: Source file is more recent than executable.
1 #include<stdio.h>
2
3 int fun(int a, int b) {
4 int val = 0;
5 if (a > b) {
6 val = a + b;
7 } else {
8 val = a - b;
9 }
10 return val;
(gdb) l
11 }
12
13 int main() {
14 printf("hello gdb!\n");
15 int i;
16 for (i=0; i<10; i++) {
17 printf("what is gdb? %d\n", i);
18 }
19 return 0;
20 }
(gdb) l -
1 #include<stdio.h>
2
3 int fun(int a, int b) {
4 int val = 0;
5 if (a > b) {
6 val = a + b;
7 } else {
8 val = a - b;
9 }
10 return val;

start

说明:
开始执行程序,并在main函数的第一条语句前面停下来

示例:

1
2
3
4
5
6
(gdb) start
Temporary breakpoint 1 at 0x617: file hello1.c, line 14.
Starting program: /home/dounine/gdb/hello1

Temporary breakpoint 1, main () at hello1.c:14
14 printf("hello gdb!\n");

run

说明:运行加载的程序。在run前,需先设定一个或多个断点,不然程序会运行直到结束。

简写:r

break

格式:

  • break <function>,在指定的函数入口处设置断点
  • break <linenum>,在指定的行号处设置断点
  • break *<address>,在指定地址对应的代码处(指令处)设置断点
  • break +<offset> / break -<offset>,在当前行的下offset行/上offset行,设置断点

简写:b

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
(gdb) start
Temporary breakpoint 1 at 0x617: file hello1.c, line 14.
Starting program: /home/dounine/gdb/hello1

Temporary breakpoint 1, main () at hello1.c:14
warning: Source file is more recent than executable.
14 printf("hello gdb!\n");
(gdb) l
9 }
10 return val;
11 }
12
13 int main() {
14 printf("hello gdb!\n");
15
16 int i;
17 for (i=0; i<10; i++) {
18 printf("what is gdb? %d\n", i);
(gdb) break 17
Breakpoint 2 at 0x400629: file hello1.c, line 17.
(gdb) break fun
Breakpoint 3 at 0x4005d0: file hello1.c, line 4.
(gdb) break *0x400630
Breakpoint 4 at 0x400630: file hello1.c, line 17.
(gdb) break +2
Note: breakpoint 2 also set at pc 0x400629.
Breakpoint 5 at 0x400629: file hello1.c, line 16.

break *<address> 在了解并查看汇编位置后再下断点。
break +2 在第16行设置了断点,是因为当前行在第14行。

continue

格式:

  • continue,当程序被停住后,可以使用该命令恢复程序的运行直到程序结束,或到达下一个断点
  • continue <ignore-count>,忽略ignore-count个断点

简写:c

next

格式:

  • next,执行下一步/下一个语句,如果该语句为函数调用,不会进入函数内部执行(即不会一步步地调试函数内部语句)
  • next <count>,执行后面的count条语句(不进入函数),然后再停住

简写:n

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
(gdb) break 22
Breakpoint 2 at 0x40065f: file hello1.c, line 22.
(gdb) c
Continuing.
hello gdb!
what is gdb? 0
what is gdb? 1
what is gdb? 2
what is gdb? 3
what is gdb? 4
what is gdb? 5
what is gdb? 6
what is gdb? 7
what is gdb? 8
what is gdb? 9

Breakpoint 2, main () at hello1.c:22
22 printf("%d\n", fun(a, b));
(gdb) n
-2
24 return 0;
(gdb) n
25 }

step

格式:

  • step,执行下一步/下一条语句,然后停住。如果该语句为函数调用,则进入函数执行其中的第一条语句
  • step <count>,执行后面的count条语句,然后再停住

简写:s

示例:

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
29
30
(gdb) start
Temporary breakpoint 1 at 0x617: file hello1.c, line 14.
Starting program: /home/dounine/gdb/hello1

Temporary breakpoint 1, main () at hello1.c:14
warning: Source file is more recent than executable.
14 printf("hello gdb!\n");
(gdb) b 22
Breakpoint 2 at 0x40065f: file hello1.c, line 22.
(gdb) c
Continuing.
hello gdb!
what is gdb? 0
what is gdb? 1
what is gdb? 2
what is gdb? 3
what is gdb? 4
what is gdb? 5
what is gdb? 6
what is gdb? 7
what is gdb? 8
what is gdb? 9

Breakpoint 2, main () at hello1.c:22
22 printf("%d\n", fun(a, b));
(gdb) s
fun (a=1, b=3) at hello1.c:4
4 int val = 0;
(gdb) n
5 if (a > b) {

注意:使用step命令会进入函数调用,而使用next显然不会。但是,如果一直使用step,那将会进入一些如printf之类的函数。

print

  • print <expr>,打印指定表达式的值(表达式可以是变量,也可以是地址)
  • print /<f> <expr>,将指定表达式的值以f格式输出

f的格式包括:

  • x 按十六进制格式显示变量。
  • d 按十进制格式显示变量。
  • u 按十六进制格式显示无符号整型。
  • o 按八进制格式显示变量。
  • t 按二进制格式显示变量。
  • a 按十六进制格式显示变量。
  • c 按字符格式显示变量。
  • f 按浮点数格式显示变量。

示例:

1
2
3
4
5
6
7
8
(gdb) print &i
$1 = (int *) 0xbffff46c
(gdb) print i
$2 = 2
(gdb) print i+=1
$3 = 3
(gdb) print i
$4 = 3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
(gdb) start
Temporary breakpoint 1 at 0x5ac: file hello2.c, line 5.
Starting program: /home/dounine/gdb/hello2

Temporary breakpoint 1, main () at hello2.c:5
5 char *c = "hello world";
(gdb) p c
$1 = 0x400601 <__libc_csu_init+33> "\215\203\354\376\377\377)\306\301\376\002\205\366t%1\377\215\266"
(gdb) p /s c
$2 = 0x400601 <__libc_csu_init+33> "\215\203\354\376\377\377)\306\301\376\002\205\366t%1\377\215\266"
(gdb) p (char*)c
$3 = 0x400601 <__libc_csu_init+33> "\215\203\354\376\377\377)\306\301\376\002\205\366t%1\377\215\266"
(gdb) p *((char*)c)='H'
$4 = 72 'H'
(gdb) p c
$5 = 0x400601 <__libc_csu_init+33> "H\203\354\376\377\377)\306\301\376\002\205\366t%1\377\215\266"

注意:可以在print <expr>的时候,通过表达式设定某个变量的值

简写:p

examine

说明:用于打印某个地址所指向的内存中的内容,十分有用!!!

格式:x/nfu <addr>xexamine的缩写。

  • n:表示要显示的内存单元个数。取值为:1 2 3…

  • f:表示显示方式, 可取如下值:

    • x 按十六进制格式显示变量。
    • d 按十进制格式显示变量。
    • u 按十进制格式显示无符号整型。
    • o 按八进制格式显示变量。
    • t 按二进制格式显示变量。
    • i 指令地址格式
    • c 按字符格式显示变量。
    • f 按浮点数格式显示变量。
  • u:表示一个地址单元的长度,与n一起表示显示的地址长度。取值如下:

    • b 表示单字节,
    • h 表示双字节,
    • w 表示四字节,
    • g 表示八字节

示例:

1
2
3
# 显示0x7fffffffd708(这是个地址)处1个(n=1)单字节(u=b)的内容,以十六进制(f=x)表示;
(gdb)x/1xb 0x7fffffffd708
0x7fffffffd708: 0x26

也可以省略n f u参数:

1
2
(gdb) x/ 0x402470
0x402470: 0x00400f7c

display

  • display,跟踪查看某个变量,每次停下来都显示它的值

简写:disp

watch

  • watch,一般用来观察某个表达式(变量也是一种表达式)的值是否有变化。相当于,在每次该表达式值变化的地方,都设置一个断点。我们需要使用continue命令前进。

示例:

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) start
Temporary breakpoint 1 at 0x617: file hello1.c, line 14.
Starting program: /home/dounine/gdb/hello1

Temporary breakpoint 1, main () at hello1.c:14
14 printf("hello gdb!\n");
(gdb) watch i
Hardware watchpoint 2: i
(gdb) c
Continuing.
hello gdb!

Hardware watchpoint 2: i

Old value = 4196033
New value = 0
0x00400630 in main () at hello1.c:17
17 for (i=0; i<10; i++) {
(gdb) c
Continuing.
what is gdb? 0

Hardware watchpoint 2: i

Old value = 0
New value = 1
0x0040064b in main () at hello1.c:17
17 for (i=0; i<10; i++) {

info

说明:info命令可以在调试时用来查看寄存器、断点、观察点(watch)和信号等信息。

info可以查看的所有信息如下:

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
(gdb) info
"info" must be followed by the name of an info command.
List of info subcommands:

info address -- Describe where symbol SYM is stored
info all-registers -- List of all registers and their contents
info args -- Argument variables of current stack frame
info auto-load -- Print current status of auto-loaded files
info auxv -- Display the inferior's auxiliary vector
info bookmarks -- Status of user-settable bookmarks
info breakpoints -- Status of specified breakpoints (all user-settable breakpoints if no argument)
info checkpoints -- IDs of currently known checkpoints
info classes -- All Objective-C classes
info common -- Print out the values contained in a Fortran COMMON block
info copying -- Conditions for redistributing copies of GDB
info dcache -- Print information on the dcache performance
info display -- Expressions to display when program stops
info exceptions -- List all Ada exception names
info extensions -- All filename extensions associated with a source language
info files -- Names of targets and files being debugged
info float -- Print the status of the floating point unit
info frame -- All about selected stack frame
info frame-filter -- List all registered Python frame-filters
info functions -- All function names
info guile -- Prefix command for Guile info displays
info handle -- What debugger does when program gets various signals
info inferiors -- IDs of specified inferiors (all inferiors if no argument)
info line -- Core addresses of the code for a source line
info locals -- Local variables of current stack frame
info macro -- Show the definition of MACRO
info macros -- Show the definitions of all macros at LINESPEC
info mem -- Memory region attributes
info os -- Show OS data ARG
info pretty-printer -- GDB command to list all registered pretty-printers
info probes -- Show available static probes
info proc -- Show /proc process information about any running process
info program -- Execution status of the program
info record -- Info record options
info registers -- List of integer registers and their contents
info scope -- List the variables local to a scope
info selectors -- All Objective-C selectors
info set -- Show all GDB settings
info sharedlibrary -- Status of loaded shared object libraries
info signals -- What debugger does when program gets various signals
info skip -- Display the status of skips
info source -- Information about the current source file
info sources -- Source files in the program
info stack -- Backtrace of the stack
info static-tracepoint-markers -- List target static tracepoints markers
info symbol -- Describe what symbol is at location ADDR
info target -- Names of targets and files being debugged
info tasks -- Provide information about all known Ada tasks
info terminal -- Print inferior's saved terminal status
info threads -- Display currently known threads
info tracepoints -- Status of specified tracepoints (all tracepoints if no argument)
info tvariables -- Status of trace state variables and their values
info type-printers -- GDB command to list all registered type-printers
info types -- All type names
info unwinder -- GDB command to list unwinders
info variables -- All global and static variable names
info vector -- Print the status of the vector unit
info vtbl -- Show the virtual function table for a C++ object
info warranty -- Various kinds of warranty you do not have
info watchpoints -- Status of specified watchpoints (all watchpoints if no argument)
info win -- List of all displayed windows
info xmethod -- GDB command to list registered xmethod matchers

其中,常用的查看指令和作用如下:

  • info breakpoints,查看设置了所有断点的信息
  • info display,查看display命令监视的变量
  • info registers,查看寄存器中的值
  • info stack,查看栈(各函数栈帧)的信息
  • info watchpoints,查看watch命令监视的变量

delete

格式:

  • delete <breakpoints num>,删除断点编号所对应的断点,断点编号通过info breakpoints查看。
  • delete,删除所有断点。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
(gdb) br 17
Breakpoint 2 at 0x400629: file hello1.c, line 17.
(gdb) info breakpoints
Num Type Disp Enb Address What
2 breakpoint keep y 0x00400629 in main at hello1.c:17
(gdb) delete 2
(gdb) info breakpoints
No breakpoints or watchpoints.
(gdb) br 16
Breakpoint 3 at 0x400629: file hello1.c, line 16.
(gdb) br 17
Note: breakpoint 3 also set at pc 0x400629.
Breakpoint 4 at 0x400629: file hello1.c, line 17.
(gdb) br 18
Breakpoint 5 at 0x400632: file hello1.c, line 18.
(gdb) info breakpoints
Num Type Disp Enb Address What
3 breakpoint keep y 0x00400629 in main at hello1.c:16
4 breakpoint keep y 0x00400629 in main at hello1.c:17
5 breakpoint keep y 0x00400632 in main at hello1.c:18
(gdb) delete
Delete all breakpoints? (y or n) y
(gdb) info breakpoints
No breakpoints or watchpoints.

backtrace

说明:查看栈(各函数栈帧)信息,与info stack一样。

简写:bt

disassemble

说明:查看当前函数的反汇编代码。

quit

说明:退出gdb

简写:q

3. 安装peda插件

peda是用python开发的一款gdb插件,很受欢迎,github地址为https://github.com/longld/peda

3.1. 使用方法

git下载项目到本地,然后修改~/.gdbinit(当前用户的gdb配置目录)如下:

1
source xxx/peda/peda.py

修改后的效果是,每次启动gdb都会运行这条命令source xxx/peda/peda.py。这条命令的意思是:加载peda中的python脚本,xxx是peda的安装目录。

4. 使用自己python的脚本

在python中import gdb,就可以使用gdb模块了。

但是,import gdb直接运行会报错。

只有在gdbsource xxx.py时,才可以使用。

python中的gdb模块使用教程见官网:https://sourceware.org/gdb/onlinedocs/gdb/Python.html#Python