• GDB之指令基础参数


    GDB指令基础参数

    Author:Onceday date2022年7月29日

    漫漫长路,才刚刚开始!


    主要参考文档:

    1.引言

    使用gcc编译c/c++时,需要使用-g来生成调试信息。

    启动gdb有以下几种,program即需要调试的执行文件:

    • gdb

    • gdb core,配合coredump进行调试。

    • gdb ,指定服务程序的运行时的进程ID,gdb会自动attach上去。

    启动时可以加入一些常用的参数:

    • -s,从指定文件读取符号表

    • -se,从指定文件读取符号表信息,并把他用在可执行文件中

    • -c,调试时,coredump的core文件

    • -d,加入一个源文件的搜索路径,默认搜索路劲是环境变量中PATH所定义的路径

    gdb环境之下可以运行shell命令以及make命令:

    (gdb) shell ls 
    (gdb) make [args]
    
    • 1
    • 2

    2. 程序运行时,可设置的环境和变量

    2.1 程序运行参数

    set设置程序开始运行时的输入参数,show展示目前的参数列表。

    (gdb) set args 15 "145" 155 145
    (gdb) show args
    Argument list ...  is "15 "145" 155 145".
    
    • 1
    • 2
    • 3

    用于main(int,char*)的参数输入。

    2.2 运行环境

    path设定程序的运行路径,show查看程序的运行路径,set environment 设置环境变量,show environment查看环境变量。

    (gdb) path .
    Executable and object file path: /home/onceday/new:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/snap/bin
    (gdb) show path
    Executable and object file path: /home/onceday/new:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/snap/bin
    (gdb) set environment ONCE=day
    (gdb) show environment ONCE
    ONCE = day
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    环境变量用于main(argc,argv,env)中的env。

    2.3 工作目录

    cd切换目录, pwd显示当前目录。

    2.4 程序的输入输出

    info terminal 显示你程序用到的终端模式

    run > outfile 使用重定向控制程序输出

    tty /dev/ttyb 可以指写输入输出的终端设备

    3.暂停程序

    当程序暂停时,可用info program来查看程序信息。

    有如下几种暂停方式:

    • 断点(Breakpoint)

    • 观察点(WatchPoint)

    • 捕捉点(CatchPoint)

    • 信号(Signals)

    • 线程停止(Thread Stops)

    可使用c或者continue命令恢复程序运行。

    3.1 设置断点
    1. break ,在进入指定函数时停住, 可以增加类名和类型名

    2. break ,在指定行号停住

    3. break +offset /break -offset,在当前行号的前面或后面offset行停住

    4. break filename:linenum,在源文件filename的linenum行处停住

    5. break filename:function,在源文件filename的function函数的入口处停住

    6. break *address,在程序运行的内存地址处停住

    7. break ,在下一条指令处停住

    8. break ... if ...表示上述的参数,这个可以在条件成立时停住。

    3.2 设置观察点

    观察点一般是来观察某个表达式(变量也是一种表达式)的值是否有变化,如果有变化,马上停止程序。

    1. watch ,为表达式(变量),设置观察点,一旦表达式值有变化,马上停止程序。

    2. rwatch ,当表达式(变量),被读时,停住程序。

    3. awatch ,当表达式(变量)的值被读或者写的时候,停住程序。

    4. info watchpoints,列出当前所设置了的所有观察点。

    3.3 设置捕捉点

    可以设置捕捉点来捕捉程序运行时的一些事情,如:载入共享库(动态链接库)或是C++的异常。

    catch <event>
    catch assert -- Catch failed Ada assertions, when raised.
    catch catch -- Catch an exception, when caught.
    catch exception -- Catch Ada exceptions, when raised.
    catch exec -- Catch calls to exec.
    catch fork -- Catch calls to fork.
    catch handlers -- Catch Ada exceptions, when handled.
    catch load -- Catch loads of shared libraries.
    catch rethrow -- Catch an exception, when rethrown.
    catch signal -- Catch signals by their names and/or numbers.
    catch syscall -- Catch system calls by their names, groups and/or numbers.
    catch throw -- Catch an exception, when thrown.
    catch unload -- Catch unloads of shared libraries.
    catch vfork -- Catch calls to vfork.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    4.清除停止点

    清除停止点:

    1. clear,清除所有的已定义的停止点。

    2. clear <[filename:]function>,清除所有设置在函数上的停止点。

    3. clear <[filename:]function>,清除所有设置在指定行上的停止点。

    4. delete breakpoints,删除指定的断点,breakpoints为断点号。

    5. delete range...,删除指定范围内的断点。

    6. delete,删除所有断点。

    7. disable breakpoints,停止指定的断点。

    8. disable range...,停止指定范围内的断点。

    9. disable,停止所有断点

    10. enable [breakpoints] [range...],使能断点

    11. enable [breakpoints] once range...,使能一次,程序停止后 ,会被GDB自动disable。

    12. enable [breakpoints] delete range...,使能一次,程序停止后,会被GDB自动删除。

    可以用condition修改断点的停止条件,即满足后面的表达式:

    condition <bnum> <expression> #修改断点号bnum的停止条件为expression
    condition <bnum>  #清除断点号为bnum的停止条件
    
    • 1
    • 2

    比较特殊的维护命令ignore,可以指定程序运行,忽略停止条件几次。

    ignore <bnum> <count>
    
    • 1

    还可以为停止点设定运行命令:

    当运行程序被停止住时,可以让其自动运行一些别的命令。

    commands [bnum]
    ... command-list ...
    end
    
    • 1
    • 2
    • 3

    实例如下:

    break foo if x>0
    commands
    printf "x is %d/n",x
    continue
    end
    
    • 1
    • 2
    • 3
    • 4
    • 5

    5. 恢复程序运行和单步调试

    当程序被停住了,可以用continue命令恢复程序的运行直到程序结束,或者下一个断点的到来。如下三个命令:

    continue [ignore-count]
    c [ignore-count]
    fg [ignore-count]
    
    • 1
    • 2
    • 3

    ignore-count表示忽略其后的断点次数。

    单步跟踪step,如果有函数调用,会进入该函数,前提是此函数被编译有debug信息。

    step <count> #count表示执行指令的条数,不加则为1
    
    • 1

    单步跟踪next,如果有函数调用,不会进入该函数。

    next <count> #count表示执行指令的条数,不加则为1
    
    • 1

    可以打开step-mode模式,在进行单步跟踪时,程序不会因为没有debug信息而靠不住。

    set step-mode on
    set step-mode off 
    
    • 1
    • 2

    finish运行程序,直到当前函数完成返回,并打印函数返回时的堆栈地址和返回值即参数值等信息。

    until 或 u 可以在一个循环体内单步跟踪,这个命令可以运行程序直到退出循环体。

    stepi或si,nexti或ni:单步跟踪一条机器指令,一条程序代码有可能由数条机器指令完成。

    6.信号处理

    GDB可以在调试程序的时候处理任何一种信号。当收到指定的信号时,拿上停住正在运行的程序,以供你进行调试。

    handle <signal> <keywords ...>
    
    • 1

    信号可以书写为:SIGIO-SIGKILL

    关键字有以下几种:

    • nostop,收到信号时,GDB不会停住,但可以打印出消息。

    • stop,当被调试的程序收到信号时,GDB会停住你的程序。

    • print,当被调试的程序收到信号时,GDB会显示出一条信息。

    • noprint,当被调试的程序收到信号时,GDB不会告诉你收到信号的信息。

    • pass noignore,当被调试的程序收到信号时,GDB不处理信号。这表示,GDB会把这个信号交给被调试程序会处理。

    • nopass ignore,当被调试的程序收到信号时,GDB不会让被调试程序来处理这个信号。

    可以使用info signalsinfo handle查看有哪些信号在被GDB检测中。

    7. 多线程

    在多线程上定义断点:

    break <linespec> thread <threadno>
    break <linespec> thread <threadno> if ...
    
    • 1
    • 2

    linespec指定了断点设置在的源程序的行号。threadno指定了线程的ID。

    ID由GDB分配的,可以通过“info threads”命令来查看正在运行程序中的线程信息。

    如果不指定thread ,则表示断点设在所有线程上面。

    还可以为某线程指定断点条件。如

    (gdb) break frik.c:13 thread 28 if bartab > lim
    
    • 1

    当程序被GDB停住时,所有的运行线程都会被停住。

    而在恢复程序运行时,所有的线程也会被恢复运行。那怕是主进程在被单步调试时。

    8. 查看栈信息

    当程序被停住,可以通过查看栈信息来确认执行情况:

    backtrace
    bt    #函数调用栈
    bt <n> #n是正整数,表示只打印栈顶上n层的栈信息
    bt <-n> #-n表示一个负整数,表示只打印栈底下n层的栈信息
    
    • 1
    • 2
    • 3
    • 4

    查看某一层栈的信息:

    frame <n>
    f  <n>
    
    • 1
    • 2

    n是一个从0开始的整数,是栈中的层编号,比如,frame 0表示栈顶,frame 1表示栈的第二层。

    up <n>  #表示向栈的上面移动n层,可以不打n,表示向上移动一层。
    down <n> #表示向下移动n层。
    
    • 1
    • 2

    以下命令不打印出移动的栈层信息:

    select-frame <n> 对应于 frame 命令。
    up-silently <n> 对应于 up 命令。
    down-silently <n> 对应于 down 命令。
    
    • 1
    • 2
    • 3

    输出当前栈层信息的命令:

    • 可以使用info frameinfo f打印出更为详细的当前栈层信息。

    • info args打印当前函数的参数名及其值。

    • info locals打印出当前函数中所有局部变量及其值。

    • info catch 打印出当前的函数中的异常处理信息。

    9.显示源代码

    编译时需要加上-g参数。

    list <[function:]linenum>    #显示程序第linenum行的周围的源程序
    
    • 1
    list <[filename:]function>    #显示函数名为function的函数的源程序。
    
    • 1
    list               #显示当前行后面的源程序。
    
    • 1
    list -            #显示当前行前面的源程序
    
    • 1

    设置一次显示源代码的行数:

    set listsize <count>
    
    show listsize    #查看当前listsize的设置
    
    • 1
    • 2
    • 3

    还有以下的选行显示

    list <first><last>    #显示从first行到last行之间的源代码
    list , <last>·        #显示从当前行到last行之间的源代码
    list +                #往后显示源代码
    
    • 1
    • 2
    • 3
    9.1 源码搜索

    可搭配正则表达式进行源代码搜索:

    forward-search <regexp>
    search <regexp>    #向前面搜索
    
    reverse-search <regexp>  #全部搜索
    
    • 1
    • 2
    • 3
    • 4
    9.2 指定源文件的路径
    directory <dirname [: dirname2 ....]>
    dir <dirname [: dirname2 ....]>
    
    
    show directories #显示定义了的源文件搜索路径
    
    • 1
    • 2
    • 3
    • 4
    • 5
    9.3 查看源代码在内存中的地址

    打印出所指定的源码在运行时的内存地址:

    info line 行业/函数名/文件名:行号/文件名:函数名
    
    • 1

    查看源程序的当前执行时的机器码,这个命令会把目前内存中的指令dump出来:

    disassemble 函数名....
    
    • 1

    10. 查看运行时数据

    print <expr>
    print /<f> <expr>
    
    • 1
    • 2

    是表达式,是你所调试的程序的语言的表达式(GDB可以调试多种编程语言),是输出的格式。

    表达式可支持以下几种操作符:

    1. ::,指定一个在文件或是在一个函数中的变量。

    2. @,一个和数组有关的操作符

    3. {} ,表示一个指向内存地址的类型为type的一个对象。

    示例如下:

    p file::variable
    p function::variable
    p "f2.c"::x
    p *array@len  #int *array = (int *) malloc (len * sizeof (int));
    
    • 1
    • 2
    • 3
    • 4

    静态数组直接print数组名即可输出数组内容。

    格式有以下几种:

    • x 按十六进制格式显示变量。

    • d 按十进制格式显示变量。

    • u 按十六进制格式显示无符号整型。

    • o 按八进制格式显示变量。

    • t 按二进制格式显示变量。

    • a 按十六进制格式显示变量。

    • c 按字符格式显示变量。

    • f 按浮点数格式显示变量。

    示例如下:

    (gdb) p /f i
    $24 = 1.41531145e-43
    
    • 1
    • 2
    10.1 使用examine(x)查看内存地址的值
    x [/<n/f/u>] <addr>
    
    • 1

    可选参数:

    • n,是一个正整数,表示显示内存的长度。

    • f,表示显示的格式,即上面所展示的。

    • u,表示从当前地址往后请求的字节数。默认是4个bytes。以下为预设的几种字符:

      1. b表示单字节

      2. h表示双字节

      3. w表示四字节

      4. g表示八字节

    示例:

    x/3uh 0x54320
    
    • 1

    表示从内存地址0x54320读取内容,h表示以双字节为一个单位,3表示三个单位,u表示按十六进制显示。

    10.2 自动显示

    当程序停住时,这些变量可以自动显示。

    display <expr>
    display /<fmt> <expr>
    
    • 1
    • 2

    示例:

    display /i $pc  
    
    • 1

    $pc是GDB的环境变量,表示着指令的地址,/i 输出汇编指令。

    删除自动显示:

    undisplay <dnums...>
    delete display <dnums...>
    
    • 1
    • 2

    是需要自动显示的变量的序列号。

    使用info display可以观察当前所有的自动显示变量,以及它们的序列号。

    使用示例:

    delete display 2,3  #同时删除序列号2和3对应的自动显示变量
    disable display 2,3  #同时失效序列号2和3对应的自动显示变量
    enable display 2-5   #同时使能序列号2-5范围内的所有对应自动显示变量
    
    • 1
    • 2
    • 3

    11.设置显示(print)选项

    1.打开地址输出,当程序显示函数信息时,GDB会显出函数的参数地址。系统默认为打开的

    set print address on
    set print address off
    
    • 1
    • 2

    2.打开数组显示,打开后当数组显示时,每个元素占一行,如果不打开的话,每个元素则以逗号分隔。这个选项默认是关闭的。

    set print array
    set print array on
    
    • 1
    • 2

    3.设置数组显示的最大长度以及显示当前print elements的选项信息。

    set print elements <number-of-elements>
    show print elements
    
    • 1
    • 2

    4.当显示字符串时,遇到结束符则停止显示,这个选项默认为off。

    set print null-stop <on/off>
    
    • 1

    5.以漂亮的格式显示结构体等内容。

    set print pretty on
    set print pretty off
    
    • 1
    • 2

    6.设置字符显示,是否按“/nnn”的格式显示

    set print sevenbit-strings <on/off>
    
    • 1

    7.设置显示结构体时,是否显式其内的联合体数据。

    set print union <on/off>
    
    • 1

    8.对象、成员、虚函数等C++类设置

    set print object <on/off>   #对对象指针的处理方法
    
    • 1

    在C++中,如果一个对象指针指向其派生类,如果打开这个选项,GDB会自动按照虚方法调用的规则显示输出,如果关闭这个选项的话,GDB就不管虚函数表了。这个选项默认是off。

    set print static-members <on/off>
    
    • 1

    这个选项表示,当显示一个C++对象中的内容是,是否显示其中的静态数据成员。默认是on。

    set print vtbl <on/off>
    
    • 1

    当此选项打开时,GDB将用比较规整的格式来显示虚函数表时。其默认是关闭的。

    11.2 print历史记录

    GDB会记录当前运行过程中产生的print记录,并以$1$2$3…这样的方式来编号。

    那么就可以使用$1这样的方式来重新输入之前的print表达式。

    11.3 GDB环境变量

    可以在GDB的调试环境中定义自己的变量,用来保存一些调试程序中的运行数据。

    使用以下命令即可定义一个GDB变量:

    set $foo = *object_ptr
    
    • 1

    使用以下命令可以查看当前设置的所有的环境变量。

    show convenience
    
    • 1

    环境变量可以和程序变量交互使用:

    set $i = 0
    print bar[$i++]->contents
    
    • 1
    • 2
    11.4 查看寄存器

    使用以下命令即可查看寄存器情况(不包括浮点寄存器):

    info registers
    
    • 1

    以下命令可以包括浮点寄存器:

    info all-registers
    
    • 1

    查看所指定的寄存器的情况:

    info registers <regname ...>
    
    • 1

    也可以使用print命令访问($+寄存器名):

    print $sp
    
    • 1

    本文收集整理于互联网,仅供交流学习之用!

  • 相关阅读:
    【100天精通Python】Day68:Python可视化_Matplotlib 绘制热力图,示例+代码
    FME读写cass数据的方案及操作流程
    算法升级之路(七)-盛最多水的容器
    Go基础-文件、字符
    如何在IDEA 中设置背景图片
    Vue项目中,Async与Await设置多个Axios异步请求的执行顺序
    jsbridge实战2:Swift和h5的jsbridge通信
    Homography详解&&在MVSNet中的应用
    git学习笔记 | 版本管理 - 分支管理
    第十届蓝桥杯省赛C++C/研究生组,第十届蓝桥杯省赛JAVAC/研究生组——扫地机器人题解(二分)
  • 原文地址:https://blog.csdn.net/Once_day/article/details/126254200