调试利器GDB-上

Posted dengqiangjiayou

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了调试利器GDB-上相关的知识,希望对你有一定的参考价值。

调试利器GDB-上

  • 什么是GDB?

    • GNU项目中的调试器(gnu debuger)
    • 能够跟踪程序的执行,也能够恢复程序崩溃前的状态
  • 为什么需要GDB?

    • 软件不是一次性开发完成的(是软件就有bug,是程序就有问题)
    • 调试是软件开发过程中不可获取的技术(调试工具也很重要)
  • GDB的常规应用

    • 自定义程序的启动方式(指定影程序运行的参数)
    • 设置条件断点
    • 回溯检查导致程序异常结束的原因(需要Core Dump)
    • 动态改变程序的执行流(定位问题的辅助方式)
  • GDB的启动方式

    • 直接启动

      • gdb(在Ubuntu命令行下)
      • gdb test.out
      • gdb test.out core
    • 动态链接

      • gdb test.out pid
    • GDB应用实例

      • gdb (在目标文件夹下启动GDB)

      • file test.out (载入目标程序,.out文件是编译产生的文件)

      • set args arg1 arg2 (设置命令行参数)

      • run (执行目标文件,也可以start可以以断点的形式停止在main函数的入口处)

    topeet@ubuntu:~/Desktop/Code$ ls
    a.out  core  func.c  test.c  test.i  test.out
    topeet@ubuntu:~/Desktop/Code$ gdb
    GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04
    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-linux-gnu".
    For bug reporting instructions, please see:
    <http://bugs.launchpad.net/gdb-linaro/>.
    (gdb) file test.out 
    Reading symbols from /home/topeet/Desktop/Code/test.out...done.
    (gdb) set args HelloWorld
    (gdb) run
    Starting program: /home/topeet/Desktop/Code/test.out HelloWorld
    main() : begin...
    argv[0] = /home/topeet/Desktop/Code/test.out //传入的参数
    argv[1] = HelloWorld
    test_1() : 0x400584 //已经开始main函数了
    test_2() : 0x4005a1
    ^C
    Program received signal SIGINT, Interrupt.
    0x00007ffff7adb050 in nanosleep () from /lib/x86_64-linux-gnu/libc.so.6
    (gdb) 
    
    
  • 使用GDB进行断点调试

    • 断点类型

      • 软件断点:由非法指令异常实现(软件实现)运行在内存里面的程序可以用软件断点来调试
      • 硬件断点:由硬件特性实现(所以数量有限)加载到flash/ROM里面的程序可以用硬件断点来调试
      • 数据断点:由硬件特性实现(基于硬件断点实现,数量有限)某个设定的数据被读或被写程序就会立即停止并打印相关信息
    • 软件断点的相关操作

      • 通过函数名来设置断点
        • break func_name [if var = value] //后面中括号可用可不用
        • tbreak func_name [if var = value]
      • 通过文件名行号设置断点
        • break file_name:line_name [if var = value]
        • tbreak file_name:line_name [if var = value]
    • 软件断点相关操作

    操作命令
    断点查看info breakpoints
    断点删除delete 1 2 n
    delete breakpoints //删除所有断点
    断点状态改变enable 1 2 n
    enable breakpoints
    disable 1 2 n
    disable breakpoints
    • 调试时常用的操作
    操作命令
    变量查看print name
    变量设置set var name = value
    执行下一行代码next
    连续执行n行代码next n
    执行进入函数step //执行到函数体使用step进入函数
    强制当前函数返回return [value] //强制以value值返回当前函数,当前函数可能存在错误
    运行至当前函数返回finish
    执行至目标行until line
    跳转执行jump line //强制跳转到目标行,也可以强制跳转过有问题的函数
    • 硬件断点及其应用
      • 当代码位于只读存储器(flash)时,只能通过硬件断点调试
      • 硬件断点需要硬件支持,数量有限
      • GDB通过hbreak命令支持硬件断点
      • hbeak与break使用方式完全一致

    第一次调试:

    topeet@ubuntu:~/Desktop/Code$ ls //查看文件
    a.out  core  func.c  test.c  test.i  test.out
    topeet@ubuntu:~/Desktop/Code$ gdb test.out //执行.out文件
    GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04
    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-linux-gnu".
    For bug reporting instructions, please see:
    <http://bugs.launchpad.net/gdb-linaro/>...
    Reading symbols from /home/topeet/Desktop/Code/test.out...done.
    (gdb) set args HelloWorld //设置main参数
    (gdb) start //自动设置临时断点,进入main函数的第一行就停止
    Temporary breakpoint 1 at 0x4005ea: file test.c, line 25.
    Starting program: /home/topeet/Desktop/Code/test.out HelloWorld
    
    Temporary breakpoint 1, main (argc=2, argv=0x7fffffffe2a8) at test.c:25
    25	    
    (gdb) break test.c:37 //设置断点
    Breakpoint 2 at 0x400658: file test.c, line 37.
    (gdb) continue //继续执行
    Continuing.
    main() : begin...
    argv[0] = /home/topeet/Desktop/Code/test.out
    argv[1] = HelloWorld
    
    Breakpoint 2, main (argc=2, argv=0x7fffffffe2a8) at test.c:37
    37	    }
    (gdb) info breakpoints  //查看断点信息
    Num     Type           Disp Enb Address            What
    2       breakpoint     keep y   0x0000000000400658 in main at test.c:37
    	breakpoint already hit 1 time
    (gdb) next //执行下一个程序
    test_1() : 0x400584
    38	
    (gdb) next
    35	        fa[i%3]();
    (gdb) next 3 //执行3条程序
    
    Breakpoint 2, main (argc=2, argv=0x7fffffffe2a8) at test.c:37
    37	    }
    (gdb) print i //打印变量的信息
    $1 = 1
    (gdb) set var i =100 //设置变量信息
    (gdb) print i
    $2 = 100
    (gdb) next
    test_2() : 0x4005a1
    38	
    (gdb) next
    35	        fa[i%3]();
    (gdb) next
    41	    
    (gdb) tbreak test.c:43 //设置临时断点
    Temporary breakpoint 3 at 0x4006bb: file test.c, line 43.
    (gdb) info breakpoints 
    Num     Type           Disp Enb Address            What
    2       breakpoint     keep y   0x0000000000400658 in main at test.c:37
    	breakpoint already hit 2 times
    3       breakpoint     del  y   0x00000000004006bb in main at test.c:43
    (gdb) continue 
    Continuing.
    g_pointer = (nil)
    
    Temporary breakpoint 3, main (argc=2, argv=0x7fffffffe2a8) at test.c:43
    43	    return 0;
    (gdb) jump 45 //跳到程序结束位置
    Continuing at 0x4006c5.
    main() : end...
    [Inferior 1 (process 4672) exited normally]
    (gdb) quit //退出
    
    

    第二次调试:

    topeet@ubuntu:~/Desktop/Code$ gdb test.out 
    GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04
    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-linux-gnu".
    For bug reporting instructions, please see:
    <http://bugs.launchpad.net/gdb-linaro/>...
    Reading symbols from /home/topeet/Desktop/Code/test.out...done.
    (gdb) start
    Temporary breakpoint 1 at 0x4005ea: file test.c, line 25.
    Starting program: /home/topeet/Desktop/Code/test.out 
    
    Temporary breakpoint 1, main (argc=1, argv=0x7fffffffe2a8) at test.c:25
    25	    
    (gdb) tbreak func
    Temporary breakpoint 2 at 0x4006dc: file func.c, line 7.
    (gdb) continue 
    Continuing.
    main() : begin...
    argv[0] = /home/topeet/Desktop/Code/test.out
    test_1() : 0x400584
    test_2() : 0x4005a1
    ......
    test_1() : 0x400584
    g_pointer = (nil)
    
    Temporary breakpoint 2, func () at func.c:7
    7	}(gdb) next
    
    Program received signal SIGSEGV, Segmentation fault. //出现错误
    0x00000000004006e8 in func () at func.c:7
    7	}(gdb) ^CQuit
    (gdb) 
    
    

    第三次调试:动态的改变错误以定位错误

    topeet@ubuntu:~/Desktop/Code$ gdb test.out 
    GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04
    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-linux-gnu".
    For bug reporting instructions, please see:
    <http://bugs.launchpad.net/gdb-linaro/>...
    Reading symbols from /home/topeet/Desktop/Code/test.out...done.
    (gdb) show can-use-hw-watchpoints 
    Debugger's willingness to use watchpoint hardware is 1.
    (gdb) start
    Temporary breakpoint 1 at 0x4005ea: file test.c, line 25.
    Starting program: /home/topeet/Desktop/Code/test.out 
    
    Temporary breakpoint 1, main (argc=1, argv=0x7fffffffe2a8) at test.c:25
    25	    
    (gdb) hbreak func
    Hardware assisted breakpoint 2 at 0x4006dc: file func.c, line 7.
    (gdb) info breakpoints 
    Num     Type           Disp Enb Address            What
    2       hw breakpoint  keep y   0x00000000004006dc in func at func.c:7
    (gdb) continue 
    Continuing.
    main() : begin...
    argv[0] = /home/topeet/Desktop/Code/test.out
    test_1() : 0x400584
    test_2() : 0x4005a1
    .......
    test_1() : 0x400584
    g_pointer = (nil)
    
    Breakpoint 2, func () at func.c:7
    7	}(gdb) print g_pointer 
    $1 = (int *) 0x0 //这个函数指针指向的地址为0,空指针
    (gdb) set var g_pointer = (int*)malloc(sizeof(int)) //动态给其分配内存空间
    (gdb) print g_pointer 
    $2 = (int *) 0x602010 //得到堆空间地址
    (gdb) continue 
    Continuing.
    main() : end...  //程序能正常结束
    [Inferior 1 (process 4715) exited normally]
    (gdb) 
    
    

    上面放在Ubuntu下调试的代码如下:

    test.c

    #include <stdio.h>
    #include <unistd.h>
    
    extern int* g_pointer;
    extern void func();
    
    void test_1()
    {
        printf("test_1() : %p\\n", test_1);
    }
    
    void test_2()
    {
        printf("test_2() : %p\\n", test_2);
    }
    
    void test_3()
    {
        printf("test_3() : %p\\n", test_3);
    }
    
    int main(int argc, char *argv[])
    {
        typedef void(TFunc)();
        TFunc* fa[] = {test_1, test_2, test_3};
        int i = 0;
        
        printf("main() : begin...\\n");
        
        for(i=0; i<argc; i++)
        {
            printf("argv[%d] = %s\\n", i, argv[i]);
        }
        
        for(i=0; i<100; i++)
        {
            fa[i%3]();
            sleep(argc > 1);
        }
    
        printf("g_pointer = %p\\n", g_pointer);
    
        func();
        
        printf("main() : end...\\n");
    
        return 0;
    }
    

    func.c

    #include <stdio.h>
    
    int* g_pointer;
    
    void func()
    {
        *g_pointer = (int)"HelloWorld";
    
        return;
    }
    

以上是关于调试利器GDB-上的主要内容,如果未能解决你的问题,请参考以下文章

调试利器GDB-上

调试利器GDB-上

调试利器GDB(下)

调试利器GDB-中

调试利器GDB-中

调试利器GDB-下