关于
GDB调试C程序的
常用命令与手段就不多说了,这里主要介绍一下如何对C程序做到
汇编指令级别的调试。
首先是获取汇编代码,这可以通过disassemble命令或x命令或类似的命令:
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
[root@localhost test]# gdb ./a.out -q
(gdb) list
1 #include<stdio.h>
2 #include<malloc.h>
3
4 int callee(int a, int b, int c, int d, int e)
5 {
6 return 1;
7 }
8
9 int main(){
10 callee(1,2,3,4,5);
(gdb) disassemble main
Dump of assembler code for function main:
0x0000000000400463 <main+0>: push %rbp
0x0000000000400464 <main+1>: mov %rsp,%rbp
0x0000000000400467 <main+4>: mov $0x5,%r8d
0x000000000040046d <main+10>: mov $0x4,%ecx
0x0000000000400472 <main+15>: mov $0x3,%edx
0x0000000000400477 <main+20>: mov $0x2,%esi
0x000000000040047c <main+25>: mov $0x1,%edi
0x0000000000400481 <main+30>: callq 0x400448 <callee>
0x0000000000400486 <main+35>: mov $0x2,%eax
0x000000000040048b <main+40>: leaveq
0x000000000040048c <main+41>: retq
End of assembler dump.
(gdb) x/10i main
0x400463 <main>: push %rbp
0x400464 <main+1>: mov %rsp,%rbp
0x400467 <main+4>: mov $0x5,%r8d
0x40046d <main+10>: mov $0x4,%ecx
0x400472 <main+15>: mov $0x3,%edx
0x400477 <main+20>: mov $0x2,%esi
0x40047c <main+25>: mov $0x1,%edi
0x400481 <main+30>: callq 0x400448 <callee>
0x400486 <main+35>: mov $0x2,%eax
0x40048b <main+40>: leaveq
(gdb)
接着,利用display命令自动显示当前正要执行的汇编指令,
display命令可以在每次程序暂停时自动打印指定变量的值。而我们要显示的汇编指令在ip寄存器内(当然,ip寄存器内存储的是机器码),我们可以看看(先得把程序执行起来):
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) b main
Breakpoint 1 at 0x400467: file t3.5.c, line 10.
(gdb) r
Starting program: /root/test/a.out
Breakpoint 1, main () at t3.5.c:10
10 callee(1,2,3,4,5);
(gdb) info reg
rax 0x3cd2153a60 261222644320
rbx 0x3cd101bbc0 261204589504
rcx 0x4004a0 4195488
rdx 0x7fffc5f6fa38 140736514685496
rsi 0x7fffc5f6fa28 140736514685480
rdi 0x1 1
rbp 0x7fffc5f6f940 0x7fffc5f6f940
rsp 0x7fffc5f6f940 0x7fffc5f6f940
r8 0x3cd21522d0 261222638288
r9 0x3cd0e0d620 261202433568
r10 0x0 0
r11 0x3cd1e1d8a0 261219276960
r12 0x0 0
r13 0x7fffc5f6fa20 140736514685472
r14 0x0 0
r15 0x0 0
rip 0x400467 0x400467 <main+4>
eflags 0x246 [ PF ZF IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
fctrl 0x37f 895
fstat 0x0 0
ftag 0xffff 65535
fiseg 0x0 0
fioff 0x0 0
foseg 0x0 0
fooff 0x0 0
fop 0x0 0
mxcsr 0x1f80 [ IM DM ZM OM UM PM ]
(gdb)
看汇编指令:
1
2
3
4
5
(gdb) p $rip
$2 = (void(*)()) 0x400467 <main+4>
(gdb) x/i $rip
0x400467 <main+4>: mov $0x5,%r8d
(gdb)
我们还可以利用一个名为
pc的gdb内部变量:
1
2
3
4
5
(gdb) p $pc
$3 = (void(*)()) 0x400467 <main+4>
(gdb) x/i $pc
0x400467 <main+4>: mov $0x5,%r8d
(gdb)
结合display命令和寄存器或pc内部变量,我们做如下设置:
1
2
3
4
(gdb) display /i $pc
1: x/i $pc
0x400467 <main+4>: mov $0x5,%r8d
(gdb)
或同时显示多条汇编,比如3条:
1
2
3
4
5
6
7
8
9
10
11
12
13
(gdb) display /3i $pc
(gdb) b main
Breakpoint 1 at 0x400467: file t3.5.c, line 10.
(gdb) r
Starting program: /root/test/a.out
Breakpoint 1, main () at t3.5.c:10
10 callee(1,2,3,4,5);
1: x/3i $pc
0x400467 <main+4>: mov $0x5,%r8d
0x40046d <main+10>: mov $0x4,%ecx
0x400472 <main+15>: mov $0x3,%edx
(gdb)
接下来,利用
ni(nexti)或si(stepi)命令进行汇编指令级的调试,如下所示可以看到参数是如何传递的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
(gdb) display /i $pc
1: x/i $pc
0x400467 <main+4>: mov $0x5,%r8d
(gdb) ni
0x000000000040046d 10 callee(1,2,3,4,5);
1: x/i $pc
0x40046d <main+10>: mov $0x4,%ecx
(gdb) ni
0x0000000000400472 10 callee(1,2,3,4,5);
1: x/i $pc
0x400472 <main+15>: mov $0x3,%edx
(gdb) ni
0x0000000000400477 10 callee(1,2,3,4,5);
1: x/i $pc
0x400477 <main+20>: mov $0x2,%esi
(gdb) ni
0x000000000040047c 10 callee(1,2,3,4,5);
1: x/i $pc
0x40047c <main+25>: mov $0x1,%edi
(gdb)
更简单直接的方法是利用
layout显示汇编代码窗口:
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
(gdb) help layout
Change the layout of windows.
Usage: layout prev | next | <layout_name>
Layout names are:
src : Displays source and command windows.
asm : Displays disassembly and command windows.
split : Displays source, disassembly and command windows.
regs : Displays registerwindow. If existing layout
is source/command or assembly/command, the
registerwindow is displayed. If the
source/assembly/command (split) is displayed,
theregisterwindow is displayed with
the window that has current logical focus.
(gdb) layout asm lqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqk
x0x400463 <main> push %rbp x
x0x400464 <main+1> mov %rsp,%rbp x
x0x400467 <main+4> mov $0x5,%r8d x
x0x40046d <main+10> mov $0x4,%ecx x
x0x400472 <main+15> mov $0x3,%edx x
x0x400477 <main+20> mov $0x2,%esi x
x0x40047c <main+25> mov $0x1,%edi x
x0x400481 <main+30> callq 0x400448 <callee> x
x0x400486 <main+35> mov $0x2,%eax x
x0x40048b <main+40> leaveq x
x0x40048c <main+41> retq x
x0x40048d nop x
x0x40048e nop x
x0x40048f nop x
x0x400490 <__libc_csu_fini> repz retq x
x0x400492 nopl 0x0(%rax) x
x0x400499 nopl 0x0(%rax) x
x0x4004a0 <__libc_csu_init> mov %r12,-0x20(%rsp) x
x0x4004a5 <__libc_csu_init+5> mov %r13,-0x18(%rsp) x
x0x4004aa <__libc_csu_init+10> lea 0x2001bb(%rip),%r12 # 0x60066c x
x0x4004b1 <__libc_csu_init+17> mov %r14,-0x10(%rsp) x
x0x4004b6 <__libc_csu_init+22> mov %r15,-0x8(%rsp) x
x0x4004bb <__libc_csu_init+27> mov %rsi,%r14 x
x0x4004be <__libc_csu_init+30> mov %rbx,-0x30(%rsp) x
x0x4004c3 <__libc_csu_init+35> mov %rbp,-0x28(%rsp) x
x0x4004c8 <__libc_csu_init+40> sub $0x38,%rsp x
mqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqj
exec No process In: Line: ?? PC: 0x0
(gdb)
如果是7.0版本以上的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
[root@localhost gdb-7.4.1]# ./gdb/gdb -version | grep "(GDB)"
GNU gdb (GDB) 7.4.1
[root@localhost gdb-7.4.1]# ./gdb/gdb ~/test/a.out
GNU gdb (GDB) 7.4.1
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is freesoftware: you are freeto 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-unknown-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /root/test/a.out...done.
(gdb) set disassemble-next-line on
(gdb) b main
Breakpoint 1 at 0x400467: file t3.5.c, line 10.
(gdb) r
Starting program: /root/test/a.out
Breakpoint 1, main () at t3.5.c:10
10 callee(1,2,3,4,5);
=> 0x0000000000400467 <main+4>: 41 b8 05 00 00 00 mov $0x5,%r8d
0x000000000040046d <main+10>: b9 04 00 00 00 mov $0x4,%ecx
0x0000000000400472 <main+15>: ba 03 00 00 00 mov $0x3,%edx
0x0000000000400477 <main+20>: be 02 00 00 00 mov $0x2,%esi
0x000000000040047c <main+25>: bf 01 00 00 00 mov $0x1,%edi
0x0000000000400481 <main+30>: e8 c2 ff ff ff callq 0x400448 <callee>
(gdb) ni
0x000000000040046d 10 callee(1,2,3,4,5);
0x0000000000400467 <main+4>: 41 b8 05 00 00 00 mov $0x5,%r8d
=> 0x000000000040046d <main+10>: b9 04 00 00 00 mov $0x4,%ecx
0x0000000000400472 <main+15>: ba 03 00 00 00 mov $0x3,%edx
0x0000000000400477 <main+20>: be 02 00 00 00 mov $0x2,%esi
0x000000000040047c <main+25>: bf 01 00 00 00 mov $0x1,%edi
0x0000000000400481 <main+30>: e8 c2 ff ff ff callq 0x400448 <callee>
(gdb)
另外,7.0版本以上gdb的disas命令可以携带/m参数,让汇编与c源码同时显示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
(gdb) disas /m main
Dump of assembler code forfunction main:
9 intmain(){
0x0000000000400463 <+0>: push %rbp
0x0000000000400464 <+1>: mov %rsp,%rbp
10 callee(1,2,3,4,5);
0x0000000000400467 <+4>: mov $0x5,%r8d
0x000000000040046d <+10>: mov $0x4,%ecx
0x0000000000400472 <+15>: mov $0x3,%edx
0x0000000000400477 <+20>: mov $0x2,%esi
0x000000000040047c <+25>: mov $0x1,%edi
0x0000000000400481 <+30>: callq 0x400448 <callee>
11 return2;
0x0000000000400486 <+35>: mov $0x2,%eax
12 }
0x000000000040048b <+40>: leaveq
0x000000000040048c <+41>: retq
End of assembler dump.
(gdb)
转载请保留地址:
http://lenky.info/2012/05/30/%e5%88%a9%e7%94%a8gdb%e5%9c%a8%e6%b1%87%e7%bc%96%e6%8c%87%e4%bb%a4%e7%ba%a7%e8%b0%83%e8%af%95c%e7%a8%8b%e5%ba%8f/或
http://lenky.info/?p=1694备注:如无特殊说明,文章内容均出自
Lenky个人的真实理解而并非存心妄自揣测来故意愚人耳目。由于个人水平有限,虽力求内容正确无误,但仍然难免出错,请勿见怪,如果可以则请留言告之,并欢迎来
信讨论。另外值得说明的是,
Lenky的部分文章以及部分内容参考借鉴了网络上各位网友的热心分享,特别是一些带有完全参考的文章,其后附带的链接内容也许更直接、更丰富,而我只是做了一下归纳&转述,在此也一并表示感谢。关于本站的所有技术文章,欢迎转载,但请遵从
CC创作共享协议,而一些私人性质较强的心情随笔,建议不要转载。
法律:根据最新颁布的《信息网络传播权保护条例》,如果您认为本文章的任何内容侵犯了您的权利,请以
Email或书面等方式告知,本站将及时删除相关内容或链接。