gdb 调试汇编

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

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 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://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



(gdb) info register r1
r1             0xbffffb40    3221224256
(gdb) info registers
r0             0x1000052c    268436780
r1             0xbffffb40    3221224256
r2             0x48026ea0    1208118944
r3             0x14    20
r4             0xfef2d90    267333008
r5             0x0    0
r6             0x1    1
r7             0xff4f67c    267712124
r8             0x202d000    33738752
r9             0x1    1
r10            0x0    0
r11            0xbffffa70    3221224048
r12            0x20000082    536871042
r13            0x100189d0    268536272
r14            0x0    0
r15            0x0    0
r16            0x0    0
r17            0x0    0
r18            0x0    0
r19            0x0    0
r20            0x0    0
r21            0x0    0
r22            0x0    0
---Type to continue, or q to quit--- 
r23            0x0    0
r24            0x0    0
r25            0x0    0
r26            0x0    0
r27            0x4802f52c    1208153388
r28            0x48030018    1208156184
r29            0x0    0
r30            0xffebff4    268353524
r31            0xbffffb40    3221224256
pc             0x1000052c    0x1000052c 
msr            0x2d900    186624
cr             0x2a000022    704643106
lr             0x1000052c    0x1000052c 
ctr            0xc027c8fc    3223832828
xer            0x0    0
acc            0x0    0
spefscr        0x3c    60
orig_r3        0x1    1
trap           0x700    1792

你可以使用examine命令(简写是x)来查看内存地址中的值。x命令的语法如下所示:

x/ 

n、f、u是可选的参数。

n 是一个正整数,表示显示内存的长度,也就是说从当前地址向后显示几个地址的内容。
f 表示显示的格式,参见上面。如果地址所指的是字符串,那么格式可以是s,如果地十是指令地址,那么格式可以是i。
u 表示从当前地址往后请求的字节数,如果不指定的话,GDB默认是4个bytes。u参数可以用下面的字符来代替,b表示单字节,h表示双字节,w表示四字 节,g表示八字节。当我们指定了字节长度后,GDB会从指内存定的内存地址开始,读写指定字节,并把其当作一个值取出来。

表示一个内存地址。
n/f/u三个参数可以一起使用。例如:

命令:x/3uh 0x54320 表示,从内存地址0x54320读取内容,h表示以双字节为一个单位,3表示三个单位,u表示按十六进制显示。

输出格式
一般来说,GDB会根据变量的类型输出变量的值。但你也可以自定义GDB的输出的格式。例如,你想输出一个整数的十六进制,或是二进制来查看这个整型变量 的中的位的情况。要做到这样,你可以使用GDB的数据显示格式:

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


原文件:
double z = 39.2315;
float x = 39.2315;

调试过程:
Breakpoint 1, main () at testall.c:15
15              //double a = 2.0 * z;
(gdb) info addr x
Symbol "x" is static storage at address 0x100109d8.
(gdb) info addr z
Symbol "z" is static storage at address 0x100109d0.
(gdb) x /1fw 0x100109d8
0x100109d8 : 39.2314987
(gdb) p x
$1 = 39.2314987
(gdb) p z
$2 = 39.231499999999997
(gdb) x /1fg 0x100109d0
0x100109d0 : 39.231499999999997
(gdb)

由此可见float的精度差很多。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值