zoukankan      html  css  js  c++  java
  • C实战:强大的程序调试工具GDB

    C实战:强大的程序调试工具GDB

    1.基本调试

    这里只列举最最常用的GDB命令。

    1.1 启动GDB

    gdb program:准备调试程序。也可以直接进入gdb,再通过file命令加载。

    1.2 添加断点

    b function:为函数设置断点。b是break的缩写,除了函数名,还可以是地址、当前执行处的+/-偏移等。

    1.3 运行程序

    run args:开始运行程序,run后面可以加程序需要的参数,就像在命令行正常运行时那样。

    1.4 单步调试

    s/n/si/c/kill:s即step in,进入下一行代码执行;n即step next,执行下一行代码但不进入;si即step instruction,执行下一条汇编/CPU指令;c即continue,继续执行直到下一个断点处;kill终止调试;quit退出GDB。

    1.5 打印调试信息

    bt:bt是backtrace的缩写,打印当前所在函数的堆栈路径。
    info frame id:打印选中的栈帧的信息。
    info args:打印选中栈帧的参数。
    print variable:打印指定变量的值。
    list:列出相应的源代码。
    info registers:查看所有寄存器的值。

    还有个更灵活强大的是直接打印%esp开始的前N个元素,例如打印栈上前10个元素就是:x/10x $sp

    2.GDB实战

    下面是一个使用了上述命令的实战例子:

    [root@BC-VM-edce4ac67d304079868c0bb265337bd4 bufbomb]# gdb bufbomb 
    GNU gdb (GDB) Red Hat Enterprise Linux (7.2-75.el6)
    Copyright (C) 2010 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".
    For bug reporting instructions, please see:
    <http://www.gnu.org/software/gdb/bugs/>...
    Reading symbols from /root/Temp/bufbomb/bufbomb...done.
    (gdb) b getbuf
    Breakpoint 1 at 0x8048ad6
    (gdb) run -t cdai
    Starting program: /root/Temp/bufbomb/bufbomb -t cdai
    Team: cdai
    Cookie: 0x5e5ee04e
    
    Breakpoint 1, 0x08048ad6 in getbuf ()
    Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.149.el6_6.4.i686
    
    (gdb) bt
    #0  0x08048ad6 in getbuf ()
    #1  0x08048db2 in test ()
    #2  0x08049085 in launch ()
    #3  0x08049257 in main ()
    (gdb) info frame 0
    Stack frame at 0xffffb540:
     eip = 0x8048ad6 in getbuf; saved eip 0x8048db2
     called by frame at 0xffffb560
     Arglist at 0xffffb538, args: 
     Locals at 0xffffb538, Previous frame's sp is 0xffffb540
     Saved registers:
      ebp at 0xffffb538, eip at 0xffffb53c
    (gdb) info registers
    eax            0xc      12
    ecx            0xffffb548       -19128
    edx            0xc8c340 13157184
    ebx            0x0      0
    esp            0xffffb510       0xffffb510
    ebp            0xffffb538       0xffffb538
    esi            0x804b018        134524952
    edi            0xffffffff       -1
    eip            0x8048ad6        0x8048ad6 <getbuf+6>
    eflags         0x282    [ SF IF ]
    cs             0x23     35
    ss             0x2b     43
    ds             0x2b     43
    es             0x2b     43
    fs             0x0      0
    gs             0x63     99
    (gdb) x/10x $sp
    0xffffb510:     0xf7ffc6b0      0x00000001      0x00000001      0xffffb564
    0xffffb520:     0x08048448      0x0804a12c      0xffffb548      0x00c8aff4
    0xffffb530:     0x0804b018      0xffffffff
    
    (gdb) si
    0x08048ad9 in getbuf ()
    (gdb) si
    0x08048adc in getbuf ()
    (gdb) si
    0x080489c0 in Gets ()
    (gdb) n
    Single stepping until exit from function Gets,
    which has no line number information.
    Type string:123
    0x08048ae1 in getbuf ()
    (gdb) si
    0x08048ae2 in getbuf ()
    (gdb) c
    Continuing.
    Dud: getbuf returned 0x1
    Better luck next time
    
    Program exited normally.
    (gdb) quit

    3.逆向调试

    GDB 7.0后加入了Reversal Debugging功能。具体来说,比如我在getbuf()和main()上设置了断点,当启动程序时会停在main()函数的断点上。此时敲入record后continue到下一断点getbuf(),GDB就会记录从main()到getbuf()的运行时信息。现在用rn就可以逆向地从getbuf()调试到main()。就像《X战警:逆转未来》里一样,挺神奇吧!

    这种方式适合从bug处反向去找引起bug的代码,实用性因情况而异。当然,它也是有局限性的。像程序假如有I/O输出等外部条件改变时,GDB是没法“逆转”的。

    [root@vm bufbomb]# gdb bufbomb 
    GNU gdb (GDB) Red Hat Enterprise Linux (7.2-75.el6)
    Copyright (C) 2010 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".
    For bug reporting instructions, please see:
    <http://www.gnu.org/software/gdb/bugs/>...
    Reading symbols from /root/Temp/bufbomb/bufbomb...done.
    
    (gdb) b getbuf
    Breakpoint 1 at 0x8048ad6
    (gdb) b main
    Breakpoint 2 at 0x80490c6
    
    (gdb) run -t cdai
    The program being debugged has been started already.
    Start it from the beginning? (y or n) y
    
    Starting program: /root/Temp/bufbomb/bufbomb -t cdai
    
    Breakpoint 2, 0x080490c6 in main ()
    (gdb) record
    (gdb) c
    Continuing.
    Team: cdai
    Cookie: 0x5e5ee04e
    
    Breakpoint 1, 0x08048ad6 in getbuf ()
    
    (gdb) rn
    Single stepping until exit from function getbuf,
    which has no line number information.
    0x08048dad in test ()
    (gdb) rn
    Single stepping until exit from function test,
    which has no line number information.
    0x08049080 in launch ()
    (gdb) rn
    Single stepping until exit from function launch,
    which has no line number information.
    0x08049252 in main ()
  • 相关阅读:
    div与>div区别小结
    自定义动画方法animate
    字符串与json之间的相互转化
    onclick事件与onserverclick事件
    jQuery实现隐藏标签
    CS0016: 未能写入输出文件“c:WindowsMicrosoft.NETFramework64v4.0.30319Temporary ASP.NET Fileshelloiisceb8cab34db603d8App_global.asax.gr73hi-k.dll”--“拒绝访问。 ”
    关于迭代器中IEnumerable与IEnumerator的区别
    C#中部分方法返回值类型为什么只能是void?
    抽象函数与虚函数
    括号配对问题
  • 原文地址:https://www.cnblogs.com/xiaomaohai/p/6157616.html
Copyright © 2011-2022 走看看