0%

GDB 调试

引子

GDB 调试程序

给个例子程序

1
2
3
4
5
6
7
8
9
10
11
12
13
#include"stdio.h"
int add(int x,int y)
{
return x+y;
}

int main()
{
int p = add(6,5);
printf("%d\n",p);
return 0;
}

编译 gcc

1
2
3
4
5
6
7
8
[root@localhost cpp]# gcc add.cpp -o add.o
[root@localhost cpp]# ll -al
total 20
drwxr-xr-x. 2 root root 34 Oct 15 02:14 .
drwxr-xr-x. 4 root root 39 Oct 15 00:41 ..
-rw-r--r--. 1 root root 121 Oct 15 00:43 add.cpp
-rwxr-xr-x. 1 root root 12776 Oct 15 02:14 add.o
[root@localhost cpp]#

进入gdb调试

1. 方法一

1
gdb $file

如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[root@localhost cpp]# gdb add.o
GNU gdb (GDB) Red Hat Enterprise Linux 8.2-11.el8
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from add.o...(no debugging symbols found)...done.
(gdb)

2. 方法二

1
2
gdb 
file $file

先进入 gdb 程序,然后调用 file 打开文件

如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[root@localhost cpp]# gdb
GNU gdb (GDB) Red Hat Enterprise Linux 8.2-11.el8
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word".
(gdb) file add.o
Reading symbols from add.o...(no debugging symbols found)...done.
(gdb)

使用gdb打开文件后 ,使用 run 或者 r 开始程序的执行,
也可以使用 run parameter 将参数传递给该程序

GDB 命令列表

命令 缩写 命令说明
list l 显示多行源代码 编译选项需要 gcc -g
break b 设置断点 b main
info i 描述程序的状态
run r 开始运行程序
display disp 跟踪查看某个变量,每次停下来都显示它的值
step s 执行下一条语句,如果该语句为函数调用,则进入函数执行第一条语句s;相当于其它调试器中的“Step Into (单步跟踪进入)”
next n 执行下一条语句,如果该语句为函数调用,不会进入函数内部执行(即不会一步步调试函数内部语句);相当于其它调试器中的“Step Over (单步跟踪)”
print p 打印内部变量值
continue c 继续程序的运行,直到遇到下一个断点
set var name =v 设置变量值
start st 开始执行程序,在main函数的第一条语句前停下来
file 装载需要调试的程序
kill k 终止正在调试的程序
watch 监视变量值的变化
backtrace bt 查看函数调用的信息(堆栈)
frame f 查看栈帧
quit q 退出gdb环境

list

注意:显示多行源代码 编译选项需要 gcc -g

不要忘了 -g 选项或其它相应的选项,才能将调试信息加到你要调试的程序中

使用 gcc -o 编译 add.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[root@localhost cpp]# gcc -o add.o add.cpp
[root@localhost cpp]# gdb add.o
GNU gdb (GDB) Red Hat Enterprise Linux 8.2-11.el8
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from add.o...(no debugging symbols found)...done.
(gdb) list
No symbol table is loaded. Use the "file" command.
(gdb)

使用 gcc -g 编译

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
[root@localhost cpp]# gcc -g -o add.o add.cpp
[root@localhost cpp]# gdb add.o
GNU gdb (GDB) Red Hat Enterprise Linux 8.2-11.el8
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from add.o...done.
(gdb) l
1 #include"stdio.h"
2 int add(int x,int y)
3 {
4 return x+y;
5 }
6
7 int main()
8 {
9 int p = add(6,5);
10 printf("%d\n",p);
(gdb)

list n

显示已第n行为中心的10行代码

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
(gdb) list 6
1 #include"stdio.h"
2 int add(int x,int y)
3 {
4 return x+y;
5 }
6
7 int main()
8 {
9 int p = add(6,5);
10 printf("%d\n",p);
(gdb) list 7
2 int add(int x,int y)
3 {
4 return x+y;
5 }
6
7 int main()
8 {
9 int p = add(6,5);
10 printf("%d\n",p);
11 return 0;
(gdb) list 8
3 {
4 return x+y;
5 }
6
7 int main()
8 {
9 int p = add(6,5);
10 printf("%d\n",p);
11 return 0;
12 }

(gdb)

list functionname

显示以functionname的函数为中心的10行代码

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) list main
3 {
4 return x+y;
5 }
6
7 int main()
8 {
9 int p = add(6,5);
10 printf("%d\n",p);
11 return 0;
12 }
(gdb) list add
1 #include"stdio.h"
2 int add(int x,int y)
3 {
4 return x+y;
5 }
6
7 int main()
8 {
9 int p = add(6,5);
10 printf("%d\n",p);
(gdb)

list -

显示刚才打印过的源代码之前的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(gdb) list main
3 {
4 return x+y;
5 }
6
7 int main()
8 {
9 int p = add(6,5);
10 printf("%d\n",p);
11 return 0;
12 }
(gdb) list -
1 #include"stdio.h"
2 int add(int x,int y)
(gdb)

list

在刚才打印过的源代码之后打印10条代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
(gdb) list -
1 #include"stdio.h"
2 int add(int x,int y)
(gdb) list
3 {
4 return x+y;
5 }
6
7 int main()
8 {
9 int p = add(6,5);
10 printf("%d\n",p);
11 return 0;
12 }
(gdb) list
Line number 13 out of range; add.cpp has 12 lines.
(gdb)

断点break/b

break location

location 位置可以为某一行,某函数名或者其它结构的地址

gdb 会在执行该位置代码之前停下来

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
(gdb) list
3 {
4 return x+y;
5 }
6
7 int main()
8 {
9 int p = add(6,5);
10 printf("%d\n",p);
11 return 0;
12 }
(gdb) b 10
Breakpoint 1 at 0x4005c4: file add.cpp, line 10.
(gdb) r
Starting program: /root/projects/cpp/add.o
Missing separate debuginfos, use: yum debuginfo-install glibc-2.28-101.el8.x86_64

Breakpoint 1, main () at add.cpp:10
10 printf("%d\n",p);
(gdb) c
Continuing.
11
[Inferior 1 (process 1957) exited normally]
(gdb)

使用 delete breakpoints 断点号 删除断点
这里的断点号表示的是第几个断点,刚才执行 break 10 返回 Breakpoint 1 at 0x4005c4: file add.cpp, line 10.
中的1表示该断点的标号,因此使用 delete breakpoints 1 表示删除第10行所定义的断点
clear n 表示清除第n行的断点,因此 clear 10 等同于 delete breakpoints 1
disable/enable n 表示使得编号为n的断点暂时失效或有效

info breakpoints 查看断点相关的信息

属性 含义
Num 断点编号
Disp 断点执行一次之后是否有效 kep:有效 dis:无效
Enb 当前断点是否有效 y:有效 n:无效
Address 内存地址
What 位置

如下:

1
2
3
4
5
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y 0x00000000004005c4 in main() at add.cpp:10
breakpoint already hit 1 time
(gdb)

display /disp 查看参数值

1
2
3
4
5
6
7
8
9
10
11
(gdb) b 10
Breakpoint 1 at 0x4005c4: file add.cpp, line 10.
(gdb) r
Starting program: /root/projects/cpp/add.o
Missing separate debuginfos, use: yum debuginfo-install glibc-2.28-101.el8.x86_64

Breakpoint 1, main () at add.cpp:10
10 printf("%d\n",p);
(gdb) display p
1: p = 11
(gdb)

也可以使用 disable,enable,delete,info 命令修改及查看其状态,用法与对断点的一样

也可以使用 undisplay

step/next 命令

step 命令

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) b main
Breakpoint 2 at 0x4005b2: file add.cpp, line 9.
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /root/projects/cpp/add.o

Breakpoint 2, main () at add.cpp:9
9 int p = add(6,5);
1: p = 0
(gdb) s
add (x=6, y=5) at add.cpp:4
4 return x+y;
(gdb) s
5 }
(gdb) s

Breakpoint 1, main () at add.cpp:10
10 printf("%d\n",p);
1: p = 11
(gdb) s
11
11 return 0;
1: p = 11
(gdb) s
12 }
1: p = 11
(gdb) s
0x00007ffff7a356a3 in __libc_start_main () from /lib64/libc.so.6
(gdb)

next 命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
(gdb) r
Starting program: /root/projects/cpp/add.o

Breakpoint 2, main () at add.cpp:9
9 int p = add(6,5);
1: p = 0
(gdb) n

Breakpoint 1, main () at add.cpp:10
10 printf("%d\n",p);
1: p = 11
(gdb) n
11
11 return 0;
1: p = 11
(gdb) n
12 }
1: p = 11
(gdb) n
0x00007ffff7a356a3 in __libc_start_main () from /lib64/libc.so.6

watch

可以设置观察点,使得当某表达式发生变化时程序暂停执行。

执行该命令前保证程序已经运行

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
(gdb) l
1 #include"stdio.h"
2 int add(int x,int y)
3 {
4 return x+y;
5 }
6
7 int main()
8 {
9 int p = add(6,5);
10 printf("%d\n",p);
(gdb) l
11 return 0;
12 }
(gdb) b main
Breakpoint 1 at 0x4005b2: file add.cpp, line 9.
(gdb) r
Starting program: /root/projects/cpp/add.o
Missing separate debuginfos, use: yum debuginfo-install glibc-2.28-101.el8.x86_64

Breakpoint 1, main () at add.cpp:9
9 int p = add(6,5);
(gdb) watch p
Hardware watchpoint 2: p
(gdb) c
Continuing.

Hardware watchpoint 2: p

Old value = 0
New value = 11
main () at add.cpp:10
10 printf("%d\n",p);
(gdb) c
Continuing.
11

Watchpoint 2 deleted because the program has left the block in
which its expression is valid.
0x00007ffff7a356a3 in __libc_start_main () from /lib64/libc.so.6
(gdb)

print命令 whatis命令

print 表达式:简记为 p ,其中“表达式”可以是任何当前正在被测试程序的有效表达式,比如当前正在调试C语言的程序,那么“表达式”可以是任何C语言的有效表达式,包括数字,变量甚至是函数调用。
print a:将显示整数 a 的值
print ++a:将把 a 中的值加1,并显示出来
print name:将显示字符串 name 的值
print gdb_test(22):将以整数22作为参数调用 gdb_test() 函数
print gdb_test(a):将以变量 a 作为参数调用 gdb_test() 函数

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) l
1 #include"stdio.h"
2 int add(int x,int y)
3 {
4 return x+y;
5 }
6
7 int main()
8 {
9 int p = add(6,5);
10 printf("%d\n",p);
(gdb)
11 return 0;
12 }
(gdb) break 10
Breakpoint 1 at 0x4005c4: file add.cpp, line 10.
(gdb) r
Starting program: /root/projects/cpp/add.o
Missing separate debuginfos, use: yum debuginfo-install glibc-2.28-101.el8.x86_64

Breakpoint 1, main () at add.cpp:10
10 printf("%d\n",p);
(gdb) p p
$1 = 11
(gdb) whatis p
type = int
(gdb)

set var name=value

在程序运行中动态改变变量的值

1
2
3
4
5
6
7
8
9
(gdb) p p
$4 = 11
(gdb) set var p=100
(gdb) p p
$5 = 100
(gdb) set var p=10
(gdb) c
Continuing.
10

backtrace

可使用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
29
30
31
32
33
34
35
36
37
38
39
Reading symbols from add.o...done.
(gdb) b main
Breakpoint 1 at 0x4005b2: file add.cpp, line 9.
(gdb) r
Starting program: /root/projects/cpp/add.o
Missing separate debuginfos, use: yum debuginfo-install glibc-2.28-101.el8.x86_64

Breakpoint 1, main () at add.cpp:9
9 int p = add(6,5);
(gdb) bt
#0 main () at add.cpp:9
(gdb) s
add (x=6, y=5) at add.cpp:4
4 return x+y;
(gdb) bt
#0 add (x=6, y=5) at add.cpp:4
#1 0x00000000004005c1 in main () at add.cpp:9
(gdb) s
5 }
(gdb) s
main () at add.cpp:10
10 printf("%d\n",p);
(gdb) s
11
11 return 0;
(gdb) s
12 }
(gdb) s
0x00007ffff7a356a3 in __libc_start_main () from /lib64/libc.so.6
(gdb) bt
#0 0x00007ffff7a356a3 in __libc_start_main () from /lib64/libc.so.6
#1 0x00000000004004de in _start ()
(gdb) s
Single stepping until exit from function __libc_start_main,
which has no line number information.
[Inferior 1 (process 2029) exited normally]
(gdb) bt
No stack.
(gdb)

GDB 高级用法

命令 缩写 命令说明
disassemble disass 反汇编
examine x 查看内存
stepi si 汇编级别的断点定位,会进入汇编和C函数内部;当要进入没有调试信息的库函数调试的时候,用si是唯一的方法
finish si运行到一个函数结束(跳出帧)
nexti ni 汇编级别的断点定位,不会进入汇编和C函数内部

examine/x 查看内存

格式:

1
x /nfu <addr>

其中:

n 表示要显示的内存单元的个数

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

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

u 表示一个地址单元的长度

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

例如:

x/20xw 显示20个单元,16进制,4字节每单元

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
Reading symbols from add.o...done.
(gdb) b main
Breakpoint 1 at 0x4005b2: file add.cpp, line 9.
(gdb) r
Starting program: /root/projects/cpp/add.o
Missing separate debuginfos, use: yum debuginfo-install glibc-2.28-101.el8.x86_64

Breakpoint 1, main () at add.cpp:9
9 int p = add(6,5);
(gdb) n
10 printf("%d\n",p);
(gdb) x/4xb p
0xb: Cannot access memory at address 0xb
(gdb) x/4xb &p
0x7fffffffe41c: 0x0b 0x00 0x00 0x00
(gdb) x/1xw &p
0x7fffffffe41c: 0x0000000b
(gdb) x/1dw &p
0x7fffffffe41c: 11
(gdb) x/9i $pc
=> 0x4005c4 <main()+26>: mov -0x4(%rbp),%eax
0x4005c7 <main()+29>: mov %eax,%esi
0x4005c9 <main()+31>: mov $0x400678,%edi
0x4005ce <main()+36>: mov $0x0,%eax
0x4005d3 <main()+41>: callq 0x4004a0 <printf@plt>
0x4005d8 <main()+46>: mov $0x0,%eax
0x4005dd <main()+51>: leaveq
0x4005de <main()+52>: retq
0x4005df: nop
(gdb)

disassemble/disass 命令

disass func_name

反汇编一个函数

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
Reading symbols from add.o...done.
(gdb) l
1 #include"stdio.h"
2 int add(int x,int y)
3 {
4 return x+y;
5 }
6
7 int main()
8 {
9 int p = add(6,5);
10 printf("%d\n",p);
(gdb) l
11 return 0;
12 }
(gdb) disass add
Dump of assembler code for function add(int, int):
0x0000000000400596 <+0>: push %rbp
0x0000000000400597 <+1>: mov %rsp,%rbp
0x000000000040059a <+4>: mov %edi,-0x4(%rbp)
0x000000000040059d <+7>: mov %esi,-0x8(%rbp)
0x00000000004005a0 <+10>: mov -0x4(%rbp),%edx
0x00000000004005a3 <+13>: mov -0x8(%rbp),%eax
0x00000000004005a6 <+16>: add %edx,%eax
0x00000000004005a8 <+18>: pop %rbp
0x00000000004005a9 <+19>: retq
End of assembler dump.
(gdb)

disass 不带参数

disassemble 不带参数,默认的反汇编范围是 所选择帧的pc附近的函数
单个参数, 就是pc, 当然也可以是函数名,因为函数名 也是一个 地址; 这样范围就是该pc附近的函数
两个参数,就是内存地址范围

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
(gdb) disass
Dump of assembler code for function main():
0x00000000004005aa <+0>: push %rbp
0x00000000004005ab <+1>: mov %rsp,%rbp
0x00000000004005ae <+4>: sub $0x10,%rsp
0x00000000004005b2 <+8>: mov $0x5,%esi
0x00000000004005b7 <+13>: mov $0x6,%edi
0x00000000004005bc <+18>: callq 0x400596 <add(int, int)>
0x00000000004005c1 <+23>: mov %eax,-0x4(%rbp)
=> 0x00000000004005c4 <+26>: mov -0x4(%rbp),%eax
0x00000000004005c7 <+29>: mov %eax,%esi
0x00000000004005c9 <+31>: mov $0x400678,%edi
0x00000000004005ce <+36>: mov $0x0,%eax
0x00000000004005d3 <+41>: callq 0x4004a0 <printf@plt>
0x00000000004005d8 <+46>: mov $0x0,%eax
0x00000000004005dd <+51>: leaveq
0x00000000004005de <+52>: retq
End of assembler dump.
(gdb)

disassemble 0×0, 0×10

1
2
3
4
5
6
7
8
(gdb) disass $pc,$pc+10
Dump of assembler code from 0x40059a to 0x4005a4:
=> 0x000000000040059a <add(int, int)+4>: mov %edi,-0x4(%rbp)
0x000000000040059d <add(int, int)+7>: mov %esi,-0x8(%rbp)
0x00000000004005a0 <add(int, int)+10>: mov -0x4(%rbp),%edx
0x00000000004005a3 <add(int, int)+13>: mov -0x8(%rbp),%eax
End of assembler dump.
(gdb)
1
2
3
4
5
6
7
8
(gdb) disass $pc,+10
Dump of assembler code from 0x40059a to 0x4005a4:
=> 0x000000000040059a <add(int, int)+4>: mov %edi,-0x4(%rbp)
0x000000000040059d <add(int, int)+7>: mov %esi,-0x8(%rbp)
0x00000000004005a0 <add(int, int)+10>: mov -0x4(%rbp),%edx
0x00000000004005a3 <add(int, int)+13>: mov -0x8(%rbp),%eax
End of assembler dump.
(gdb)

反汇编一段内存地址, 第1个参数是起始地址,第2个是终止地址

查看内存中的汇编代码

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
(gdb) info line main
Line 8 of "add.cpp" starts at address 0x4005aa <main()> and ends at 0x4005b2 <main()+8>.
(gdb) info line add
Line 3 of "add.cpp" starts at address 0x400596 <add(int, int)> and ends at 0x4005a0 <add(int, int)+10>.
(gdb) x/30i 0x400596
0x400596 <add(int, int)>: push %rbp
0x400597 <add(int, int)+1>: mov %rsp,%rbp
0x40059a <add(int, int)+4>: mov %edi,-0x4(%rbp)
0x40059d <add(int, int)+7>: mov %esi,-0x8(%rbp)
0x4005a0 <add(int, int)+10>: mov -0x4(%rbp),%edx
0x4005a3 <add(int, int)+13>: mov -0x8(%rbp),%eax
0x4005a6 <add(int, int)+16>: add %edx,%eax
0x4005a8 <add(int, int)+18>: pop %rbp
0x4005a9 <add(int, int)+19>: retq
0x4005aa <main()>: push %rbp
0x4005ab <main()+1>: mov %rsp,%rbp
0x4005ae <main()+4>: sub $0x10,%rsp
0x4005b2 <main()+8>: mov $0x5,%esi
0x4005b7 <main()+13>: mov $0x6,%edi
0x4005bc <main()+18>: callq 0x400596 <add(int, int)>
0x4005c1 <main()+23>: mov %eax,-0x4(%rbp)
=> 0x4005c4 <main()+26>: mov -0x4(%rbp),%eax
0x4005c7 <main()+29>: mov %eax,%esi
0x4005c9 <main()+31>: mov $0x400678,%edi
0x4005ce <main()+36>: mov $0x0,%eax
0x4005d3 <main()+41>: callq 0x4004a0 <printf@plt>
0x4005d8 <main()+46>: mov $0x0,%eax
0x4005dd <main()+51>: leaveq
0x4005de <main()+52>: retq
0x4005df: nop
0x4005e0 <__libc_csu_init>: endbr64
0x4005e4 <__libc_csu_init+4>: push %r15
0x4005e6 <__libc_csu_init+6>: mov %rdx,%r15
0x4005e9 <__libc_csu_init+9>: push %r14
0x4005eb <__libc_csu_init+11>: mov %rsi,%r14
(gdb)

使用 disassemble /m func_name

/m 源码和汇编一起排列

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
(gdb) disassemble /m main
Dump of assembler code for function main():
8 {
0x00000000004005aa <+0>: push %rbp
0x00000000004005ab <+1>: mov %rsp,%rbp
0x00000000004005ae <+4>: sub $0x10,%rsp

9 int p = add(6,5);
0x00000000004005b2 <+8>: mov $0x5,%esi
0x00000000004005b7 <+13>: mov $0x6,%edi
0x00000000004005bc <+18>: callq 0x400596 <add(int, int)>
0x00000000004005c1 <+23>: mov %eax,-0x4(%rbp)

10 printf("%d\n",p);
0x00000000004005c4 <+26>: mov -0x4(%rbp),%eax
0x00000000004005c7 <+29>: mov %eax,%esi
0x00000000004005c9 <+31>: mov $0x400678,%edi
0x00000000004005ce <+36>: mov $0x0,%eax
0x00000000004005d3 <+41>: callq 0x4004a0 <printf@plt>

11 return 0;
0x00000000004005d8 <+46>: mov $0x0,%eax

12 }
0x00000000004005dd <+51>: leaveq
0x00000000004005de <+52>: retq

End of assembler dump.
(gdb) disassemble /m add
Dump of assembler code for function add(int, int):
3 {
0x0000000000400596 <+0>: push %rbp
0x0000000000400597 <+1>: mov %rsp,%rbp
=> 0x000000000040059a <+4>: mov %edi,-0x4(%rbp)
0x000000000040059d <+7>: mov %esi,-0x8(%rbp)

4 return x+y;
0x00000000004005a0 <+10>: mov -0x4(%rbp),%edx
0x00000000004005a3 <+13>: mov -0x8(%rbp),%eax
0x00000000004005a6 <+16>: add %edx,%eax

5 }
0x00000000004005a8 <+18>: pop %rbp
0x00000000004005a9 <+19>: retq

End of assembler dump.
(gdb)

使用 disassemble /r func_name

/r 还可以看到16进制代码

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
(gdb) disassemble /r main
Dump of assembler code for function main():
0x00000000004005aa <+0>: 55 push %rbp
0x00000000004005ab <+1>: 48 89 e5 mov %rsp,%rbp
0x00000000004005ae <+4>: 48 83 ec 10 sub $0x10,%rsp
0x00000000004005b2 <+8>: be 05 00 00 00 mov $0x5,%esi
0x00000000004005b7 <+13>: bf 06 00 00 00 mov $0x6,%edi
0x00000000004005bc <+18>: e8 d5 ff ff ff callq 0x400596 <add(int, int)>
0x00000000004005c1 <+23>: 89 45 fc mov %eax,-0x4(%rbp)
0x00000000004005c4 <+26>: 8b 45 fc mov -0x4(%rbp),%eax
0x00000000004005c7 <+29>: 89 c6 mov %eax,%esi
0x00000000004005c9 <+31>: bf 78 06 40 00 mov $0x400678,%edi
0x00000000004005ce <+36>: b8 00 00 00 00 mov $0x0,%eax
0x00000000004005d3 <+41>: e8 c8 fe ff ff callq 0x4004a0 <printf@plt>
0x00000000004005d8 <+46>: b8 00 00 00 00 mov $0x0,%eax
0x00000000004005dd <+51>: c9 leaveq
0x00000000004005de <+52>: c3 retq
End of assembler dump.
(gdb) disassemble /r add
Dump of assembler code for function add(int, int):
0x0000000000400596 <+0>: 55 push %rbp
0x0000000000400597 <+1>: 48 89 e5 mov %rsp,%rbp
=> 0x000000000040059a <+4>: 89 7d fc mov %edi,-0x4(%rbp)
0x000000000040059d <+7>: 89 75 f8 mov %esi,-0x8(%rbp)
0x00000000004005a0 <+10>: 8b 55 fc mov -0x4(%rbp),%edx
0x00000000004005a3 <+13>: 8b 45 f8 mov -0x8(%rbp),%eax
0x00000000004005a6 <+16>: 01 d0 add %edx,%eax
0x00000000004005a8 <+18>: 5d pop %rbp
0x00000000004005a9 <+19>: c3 retq
End of assembler dump.
(gdb)

可以在汇编指令上加断点

比如

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
67
68
Reading symbols from add.o...done.
(gdb) disass /m main
Dump of assembler code for function main():
8 {
0x00000000004005aa <+0>: push %rbp
0x00000000004005ab <+1>: mov %rsp,%rbp
0x00000000004005ae <+4>: sub $0x10,%rsp

9 int p = add(6,5);
0x00000000004005b2 <+8>: mov $0x5,%esi
0x00000000004005b7 <+13>: mov $0x6,%edi
0x00000000004005bc <+18>: callq 0x400596 <add(int, int)>
0x00000000004005c1 <+23>: mov %eax,-0x4(%rbp)

10 printf("%d\n",p);
0x00000000004005c4 <+26>: mov -0x4(%rbp),%eax
0x00000000004005c7 <+29>: mov %eax,%esi
0x00000000004005c9 <+31>: mov $0x400678,%edi
0x00000000004005ce <+36>: mov $0x0,%eax
0x00000000004005d3 <+41>: callq 0x4004a0 <printf@plt>

11 return 0;
0x00000000004005d8 <+46>: mov $0x0,%eax

12 }
0x00000000004005dd <+51>: leaveq
0x00000000004005de <+52>: retq

End of assembler dump.
(gdb) b *0x00000000004005ab
Breakpoint 1 at 0x4005ab: file add.cpp, line 8.
(gdb) r
Starting program: /root/projects/cpp/add.o
Missing separate debuginfos, use: yum debuginfo-install glibc-2.28-101.el8.x86_64

Breakpoint 1, 0x00000000004005ab in main () at add.cpp:8
8 {
(gdb) p $rbp
$1 = (void *) 0x4005e0 <__libc_csu_init>
(gdb) p $rsp
$2 = (void *) 0x7fffffffe420
(gdb) si
0x00000000004005ae 8 {
(gdb) disass main
Dump of assembler code for function main():
0x00000000004005aa <+0>: push %rbp
0x00000000004005ab <+1>: mov %rsp,%rbp
=> 0x00000000004005ae <+4>: sub $0x10,%rsp
0x00000000004005b2 <+8>: mov $0x5,%esi
0x00000000004005b7 <+13>: mov $0x6,%edi
0x00000000004005bc <+18>: callq 0x400596 <add(int, int)>
0x00000000004005c1 <+23>: mov %eax,-0x4(%rbp)
0x00000000004005c4 <+26>: mov -0x4(%rbp),%eax
0x00000000004005c7 <+29>: mov %eax,%esi
0x00000000004005c9 <+31>: mov $0x400678,%edi
0x00000000004005ce <+36>: mov $0x0,%eax
0x00000000004005d3 <+41>: callq 0x4004a0 <printf@plt>
0x00000000004005d8 <+46>: mov $0x0,%eax
0x00000000004005dd <+51>: leaveq
0x00000000004005de <+52>: retq
End of assembler dump.
(gdb) p $rbp
$4 = (void *) 0x7fffffffe420
(gdb) si
9 int p = add(6,5);
(gdb) p $rsp
$5 = (void *) 0x7fffffffe410
(gdb)

参考

用GDB调试程序

欢迎关注我的其它发布渠道