zoukankan      html  css  js  c++  java
  • linux gdb快速入门教程

    前言

    gdb是一个由GNU开源组织发布的、UNIX/LINUX操作系统下的、基于命令行的、功能强大的程序调试工具。对于想要学习gdb调试的童鞋,网上搜一下就是一大堆资料,信息太多而不知道该如何筛选了,当然最有效的方式是去看gdb的手册,但是对于想快速上手的我,需要掌握最常用的一些指令和一些技巧,期间,我找到了一本很强大的书,感觉就是gdb bible——100-gdb-tips100-gdb-tips-gitbook;强烈推荐参考这个文档。文档里已经基本涵盖了gdb使用的各种操作和技巧,但是都相互比较独立和分散,没有一个完整的使用流程,下面我会总结一下整体使用的一个流程。

    常用指令概览

    命令 解释 示例
    file <文件名> 加载被调试的可执行程序文件。
    因为一般都在被调试程序所在目录下执行GDB,因而文本名不需要带路径。
    (gdb) file gdb-sample
    r Run的简写,运行被调试的程序。
    如果此前没有下过断点,则执行完整个程序;如果有断点,则程序暂停在第一个可用断点处。
    (gdb) r
    c Continue的简写,继续执行被调试程序,直至下一个断点或程序结束。 (gdb) c
    b <行号>
    b <函数名称>
    b *<函数名称>
    b *<代码地址>
    d [编号]
    b: Breakpoint的简写,设置断点。
    可以使用“行号”“函数名称”“执行地址”等方式指定断点位置。
    其中在函数名称前面加“*”符号表示将断点设置在“由编译器生成的prolog代码处”。
    如果不了解汇编,可以不予理会此用法。
    d: Delete breakpoint的简写,删除指定编号的某个断点,或删除所有断点。断点编号从1开始递增。
    (gdb) b 8
    (gdb) b main
    (gdb) b *main
    (gdb) b *0x804835c
    (gdb) d
    s, n s: 执行一行源程序代码,如果此行代码中有函数调用,则进入该函数;
    n: 执行一行源程序代码,此行代码中的函数调用也一并执行。
    s 相当于其它调试器中的“Step Into (单步跟踪进入)”;
    n 相当于其它调试器中的“Step Over (单步跟踪)”。
    这两个命令必须在有源代码调试信息的情况下才可以使用(GCC编译时使用“-g”参数)。
    (gdb) s
    (gdb) n
    si, ni si命令类似于s命令,ni命令类似于n命令。
    所不同的是,这两个命令(si/ni)所针对的是汇编指令,而s/n针对的是源代码。
    (gdb) si
    (gdb) ni
    p <变量名称> Print的简写,显示指定变量(临时变量或全局变量)的值。 (gdb) p i
    (gdb) p nGlobalVar
    display ...
    undisplay <编号>
    display,设置程序中断后欲显示的数据及其格式。
    例如,如果希望每次程序中断后可以看到即将被执行的下一条汇编指令,
    可以使用命令“display /i $pc”,其中 $pc 代表当前汇编指令,/i 表示以十六进行显示。
    当需要关心汇编代码时,此命令相当有用。
    undispaly,取消先前的display设置,编号从1开始递增。
    (gdb) display /i $pc
    (gdb) undisplay 1
    i Info的简写,用于显示各类信息,详情请查阅“help i”。 (gdb) i r
    q Quit的简写,退出GDB调试环境。 (gdb) q
    help [命令名称] GDB帮助命令,提供对GDB名种命令的解释说明。
    如果指定了“命令名称”参数,则显示该命令的详细说明;
    如果没有指定参数,则分类显示所有GDB命令,供用户进一步浏览和查询。
    (gdb) help display

    开始使用gdb

    通常我们编写一个程序,具体程序如下所示;并且编译成带调试信息的可执行文件,然后在用gdb加载调试;

    /*
     * demo learning gdb
     * gdb-sample.c
     */
     #include <stdio.h>
     void func_a(int *p){
         printf("%s:p is %d  | valuse is %d 
    ",__func__,p,*p);
     }
     void func_b(int *p){
         *p = 12345;
         func_a(p);
     }
     void func_c(int *p){
         p = NULL;
         func_b(p);
     }
     int main(void) {
         int i = 0,j=0;
         int *p = &j;
         for(; i<6; i++){
             if(i<2){
                 func_a(p);
             }else if(i<4){
                 func_b(p);
             }else{
                 func_c(p);
             }
         }
         return 0;
     }
    
    
    gcc -g gdb-sample.c -o gdb-sample
    

    记得带上-g选项,最后编译成功并生成可执行文件gdb-sample

    一个完整流程一般所需步骤

    1 加载程序

    gdb -q gdb-sample
    

    2 查看

    2.1 查看函数

    使用i functions或者info functions可以查看当前的可执行文件的函数接口;

    (gdb) i functions
    All defined functions:
    
    File gdb-sample.c:
    void func_a(int *);
    void func_b(int *);
    void func_c(int *);
    int main(void);
    
    Non-debugging symbols:
    0x0000000000400460  _init
    0x0000000000400490  puts@plt
    0x00000000004004a0  __stack_chk_fail@plt
    0x00000000004004b0  printf@plt
    0x00000000004004c0  __libc_start_main@plt
    0x00000000004004e0  _start
    0x0000000000400510  deregister_tm_clones
    0x0000000000400550  register_tm_clones
    0x0000000000400590  __do_global_dtors_aux
    0x00000000004005b0  frame_dummy
    0x00000000004006f0  __libc_csu_init
    0x0000000000400760  __libc_csu_fini
    0x0000000000400764  _fini
    
    

    3 设置断点

    断点使用

    3.1 根据函数名设置断点
    (gdb) b main
    Breakpoint 1 at 0x400658: file gdb-sample.c, line 19.
    
    3.2 根据程序位置(第几行)
    (gdb) l
    1       #include <stdio.h>
    2
    3       void func_a(int *p){
    4           printf("%s:p is %d  | valuse is %d 
    ",__func__,p,*p);
    5       }
    6
    7       void func_b(int *p){
    8           *p = 12345;
    9           func_a(p);
    10      }
    (gdb)
    11
    12      void func_c(int *p){
    13          p = NULL;
    14          func_b(p);
    15      }
    16
    17
    18
    19      int main(void) {
    20          int i = 0,j=0;
    (gdb)
    21          int *p = &j;
    22          for(; i<6; i++){
    23              if(i<2){
    24                  func_a(p);
    25              }else if(i<4){
    26                  func_b(p);
    27              }else{
    28                  func_c(p);
    29              }
    30          }
    (gdb) b 19
    Breakpoint 3 at 0x400618: file gdb-sample.c, line 19.
    

    删除断点

    (gdb) d
    删除所有断点吗? (y or n) y
    

    4 运行程序

    使用runr运行程序,如果被断点中断,可以使用c继续运行程序;

    (gdb) r
    Starting program: /home/thinkpad/code/gdb-tips/core_dump/gdb-sample
    
    Breakpoint 1, main () at gdb-sample.c:19
    19      int main(void) {
    

    使用next或者n可以进行单步调试;不会进入到子函数内部;
    使用step或者s可以进行单步调试;会进入到子函数内部;

    5 查看变量

    查看变量可以使用printp

    (gdb) b main
    Breakpoint 6 at 0x400618: file gdb-sample.c, line 19.
    (gdb) r
    The program being debugged has been started already.
    Start it from the beginning? (y or n) y
    Starting program: /home/zhaojh/code/gdb-tips/core_dump/gdb-sample
    
    Breakpoint 6, main () at gdb-sample.c:19
    19      int main(void) {
    (gdb) n
    20          int i = 0,j=0;
    (gdb) p i
    $1 = 0
    (gdb) n
    21          int *p = &j;
    (gdb) n
    22          for(; i<6; i++){
    (gdb) p p
    $2 = (int *) 0x7fffffffe2f8
    (gdb) p *p
    $3 = 0
    (gdb)
    

    6 查看寄存器

    使用i rinfo registeri registerinfo r可以查看寄存器;

    (gdb) i r
    rax            0x7fffffffe2f8   140737488347896
    rbx            0x0      0
    rcx            0x0      0
    rdx            0x7fffffffe408   140737488348168
    rsi            0x7fffffffe3f8   140737488348152
    rdi            0x1      1
    rbp            0x7fffffffe310   0x7fffffffe310
    rsp            0x7fffffffe2f0   0x7fffffffe2f0
    r8             0x400710 4196112
    r9             0x7ffff7de7ac0   140737351940800
    r10            0x846    2118
    r11            0x7ffff7a2d740   140737348032320
    r12            0x4004a0 4195488
    r13            0x7fffffffe3f0   140737488348144
    r14            0x0      0
    r15            0x0      0
    rip            0x40063f 0x40063f <main+47>
    eflags         0x293    [ CF AF SF IF ]
    cs             0x33     51
    ss             0x2b     43
    ds             0x0      0
    es             0x0      0
    fs             0x0      0
    gs             0x0      0
    
    

    总结

    记录了一些比较简单并且会被普遍用到的gdb指令,作为入门使用还是比较好的,更多高级的调试参考gdb bible——100-gdb-tips100-gdb-tips-gitbook

    参考

    https://github.com/hellogcc/100-gdb-tips
    https://wizardforcel.gitbooks.io/100-gdb-tips/content/
    GDB十分钟教程

  • 相关阅读:
    八数码难题 (codevs 1225)题解
    小木棍 (codevs 3498)题解
    sliding windows (poj 2823) 题解
    集合删数 (vijos 1545) 题解
    合并果子 (codevs 1063) 题解
    等价表达式 (codevs 1107)题解
    生理周期 (poj 1006) 题解
    区间 (vijos 1439) 题解
    区间覆盖问题 题解
    种树 (codevs 1653) 题解
  • 原文地址:https://www.cnblogs.com/unclemac/p/12783377.html
Copyright © 2011-2022 走看看