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

http://lenky.info/tag/%E8%B0%83%E8%AF%95/

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

2012年5月30日 lenky 没有评论 181 次浏览

关于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 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,那么还有一个方法显示汇编:

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)
分类: *nix技术, 跟踪调试 标签: C程序, GDB, 汇编, 调试

利用KVM调试内核

2012年5月12日 lenky 没有评论 224 次浏览

虽然kvm运行的虚拟机也是host的一个进程,但是却不能像UML那样直接gdb attach到对应的进程进行调试,毕竟kvm和uml完全不同,如果那样做的话,你会发现你attach的只是qemu-system-x86进程:

1
2
3
4
5
(gdb) bt
#0  0x00007f8dba022ed2 in select () from /lib64/libc.so.6
#1  0x00007f8dbdd2118a in ?? () from /usr/local/bin/qemu-system-x86_64
#2  0x00007f8dbdd1a798 in main () from /usr/local/bin/qemu-system-x86_64
(gdb)

要用gdb调试kvm虚拟机内核,需要借助qemu-system-x86的两个选项:

1
2
-s              shorthand for -gdb tcp::1234
-S              freeze CPU at startup (use 'c' to start execution)

选项-s使得可以通过gdb远程连接qemu进行调试,而-S将让kvm虚拟机停止在执行第一条内核镜像代码的地方,等待gdb连接,如果没有-S选项,那么kvm不等待:

1
[root@localhost kvm]# qemu- system -x86_64 -hda vdisk.img -net none -m 1024 -daemonize -cpu host -smp 2 -vnc :1 -s

gdb可以通过127.0.0.1:1234或:1234(gdb在本机执行)或192.168.1.1:1234(gdb在另外的机器执行,而kvm host机器ip为192.168.1.1),假设在本host执行gdb命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@localhost kvm]# gdb
GNU gdb Fedora (6.8-37.el5)
Copyright (C) 2008 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" .
(gdb) target remote :1234
Remote debugging using :1234
[New Thread 1]
Remote 'g' packet reply is too long : d85f8780ffffffff88f58680ffffffff00000000000000000000000000000000180000000000000020fb7c80ffffffff40318880ffffffff205f8780ffffffff000000000000000063c3dd712e00000072feff00000000004bb52180ffffffffb76ddbb66ddbb66d20748b80ffffffffc09c8b80ffffffff0000000000000000241c2280ffffffff4602000010000000180000001800000018000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007f03000000000000000000000000000000000000000000000000000000000000000000000000e03f00000000000000007b14ae47e17a843f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a01f0000
(gdb)

如果出现上面这种情况,需要先执行:set architecture i386:x86-64:intel,我的kvm客户机是x86-64:

1
2
[root@localhost ~]# uname -a
Linux localhost.localdomain 2.6.30-gentoo-r8 #55 SMP Thu May 10 20:05:44 CST 2012 x86_64 x86_64 x86_64 GNU/Linux

,使得gdb知道远程系统的架构:

1
2
3
4
5
6
7
(gdb) set architecture i386:x86-64:intel
The target architecture is assumed to be i386:x86-64:intel
(gdb) target remote :1234
Remote debugging using :1234
[New Thread 1]
0xffffffff80221c24 in ?? ()
(gdb)

加载对应的kvm客户机内核镜像,当然是未压缩的(务必选中内核选项:[*] Compile the kernel with debug info和[*] Compile the kernel with frame pointers):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
(gdb) file /tmp/vmlinux
A program is being debugged already.
Are you sure you want to change the file? (y or n) y
Reading symbols from /tmp/vmlinux...done.
(gdb) bt
#0  native_safe_halt () at /usr/src/linux-2.6.37.2/arch/x86/include/asm/irqflags.h:51
#1  0xffffffff80211e41 in default_idle ()
     at /usr/src/linux-2.6.37.2/arch/x86/include/asm/paravirt.h:802
#2  0xffffffff8020ab67 in cpu_idle ()
     at /usr/src/linux-2.6.37.2/arch/x86/kernel/process_64.c:149
#3  0xffffffff8061ab0d in rest_init () at /usr/src/linux-2.6.37.2/init/main.c:474
#4  0xffffffff808adcda in start_kernel () at /usr/src/linux-2.6.37.2/init/main.c:701
#5  0xffffffff808ad2a7 in x86_64_start_reservations (
     real_mode_data=<value optimized out>)
     at /usr/src/linux-2.6.37.2/arch/x86/kernel/head64.c:123
#6  0xffffffff808ad39f in x86_64_start_kernel (
     real_mode_data=0x93050 <Address 0x93050 out of bounds>)
     at /usr/src/linux-2.6.37.2/arch/x86/kernel/head64.c:94
#7  0x0000000000000000 in ?? ()
(gdb)

加个__schedule断点:

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
(gdb) c
Continuing.
^C
Program received signal SIGINT, Interrupt.
native_safe_halt () at /usr/src/linux-2.6.37.2/arch/x86/include/asm/irqflags.h:51
51  /usr/src/linux-2.6.37.2/arch/x86/include/asm/irqflags.h: No such file or directory.
     in /usr/src/linux-2.6.37.2/arch/x86/include/asm/irqflags.h
(gdb) b __schedule
Breakpoint 1 at 0xffffffff80636792: file /usr/src/linux-2.6.37.2/kernel/sched.c, line 5022.
(gdb) c
Continuing.
[New Thread 4]
[Switching to Thread 4]
 
Breakpoint 1, __schedule () at /usr/src/linux-2.6.37.2/kernel/sched.c:5022
5022    /usr/src/linux-2.6.37.2/kernel/sched.c: No such file or directory.
     in /usr/src/linux-2.6.37.2/kernel/sched.c
(gdb) bt
#0  __schedule () at /usr/src/linux-2.6.37.2/kernel/sched.c:5022
#1  0xffffffff80636f51 in schedule () at /usr/src/linux-2.6.37.2/kernel/sched.c:5084
#2  0xffffffff8020ab88 in cpu_idle ()
     at /usr/src/linux-2.6.37.2/arch/x86/kernel/process_64.c:159
#3  0xffffffff80632a4e in start_secondary (unused=<value optimized out>)
     at /usr/src/linux-2.6.37.2/arch/x86/kernel/smpboot.c:329
#4  0x0000000000000000 in ?? ()
(gdb)

利用命令q退出gdb时,如果导致kvm虚拟机终止,此时需先执行detach命令,后再退出gdb:

1
2
3
4
5
6
7
(gdb) q
The program is running.  Exit anyway? (y or n) n
Not confirmed.
(gdb) detach
Ending remote debugging.
(gdb) q
[root@localhost kvm]#

对于内核调试的一个十分有利帮助是串口的使用,kvm虚拟机的串口可以这样添加:

1
[root@localhost kvm]# qemu- system -x86_64 -hda vdisk.img -net none -m 1024 -daemonize -cpu host -smp 2 -vnc :1 -s -serial file:serial. log

这将在当前目录下生成一个serial.log的文件,kvm虚拟机的串口输出将重定向到这个文件内,比如给kvm虚拟机的内核加上串口输出选项(console=ttyS0,115200)后,kvm虚拟机的内核信息将输出到这个文件:

1
2
3
[root@localhost kvm]# ls serial. log -lh
-rw-r----- 1 root root 21K May 11 16:56 serial. log
[root@localhost kvm]#

还可以将kvm虚拟机的串口重定向到一个tcp监听口:

1
2
[root@localhost kvm]# qemu- system -x86_64 -hda vdisk.img -net none -m 1024 -daemonize -cpu host -smp 2 -vnc :1 -s -serial tcp::1235,server
QEMU waiting for connection on: tcp:0.0.0.0:1235,server

执行qemu-system-x86_64后进行等待链接状态,在本机可以执行(当然,你需要另开一个终端):

1
[root@localhost ~]# telnet 127.0.0.1 1235

在另外的机器,那么可执行(前面已交代这里kvm host机器的ip为192.168.1.1):

1
[root@localhost ~]# telnet 192.168.1.1 1235

之后,kvm虚拟机的串口输出将都打印在telnet上,并且此时可通过这个串口通道登陆kvm虚拟机。
另外,发现一个问题就是通过windows上的VNC Viewer 4远程连接到kvm虚拟机,进入grub后键盘就无响应,任何对内核选项的上下选择、编辑或启动都失效,此时无法做任何操作,只能在host机器内kill qemu-system-x86_64。如果在升级内核,这非常不方便,但值得庆幸的是qemu-system-x86_64支持直接在外部指定内核镜像(具体可以参考qemu-system-x86_64 –help):

1
2
[root@localhost kvm]# qemu- system -x86_64 -hda vdisk.img -net none -m 1024 -daemonize -cpu host -smp 2 -vnc :1 -kernel vmlinuz-2.6.18-194.el5 -initrd initrd-2.6.18-194.el5.img
[root@localhost kvm]#

所以,在装好最初的kvm虚拟机后立马把这两个文件备份到host机器来,这样如果后续捣鼓其它内核出了问题还能通过这种方法进入kvm虚拟机内进行修复(也许还可以利用其它工具,比如http://libguestfs.org/来进行,不过毕竟不是直接手段而比较麻烦)。
kvm虚拟机模块的调试要麻烦一点,首先需要在gdb里主动加载对应模块的符号,并且要加载到正确的位置。模块的代码位置可以在kvm虚拟机使用如下命令查看:

1
2
3
4
[root@localhost ~]# cat /proc/modules
igb 84012 0 - Live 0xffffffffa0007000
dca 6468 1 igb, Live 0xffffffffa0000000
[root@localhost ~]#

只加载了两个模块,以igb模块为例,在host机内的gdb内执行add-symbol-file,其中/tmp/igb.ko是kvm虚拟机的igb模块文件,拷贝到host机器内的,而0xffffffffa0007000是从上面/proc/modules文件内看到的:

1
2
3
4
5
6
7
(gdb) add-symbol-file /tmp/igb.ko 0xffffffffa0007000
add symbol table from file "/tmp/igb.ko" at
     .text_addr = 0xffffffffa0007000
(y or n) y
Reading symbols from /tmp/igb.ko...done.
(gdb) c
Continuing.

设置一个igb模块内的igb_clean_tx_irq函数断点试试,马上断下来了(因为我这里使用了igb ssh远程连接),看来没什么问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
(gdb) b igb_clean_tx_irq
Breakpoint 2 at 0xffffffffa000a5a8
(gdb) c
Continuing.
[New Thread 2]
[Switching to Thread 2]
 
Breakpoint 2, 0xffffffffa000a5a8 in igb_clean_tx_irq ()
(gdb) bt
#0  0xffffffffa000a5a8 in igb_clean_tx_irq ()
#1  0xffffffffa000c19e in igb_msix_tx ()
#2  0xffffffff8027cb92 in handle_IRQ_event (irq=27, action=0xffff88003e18bf40)
     at /usr/src/linux-2.6.37.2/kernel/irq/handle.c:371
#3  0xffffffff8027e9f0 in handle_edge_irq (irq=27, desc=0xffff88003e6a85c0)
     at /usr/src/linux-2.6.37.2/kernel/irq/chip.c:514
#4  0xffffffff8020de43 in handle_irq (irq=27, regs=<value optimized out>)
     at /usr/src/linux-2.6.37.2/include/linux/irq.h:312
#5  0xffffffff8020d6a1 in do_IRQ (regs=0xffff88003f89de18) at /usr/src/linux-2.6.37.2/arch/x86/kernel/irq.c:215
#6  0xffffffff8020c453 in common_interrupt ()
#7  0xffff88003f89de40 in ?? ()
#8  0x0000000000000000 in ?? ()
(gdb) c
Continuing.

如果不执行对应的add-symbol-file命令,那么将会这样:

1
2
3
(gdb) b igb_clean_tx_irq
Function "igb_clean_tx_irq" not defined.
Make breakpoint pending on future shared library load? (y or [n]) n

就算选择y,后续也不能捕获到该断点。

分类: *nix技术, 仿真虚拟, 内核技术, 跟踪调试 标签: kvm, 内核, 调试

Linux下逆向工具

2012年1月12日 lenky 没有评论 366 次浏览

Windows下有很多逆向工具Linux下也有,当然,和Windows平台有所不同的是,Linux下的逆向工具主要是用来定位和分析程序的问题,比如当应用程序崩溃之后,如何从core文件里给出的信息查出原因所在。
曾经用过的一些命令如下(只列出主要功能):
addr2line:根据一个代码地址,定位到对应的源文件与代码行。
nm:列出程序里的符号。
objdump:反汇编。
readelf:显示任何ELF格式目标文件里的相关符号信息。
等等。

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
[root@localhost db]# addr2line -e xfs_db -f 44c794
xfs_attr_leaf_add
/root/xfs.code/xfsprogs/libxfs/xfs_attr_leaf.c:785
[root@localhost db]# nm ./xfs_db
000000000047caa0 r C.135.10410
000000000046c608 t INIT_HLIST_NODE
0000000000692da4 b Rflag
0000000000692028 d _DYNAMIC
00000000006921f0 d _GLOBAL_OFFSET_TABLE_
000000000046e0c0 R _IO_stdin_used
                  w _Jv_RegisterClasses
0000000000692008 d __CTOR_END__
0000000000692000 d __CTOR_LIST__
0000000000692018 D __DTOR_END__
0000000000692010 d __DTOR_LIST__
0000000000491660 r __FRAME_END__
00000000004806e0 r __FUNCTION__.10009
...
[root@localhost db]# objdump --source xfs_db
 
xfs_db:     file format elf64-x86-64
 
Disassembly of section .init:
 
0000000000401e68 <_init>:
   401e68:   48 83 ec 08             sub    $0x8,%rsp
   401e6c:   e8 1b 07 00 00          callq  40258c <call_gmon_start>
   401e71:   e8 9a 07 00 00          callq  402610 <frame_dummy>
   401e76:   e8 e5 c1 06 00          callq  46e060 <__do_global_ctors_aux>
   401e7b:   48 83 c4 08             add    $0x8,%rsp
   401e7f:   c3                      retq
Disassembly of section .plt:
 
0000000000401e80 < ctime @plt-0x10>:
   401e80:   ff 35 72 03 29 00       pushq  2687858(%rip)        # 6921f8 <_GLOBAL_OFFSET_TABLE_+0x8>
   401e86:   ff 25 74 03 29 00       jmpq   *2687860(%rip)        # 692200 <_GLOBAL_OFFSET_TABLE_+0x10>
   401e8c:   0f 1f 40 00             nopl   0x0(%rax)
...
[root@localhost db]# readelf -S xfs_db
There are 37 section headers, starting at offset 0x1a8fb8:
 
Section Headers:
   [Nr] Name              Type             Address           Offset
        Size              EntSize          Flags  Link  Info  Align
   [ 0]                   NULL             0000000000000000  00000000
        0000000000000000  0000000000000000           0     0     0
   [ 1] .interp           PROGBITS         0000000000400200  00000200
        000000000000001c  0000000000000000   A       0     0     1
...
   [34] .shstrtab         STRTAB&

你可能感兴趣的:(利用gdb在汇编指令级调试C程序)