zoukankan      html  css  js  c++  java
  • GDB调试

    首先介绍下GDB常用命令

    流程
    start <args>或run <args>:bin程序开始执行
    c(continue):从断点开始继续执行,直到下一断点或结束
    n(next):执行下一行(跳过函数)
    s(step):执行下一行(进入函数)
    finish:运行到当前函数结束退出
    运行状态下ctrl-c:暂停
    q(quit),或暂停状态下ctrl-c:退出

    断点
    b <func-name>:在函数上打断点
    b * <address>:在代码段地址上打断点
    i b:查看断点
    d b <N>:禁用指定编号的断点
    e b <N>:启用指定编号的断点
    b ... if <expr>:条件断点:若<expr>为真(或非NULL),在断点处暂停

    临时进入shell模式
    shell(进入)、exit(退出)
    帮助:help或?

    查看信息
    bt(backtrace):查看调用栈
    i r:查看寄存器信息
    x/Ns:以字符串形式查看指定变量/地址
    x/Nd:以十进制数字形式查看指定变量/地址
    x/Nx:以十六进制形式查看指定变量/地址
    x/Ni:查看指定函数/地址的汇编指令
    p <expr>:查看<expr>的值

    x/b &str:查看全局变量的字符串,str是一个全局字符串

    其它
    暂停状态下回车:执行上一条命令
    支持上翻、下翻

    设置打印字符的个数为不限制数量,设置为unlimited或者zero。

    (gdb) set print elements 0
    (gdb) show print elements
    Limit on string chars or arry elemtns to print is unlimited

    CPU寄存器信息

    mips

    zero:永远为0
    v0/v1:临时寄存器;函数返回时存返回值
    a0 ~ a3:临时寄存器;调用函数时存参数
    t0 ~ t9:临时寄存器。t9常用于临时存要调用的子函数入口地址
    s0 ~ s8:非易失性寄存器
    gp:全局指针
    sp:栈顶指针
    ra:当前函数返回地址
    pc:当前指令

    x86

    1) %rax 作为函数返回值使用。
    2) %rsp 栈指针寄存器,指向栈顶。
    3) %rdi,%rsi,%rdx,%rcx,%r8,%r9 用作函数参数,依次对应第1参数,第2参数等。
    4) %rbx,%rbp,%r12,%r13,%14,%15 用作数据存储,遵循被调用者使用规则,简单说就是随便用,调用子函数之前要备份它,以防他被修改。
    5) %r10,%r11 用作数据存储,遵循调用者使用规则,简单说就是使用之前要先保存原值。
     
     
    栈结构信息
    X86_64的栈结构:
     
    如上图所示:%rsp寄存器存储的地址指向当前函数的栈顶,%rbp寄存器是我们推栈的关键,它指向的位置保存了两个字,前一个函数栈的%rbp寄存器值和函数返回地址。
     
    (三)推栈过程:
     
        下面开始介绍推栈过程,可以发现,推栈的过程就是跟踪查找%rbp寄存器的内容,而且我们无需像MIPS体系那样关注某个函数的堆栈的大小。
     
     1) 设备死机时会进KDB,通过KDB的rd命令可查看当前挂死环境所有寄存器的内容:
    [12]kdb> rd
         r15 = 0x0000000000000007      r14 = 0x0000000000000000 
         r13 = 0x0000000000000000      r12 = 0xffffc9005dd6b2b0 
          bp = 0xffff8800462375e8       bx = 0xffff8800463780a0 (这里的bp寄存器和上面提到的%rbp寄存器是等价的)
         r11 = 0x0000000000000000      r10 = 0xffffc9005dd735b0 
          r9 = 0x0000000000000002       r8 = 0xffffc9005dd67130 
          ax = 0x0000000004230423       cx = 0xffffc90061f9b6d3 
          dx = 0x0000000000000095       si = 0x0000000000000000 
          di = 0xffffc9005dd67008  orig_ax = 0xffffffffffffffff 
          ip = 0xffffffffc224156c       cs = 0x0000000000000010  
       flags = 0x0000000000010246       sp = 0xffff880046237570 
          ss = 0x0000000000000018 &regs = 0xffff8800462374d8

    2) SP寄存器指向当前调用栈的栈顶,通过md命令可查看调用栈的内容,而IP寄存器里存储的是正在执行的函数地址
    [12]kdb> md 0xffff880046237570    
    fa_traverse_dfa+0x1ec             
    0xffff880046237570 ffff880046237580 0000000000000018   .u#F............
    0xffff880046237580 ffff880046237696 ffff880046378355   .v#F....U.7F....
    0xffff880046237590 0000000000000000 ffffc9005dd7772e   .........w.]....
    0xffff8800462375a0 ffff8800462376e4 ffff880046378356   .v#F....V.7F....
    0xffff8800462375b0 ffff880046378010 0000000042dd1653   ..7F....S..B....
    0xffff8800462375c0 0000000000000001 0000000000000000   ................
    0xffff8800462375d0 0000000000000000 0000000000000346   ........F.......
    0xffff8800462375e0 0000000000000000                                     // 3)BP寄存器指向的地址(0xffff8800462375e8),存储了前一个函数栈的BP和返回地址。ffff880046237638 是前一个函数栈的BP值, ffffffffc22427a9是函数返回地址。
    ffff880046237638   ........8v#F....
    0xffff8800462375f0 ffffffffc22427a9                                   

    fa_traverse+0x69        // 4)通过函数返回地址得到一个调用函数名称fa_traverse
    0000000000000000   .'$.............
    0xffff880046237600 ffff880046237688 0000000000000000   .v#F............
    0xffff880046237610 0000000000000000 0000000000000000   ................
    0xffff880046237620 0000000000000000 ffffffffc31ff918   ................
    0xffff880046237630 ffffc9005dd67000                                 // 5)同时,我们得到了fa_traverse函数的BP寄存器的值,它指向的地址(ffff880046237638)同样存储了一个函数的BP和返回地址。
    ffff8800462376c8   .p.].....v#F....
    0xffff880046237640 ffffffffc22428ed                                 // 6)以此类推, 接着向下推栈即可。

    regex_traverse+0x7d
    0000000000000000   .($.............
    0xffff880046237650 ffff880046237680 ffff880046237690   .v#F.....v#F....
    0xffff880046237660 ffff8800462376e4 0000000000000000   .v#F............
    [12]kdb> 
    0xffff880046237670 ffff880046237688 0000000000000000   .v#F............
    0xffff880046237680 0000000000000000 0000000000000001   ................
    0xffff880046237690 0000000000000000 0000000000000000   ................
    0xffff8800462376a0 ffffffffc31ff660 ffff880029099c00   `..........).... 
    0xffff8800462376b0 0000000000000000 0000000000000010   ................
    0xffff8800462376c0 0000000000000000 
    ffff8800462376f8   .........v#F....
    0xffff8800462376d0 ffffffffc223f533

    pcre_engine_regex_check+0x43
    ffffffffc210f000   3.#.............
    0xffff8800462376e0 00003a98c31ff660 ffff880029099c00   `....:.....)....
    0xffff8800462376f0 ffffffffc31ff660 
    ffff880046237778   `.......xw#F....
    0xffff880046237700 ffffffffc237dea1 

    dcdm_pcre_new_single_rule_proc+0xf1
    0000020000000200   ..7.............
    0xffff880046237710 0000000000000000 ffff880029099c30   ........0..)....
    0xffff880046237720 ffffe90142dd16f0 ffffe90142dd16d8   ...B.......B....
    0xffff880046237730 ffffffffc31ff918 0000000000000000   ................
    0xffff880046237740 ffff880029099c1c ffff8800462377a8   ...).....w#F....
    0xffff880046237750 0000000000000000 ffff880046370000   ..........7F....
    0xffff880046237760 ffffffffc31ff660 0000000000000000   `...............
    0xffff880046237770 ffff880029099c00 
    ffff8800462377d8   ...).....w#F....
    0xffff880046237780 ffffffffc237e34b 

    dcdm_pcre_new_flow_proc+0x1eb
    ffff880065a04880   K.7......H.e....
    0xffff880046237790 0000000165a1e0f6 ffffe90142dd16c0   ...e.......B....
    0xffff8800462377a0 ffff880065a04880 ffff8800462377d8   .H.e.....w#F....
    0xffff8800462377b0 ffff880065a04880 ffff880046370000   .H.e......7F....
    0xffff8800462377c0 ffffe90142dd16a8 000000000002d2a0   ...B............
    0xffff8800462377d0 ffffe90142dd1518 ffff8800462377f8   ...B.....w#F....
    0xffff8800462377e0 ffffffffc237e3cb ffff880065a04880   ..7......H.e....
    0xffff8800462377f0 ffff880046370000 ffff880046237898   ..7F.....x#F....
    0xffff880046237800 ffffffffc237d311 0000000000000000   ..7.............
    0xffff880046237810 0000000000000000 ffff880046237868   ........hx#F....
    0xffff880046237820 ffffffffc21eb9ff 471d0201ba190101   ...............G
    0xffff880046237830 000000061606db27 ffff880046237858   '.......Xx#F....
    0xffff880046237840 ffff880065a04880 ffffffffc5ed6860   .H.e....`h......
    0xffff880046237850 42000004c2380ca3 ffff880046237898   ..8....B.x#F....
    0xffff880046237860 00000001c23785f4 ffff8800462378b8   ..7......x#F....

    调试进程

    使用方法
    gdb -p <pid>
    适用场景
    某进程运行过程中会出故障,需要跟踪执行过程
    例:页面下发配置时发生500错误,需分析web_main代码流程
    某进程已经出故障但未崩溃,需要查看当前正在哪个流程中
    例:串口卡住,但远程诊断能用,需要析vtysh卡在何处
    操作流程:
    进入gdb模式;
    打断点;
    c;
    进行页面/命令行等操作,使进程运行至断点处;
    分析寄存器、内存信息。
    反复进行3~5步操作,直到分析明白。
    q;

    调试bin

    使用方法
    gdb <bin-file-path>
    适用场景
    某程序执行时不会转变成后台进程,运行过程中会出故障,需要跟踪执行过程
    例:配置恢复有启动项失败,需要从startup程序跟踪其执行流程
    某程序执行时会转变成后台进程,但进入自身循环之前(相当于进程启动阶段)会出故障,需要分析该过程执行流程
    例:eventd进程进入死循环前出故障,需要分析该执行过程
    set follow-fork-mode (parent|child)命令用法
    用于指定跟随子进程还是父进程(默认为parent)
    当前进程切换成后台进程时,执行set follow-fork-mode child
    调用生成子进程的函数(如system、popen、exec系列函数等)前,执行set follow-fork-mode parent
    操作流程:
    与后台进程类似,但在1~3之间执行set follow-fork-mode child,确定已切换到后台后set follow-fork-mode parent切回来。

    调试启动项:

    先找到要调用的启动项所在文件startup_N_*、所在行M
    对/usr/bin/startup挂gdb
    先打断点、执行set follow-fork-mode child
    运行:r -p N M

  • 相关阅读:
    【XSY2505】tree
    【XSY2558】圆上的蚂蚁 Ants on circle
    【模板】生成函数
    左偏树
    Link cut tree
    高斯消元
    cdq分治——bzoj2683简单题
    半平面交
    关于向量,凸包及旋转卡壳
    状压dp:luogu P2704 [NOI2001]炮兵阵地
  • 原文地址:https://www.cnblogs.com/gaoshaonian/p/10219680.html
Copyright © 2011-2022 走看看