• 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十分钟教程

  • 相关阅读:
    04面向对象编程-01-创建对象 和 原型理解(prototype、__proto__)
    03标准对象-02-RegExp 正则表达式
    03标准对象-01-Date和JSON
    广度优先搜索
    Java虚拟机(三) —— 类加载
    业务开发(一)—— MySQL
    Java并发编程(一) —— Java内存模型JMM
    深度优先搜索
    Spark学习(一)
    清泉白石
  • 原文地址:https://www.cnblogs.com/unclemac/p/12783377.html
Copyright © 2020-2023  润新知