首页 > *nix技术, 跟踪调试 > 利用gdb在汇编指令级调试C程序

利用gdb在汇编指令级调试C程序

2012年5月30日 发表评论 阅读评论 6,101 次浏览

关于GDB调试C程序的常用命令与手段就不多说了,这里主要介绍一下如何对C程序做到汇编指令级别的调试。
首先是获取汇编代码,这可以通过disassemble命令或x命令或类似的命令:

[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寄存器内存储的是机器码),我们可以看看(先得把程序执行起来):

(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) 

看汇编指令:

(gdb) p $rip
$2 = (void (*)()) 0x400467 <main+4>
(gdb) x/i $rip
0x400467 <main+4>:	mov    $0x5,%r8d
(gdb) 

我们还可以利用一个名为pc的gdb内部变量:

(gdb) p $pc
$3 = (void (*)()) 0x400467 <main+4>
(gdb) x/i $pc
0x400467 <main+4>:	mov    $0x5,%r8d
(gdb) 

结合display命令和寄存器或pc内部变量,我们做如下设置:

(gdb) display /i $pc
1: x/i $pc
0x400467 <main+4>:	mov    $0x5,%r8d
(gdb) 

或同时显示多条汇编,比如3条:

(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)命令进行汇编指令级的调试,如下所示可以看到参数是如何传递的:

(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显示汇编代码窗口:

(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 register window. If existing layout
           is source/command or assembly/command, the 
           register window is displayed. If the
           source/assembly/command (split) is displayed, 
           the register window 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,那么还有一个方法显示汇编:

[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 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-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源码同时显示:

(gdb) disas /m main
Dump of assembler code for function main:
9	int main(){
   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		return 2;
   0x0000000000400486 <+35>:	mov    $0x2,%eax

12	}
   0x000000000040048b <+40>:	leaveq 
   0x000000000040048c <+41>:	retq   

End of assembler dump.
(gdb) 

转载请保留地址:http://www.lenky.info/archives/2012/05/1694http://lenky.info/?p=1694


备注:如无特殊说明,文章内容均出自Lenky个人的真实理解而并非存心妄自揣测来故意愚人耳目。由于个人水平有限,虽力求内容正确无误,但仍然难免出错,请勿见怪,如果可以则请留言告之,并欢迎来讨论。另外值得说明的是,Lenky的部分文章以及部分内容参考借鉴了网络上各位网友的热心分享,特别是一些带有完全参考的文章,其后附带的链接内容也许更直接、更丰富,而我只是做了一下归纳&转述,在此也一并表示感谢。关于本站的所有技术文章,欢迎转载,但请遵从CC创作共享协议,而一些私人性质较强的心情随笔,建议不要转载。

法律:根据最新颁布的《信息网络传播权保护条例》,如果您认为本文章的任何内容侵犯了您的权利,请以Email或书面等方式告知,本站将及时删除相关内容或链接。

  1. 本文目前尚无任何评论.
  1. 本文目前尚无任何 trackbacks 和 pingbacks.