使用GDB(二):调试程序常用命令

文章目录

    • 一、GDB配置文件
    • 二、启动程序/挂载进程
    • 三、改变变量和控制流程
    • 四、打印表达式(变量)信息
    • 五、永久/条件/一次/自动断点操作
    • 六、查看源码及其编译后的相关信息
    • 七、反汇编相关
    • 八、多进程与多线程
    • 九、其它常用命令

GDB官网参考

一、GDB配置文件

当gdb启动时,会读取HOME目录和当前目录下的的配置文件,执行里面的命令。配置文件名通常为.gdbinit,一些常用配置如下所示:

# 打印STL容器中的内容
python
import sys
sys.path.insert(0, "/home/xmj/project/gcc-trunk/libstdc++-v3/python")
from libstdcxx.v6.printers import register_libstdcxx_printers
register_libstdcxx_printers (None)
end

# 保存历史命令
set history filename ~/.gdb_history
set history save on

# 退出时不显示提示信息
set confirm off

# 按照派生类型打印对象
set print object on

# 打印数组的索引下标
set print array-indexes on

# 每行打印一个结构体成员
set print pretty on

gdb支持的脚本文件分为两种:一种是只包含gdb自身命令的脚本,例如.gdbinit文件,当gdb在启动时,就会执行.gdbinit文件中的命令;此外,gdb还支持其它一些语言写的脚本文件(比如python)。

gdb用set script-extension命令来决定按何种格式来解析脚本文件。它可以取3个值:

  • off:所有的脚本文件都解析成gdb的命令脚本;
  • soft:根据脚本文件扩展名决定如何解析脚本。如果gdb支持解析这种脚本语言(比如python),就按这种语言解析,否则就按命令脚本解析;
  • strict:根据脚本文件扩展名决定如何解析脚本。如果gdb支持解析这种脚本语言(比如python),就按这种语言解析,否则不解析;

写一个脚本文件(gdb.py),但内容是一个gdb命令,不是真正的python脚本。用途是退出gdb时不提示:

# gdb.py
set confirm off

然后在gdb中按顺序执行以下命令:

# 查看script-extension的值,默认值是soft
show script-extension

# 因为soft会按照pyhton语言解析gdb.py文件,但是这个文件实质上是一个gdb命令脚本,所以解析会出错
set script-extension off

# 正确解析gdb.py文件,配置生效
source gdb.py

二、启动程序/挂载进程

  • gdb [-tui] [execut_file] [| tee log_file],启动gdb
    -tui选项,启动可以直接将屏幕分成两个部分,上面显示源代码;
    tee命令可以将gdb调试时显示的所有信息输出到指定的文件中。
  • gdb attach pid,调试正在运行的进程
    // 查找所有正在运行的进程,筛选出名字中带有luarocks的,在筛选结果中剔除名字中带有auto的
    // 找出筛选结果的第二列,作为gdb attach 后面跟的参数
    gdb attach `ps -ef | grep "luarocks" | grep -v "auto" | awk '{print $2}'`
    
  • run,简写r:运行被调试的程序。如果此前没有下过断点,则执行完整个程序;如果有断点,则程序暂停在第一个可用断点处
  • start,开始调试,停在第一行代码处
  • gdb -args ./a.out arg1 arg2 ...,启动时设置被调试程序的参数
    set args ,修改发送给程序的参数(run后面跟的参数)
    ## 也可以采用以下方式设置被调试程序的参数
    gdb ./a.out
    set args arg1 arg2 ...
    ## 还可以
    gdb ./a.out
    start arg1 arg2 ...
    

三、改变变量和控制流程

  • set var ,修改指定变量的值
    # assignment的语法跟随调试语言本身(= 、:=)
    set var i = 10
    
    # 也可以只用set,但可能会存在变量名(i)与gdb参数冲突的情况(print、args)
    # 所以最好还是用set var
    set i=10
    
  • set ,修改该指定寄存器中的值,如set $pc = 100set $r1 = 0
  • set [*|*(type*)|{type}]address = value,修改指定地址处的值,如给存储地址在address,变量类型为type的变量赋值
    # 根据地址修改字符串的值
    (gdb) p &p1
      $1 = (char (*)[4]) 0x80477a4
    (gdb) set {char [4]} 0x80477a4 = "Ace"
    
    # 根据地址修改变量的值,有三种方式可选择
    (gdb) p &i
      $2 = (int *) 0x8047a54
    (gdb) set *0x8047a54 = 8
    (gdb) set *(int *)0x8047a54 = 8
    (gdb) set {int}0x8047a54 = 8
    
  • 使用修改指定地址处的值,修改二进制文件中的指令,永久生效。
    # 缺省情况下,gdb是以只读方式加载程序的。可以通过以下命令行选项指定为可写
    gdb -write ./a.out
    # 或者
    (gdb) set write on
    (gdb) file ./a.out
    
    # 将函数fun-name的每一行源码与其汇编指令和指令的具体值对应显示
    disassemble /mr fun-name
    
    # 修改二进制代码(注意大小端和指令长度)
    # 如将0x0000000120000760处的指令改为:andi	$r0,$r0,0x0
    set *0x0000000120000760=0x03400000
    set variable *(int*)0x0000000120000760=0x03400000
    set {int}0x0000000120000760=0x03400000
    
  • next,简写n:执行一行源程序代码,此行代码中的函数调用也一并执行,(gdb) n(gdb) n line-number
  • step,简写s:执行一行源程序代码,如果此行代码中有函数调用,则进入该函数,(gdb) s(gdb) s line-number
    没带调试信息的函数无法step进入(如系统库函数),但执行set step-mode on即可。
  • continue,简写c:继续执行被调试程序,直至下一个断点或程序结束,(gdb) c(gdb) c line-number
  • until [line-number],简写u [line-number]:可以指定程序运行到某一行停下来,如当前程序停在第10行,使用(gdb) u 23,则快速执行完中间代码,在23行停下来
  • finish,执行完当前函数的所有语句,然后正常退出该函数
  • return [expression],立即结束当前正在执行的函数,不再执行函数的后面语句,并返回,expression是函数返回的值

四、打印表达式(变量)信息

  • print[/f|等] [var|ptr|addr],简写p[/f|等] [var]:显示指定变量的值,(gdb) p [var](gdb) p [&var](gdb) p [ptr](gdb) p [*ptr](gdb) p/x [var],参考自print打印。
    其中f 表示显示方式, 可取如下值:
    x 按十六进制格式显示变量
    d 按十进制格式显示变量
    u 按十六进制格式显示无符号整型
    o 按八进制格式显示变量
    t 按二进制格式显示变量
    a 按十六进制格式显示变量
    c 按字符格式显示变量
    f 按浮点数格式显示变量
    s 按字符串格式显示变量
    打印数组前n个元素p *arr@n,打印数组下标从m开始的n个元素p arr[m]@n

  • set print ,以指定的格式显示输出变量的值,在查看表达式(变量)信息时使用
    set print address [on|off],打开地址输出,当程序显示函数信息时,GDB会显出函数的参数地址
    set print array [on|off],打开数组显示,打开后当数组显示时,每个元素占一行,如果不打开的话,每个元素则以逗号分隔
    set print elements [num|unlimited],指定数组显示的最大长度,,当到达这个长度时,GDB就不再往下显示了。如果设置为0,则表示不限制
    set print null-stop [on|off],如果打开了这个选项,那么当显示字符串时,遇到结束符则停止显示。这个选项默认为off
    set print union [on|off],设置显示结构体时,是否显式其内的联合体数据。
    set print object [on|off],在C++中,如果一个对象指针指向其派生类,如果打开这个选项,GDB会自动按照虚方法调用的规则显示输出,如果关闭这个选项的话,GDB就不管虚函数表了
    set print pretty [on|off],控制结构体输出格式,打开则会以如下形式显示:

    $1 = {
    next = 0x0,
    flags = {
        sweet = 1,
        sour = 1
        },
    meat = 0x54 "Pork"
    }
    
  • x /nfu ,查看指定内存中存放的值,addr是个地址之,也可以用p *addr,但是一次只能查看一个字节,没有x好用
    1)n 表示要显示的内存单元的个数
    2)f同上面print指令中的f作用一样
    3)u表示一个地址单元的长度,可取如下值:
    b表示单字节
    h表示双字节
    w表示四字节
    g表示八字节

  • display [var],设置想要跟踪的变量,自动显示
    display/[n]i $pc,每次回到gdb命令行时,显示当前要执行的汇编指令,n为显示条数
    info display,简写i display:显示所有跟踪变量
    undisplay [varnum|varnum1-varnum2],取消禁用指定编号/范围的变量跟踪显示,(gdb) undisplay 1
    disable display [varnum|varnum1-varnum2],禁用指定编号/范围的变量跟踪显示,(gdb) disable display 2-4
    enable display [varnum|varnum1-varnum2],启用指定编号/范围的变量跟踪显示
    delete display [varnum|varnum1-varnum2],删除指定编号/范围的变量跟踪显示

  • whatis [var]ptype [var],显示一个变量的类型

五、永久/条件/一次/自动断点操作

  • break,简写b
    b,在下一条命令处停止运行
    b [函数名],在某个函数的开始处设置断点,(gdb) b main
    b [行号],在当前文件的指定行,(gdb) b 10
    b [文件名:函数名/行号],指定文件的指定行
    b [*address],在程序运行的内存地址处打断点
    以上任意b命令 [if ]condtrue时,指定位置打断点,(gdb) b 10 if i==12

  • rbreak [REGEX|FILE:REGEX].REGEX是正则表达式,程序中函数的函数名只要满足REGEX条件,rbreak命令就会其内部的开头位置打断点。如在所有函数上面打断点(gdb) rbreak .,在main.c文件中的所有函数上面打断电(gdb) rbreak main.c:.

  • tbreak,简写tb,临时断点,只生效一次,如(gdb) tb main.c:10

  • watch,一般来观察某个表达式(变量也是表达式)或内存地址的值是否发生了变化,如果发生变化则程序立即暂停,自动断点
    watch [exp|*addr],为exp设置一个观察点,如果其值变化,程序暂停,(gdb) watch a(gdb) watch *(int *) 0xffffff318c
    rwatch [exp|*addr]exp被读时,程序暂停
    awatch [exp|*addr]exp的值被读或被写时,程序暂停
    info watchpoints,列出当前所设置的所有观察点

  • ignore N COUNT,让N断点执行COUNT后停下,也就是前COUNT - 1次该断点不会起效

    (gdb) b lj_BC_JLOOP 
    Breakpoint 3 at 0x12003b020
    (gdb) ignore 3 316
    Will ignore next 316 crossings of breakpoint 3.
    
  • info breakpoints,简写i b:查看所有断点信息

  • disable [break-num],禁用某一个断点

  • enable [break-num],启用某一个断点

  • delete [break-num],简写d [break-num]:删除某一个断点

  • save breakpoints [file-name],将设置的断点保存下来,等需要时(退出gdb再进入也ok),使用命令source [file-name]批量设置被保存的断点,保存和使用的[file-name]一致既可

六、查看源码及其编译后的相关信息

  • list命令,简写l
    l,显示当前行后面的代码
    l [-],继当前显示向前再显示10行
    l [行号],显示10行,指定行号处于中间位置
    l [fun-name],显示指定函数名的上下文
  • backtrace,简写bt:查看当前程序的调用堆栈
    info frame,简写i f:查看当前栈帧信息
    frame [num],简写f [num]:切换到其他堆栈处,通常与bt一起使用,(gdb) f 2。也可以用up [num]down [num]向上或向下选择函数堆栈帧,其中n是层数
  • show args,查看发送给程序的参数(run后面跟的参数)
  • info registers,简写i r:查看除了浮点寄存器以外的寄存器
    info register [reg-name],简写i r [reg-name]:查看指定寄存器reg-name
    info all-registers,简写: 查看所有的寄存器包括浮点寄存器
    p $reg-name,可以查看寄存器的值
  • info break,简写i b:查看所有断点信息
  • info functions 查看所有的函数
  • info watchpoints,查看当前设置的所有观察点
  • info signals info handle,查看有哪些信号正在被gdb检测
  • info line [currLineNum],查看源代码在内存中的地址
  • info threads,查看线程信息,只会输出线程的简短信息,通常只是一层栈
    (gdb) info threads
      Id   Target Id                                  Frame 
    * 1    Thread 0xfff7c3ce70 (LWP 26956) "sysbench" main (argc=2, argv=0xffffff33b8) at sysbench.c:1405
    
  • info source,查看当前所在的源代码文件信息,文件名称,程序语言等
  • info files,查看当前可执行文件的一些信息,如程序入口地址、各个段的内存布局等
  • info frame,查看当前函数栈的一些详细信息
    (gdb) info frame
    Stack level 0, frame at 0xffffff2d40:
     pc = 0xaaaab00e4c in sb_histogram_print (sb_histogram.c:321); saved pc = 0xaaaab85948
     called by frame at 0xffffff2d40
     source language c.
     Arglist at 0xffffff2d40, args: h=0xaaaae46020
     Locals at 0xffffff2d40, Previous frame's sp is 0xffffff2d40
     Saved registers:
      gp at 0xffffff2d28, s8 at 0xffffff2d30, ra at 0xffffff2d38, pc at 0xffffff2d38
    

七、反汇编相关

  • b *fun-name,在函数的第一条汇编指令打断点
  • 自动反汇编后面要执行的代码
    set disassemble-next-line auto,当前代码没有源码(没有调试信息)时,自动反汇编执行到的每一行代码
    set disassemble-next-line on,不管是否有源码,都自动反汇编执行到的每一行代码
    set disassemble-next-line off,关闭自动反汇编功能
  • display /[n]i $pc,显示当前要执行的汇编指令,n为显示条数
  • disassemble [/r] fun-name,查看函数fun-name的反汇编代码
    /r参数,以16进制显示每条汇编指令的值,下面指令都可以使用
    disassemble /m fun-name,将函数的每一行源码与其汇编指令对应显示
    disassemble addr:将addr所在函数的指令全部反汇编
    disassemble addr1, addr2:反汇编[addr1, addr2)处的指令,常与info line [currLineNum]配合使用

八、多进程与多线程

调试多进程常用命令。

  • set follow-fork-mode [child|parent],设置调试哪个进程
    child,调试子进程
    parent,调试父进程
  • set detach-on-fork [off|on],GDB在fork之后是否断开(detach)某个进程的调试
    off,同时调试父进程和子进程
    on,只调试父进程
  • set schedule-multiple on,让父子进程都同时运行
  • info inferiors,查看所有进程信息
  • inferiors ,切换到指定进程

调试多线程。用gdb调试多线程程序时,一旦程序断住,所有的线程都处于暂停状态。此时当你调试其中一个线程时(比如执行“step”,“next”命令),所有的线程都会同时执行。

  • set print thread-events off,当有线程产生和退出时,就不会打印提示信息

  • show scheduler-locking, 查看控制其他线程执行的设置

  • set scheduler-locking [off|on|step]
    on,表示调试线程执行时,其余线程锁定,阻塞等待
    off,表示不锁定其他线程,也是默认值
    step,表示在step(单步)调试时,只有当前线程运行,其它线程不会执行,但是用其它命令(比如"next")调试线程时,其它线程也许会执行

  • info threads,查看所有线程的信息

  • thread ,切换到指定线程

  • break thread ,在line行为指定tid的线程打断点

  • break thread all,在line行为所有的线程打断点

  • thread apply ,让tid线程执行gdb_cmd命令

九、其它常用命令

  • Enter键,复制上一条命令

  • help [cmd],指定命令帮助提示,(gdb) help list

  • quit,简写q,退出GDB调试环境

  • gcc -g编译生成的程序,是不包含预处理器宏信息; 如果想在gdb中查看宏信息,可以使用gcc -g3进行编译

  • set logging xxx组合可以将调试信息输出到指定文件,下面将gdb调试的过程记录到thread_info.txt文件中:

    set height 0	##设置在文件中的起始位置
    set logging file thread_info.txt	##指定输出文件
    set logging on	##此命令之后的所有调试信息将输出到thread_info.txt文件
    ## 开始gdb调试,会将过程记录
    set logging off	##关闭到指定文件的输出
    
    ## 在启动gdb的时候加入tee命令也可以保存调试信息,不过这就没有上面的方式灵活
    gdb ./a.out | tee log_file
    
  • info sharedlibrary regex,显示程序加载的共享链接库信息,其中regex可以是正则表达式,意为显示名字符合regex的共享链接库。如果没有regex,则列出所有的库

    (gdb) info sharedlibrary
    From                To                  Syms Read   Shared Object Library
    0x000000fff7fd2540  0x000000fff7feafd8  Yes         /lib64/ld.so.1
    0x000000fff7ef28f0  0x000000fff7f4e56c  Yes         /lib/loongarch64-linux-gnu/libm.so.6
    0x000000fff7ed90b0  0x000000fff7eda064  Yes         /lib/loongarch64-linux-gnu/libdl.so.2
    0x000000fff7e91a90  0x000000fff7eb9300  Yes (*)     /lib/loongarch64-linux-gnu/libgcc_s.so.1
    0x000000fff7cfd040  0x000000fff7df7af8  Yes         /lib/loongarch64-linux-gnu/libc.so.6
    (*): 带“*”表示库缺少调试信息.
    
  • stack 20,查看栈内20个值
    vmmap,查看映射状况 peda带有
    readelf,查看elf文件中各个段的起始地址 peda带有
    parseheap,显示堆状况 peda带有

你可能感兴趣的:(工具及使用经验,gdb)