GDB的使用

大耗子 2020年02月20日 308次浏览

GDB安装插件

下载链接: git clone https://github.com/gatieme/GdbPlugins.git ~/GdbPlugins

设置方法如下:

echo "source ~/GdbPlugins/peda/peda.py" > ~/.gdbinit
echo "source ~/GdbPlugins/gef/gef.py" > ~/.gdbinit
echo "source ~/GdbPlugins/gdbinit/gdbinit" > ~/.gdbinit

根据个人喜好选择自己喜欢的调试脚本

GDB的命令

启动方法

  • 本地普通启动 gdb <program>
  • 本地段错误文件启动 gdb <program> core
  • attach方式启动 gdb <program> <PID>
  • 远程启动 gdbserver 0.0.0.0:1234 /path/to/file

Linux程序发布流程

  • 确定程序是否存在符号表
    readelf -s test
  • 生成符号表
    objcopy --only-keep-debug test test.symbol
  • 生成发布程序
    objcopy --strip-debug test test-release
  • 使用符号表进行程序debug
    gdb -q --symbol=test.symbol --exec=test-release

调试

基本命令

  • 展示代码

    list [文件名]:行数

  • 设置代码区块长度

    set listsize 长度

  • 设置参数

    set args 参数...

  • 执行下一步

    进入函数s(step) 
    不进入函数n(next) 
    跳出循环u(until)
    跳到下一个断点c(continue)
    快速结束函数f(finish)
    
  • 查看变量类型

    pt 变量名

  • 查看变量的值

    单个输出变量值:print 变量名
    输出局部所有变量:info local
    
    print 输出格式
    x 按十六进制格式显示变量。
    d 按十进制格式显示变量。
    u 按十六进制格式显示无符号整型。
    o 按八进制格式显示变量。
    t 按二进制格式显示变量。
    a 按十六进制格式显示变量。p/a i 
    c 按字符格式显示变量。p/c i 
    f 按浮点数格式显示变量。
    
    查看数组 
    p *array@len  # 人为数组,查看内存中的连续对象
    如果是静态数组,直接 p array 
    
    
  • 查看内存

    x 地址 (例如:x &i)
    输出十进制:x/d 地址
    x命令的语法如下所示
    x/n、f、u是可选的参数
    x/s 输出字符串
    n 是一个正整数,表示显示内存的长度,是从当前地址向后显示几个地址的内容。
    f 表示显示的格式,跟print 的格式参数相同
    u 表示从当前地址往后请求的字节数,如果不指定的话,GDB默认是4个bytes。u参数可以用下面的字符来代替,b表示单字节,h表示双字节,w表示四字节,g表示八字节。当我们指定了字节长度后,GDB会从指内存定的内存地址开始,读写指定字节,并把其当作一个值取出来。
    n/f/u三个参数可以一起使用 
    例如:
    x/3uh 0x54320 表示,从内存地址0x54320读取内容,h表示以双字节为一个单位,3表示三个单位,u表示按十六进制显示。 
    
  • 查看函数调用栈

    bt

  • 调核文件的时候,调栈

    frame [num]

  • 输出栈信息

    info frame

  • 使用shell命令

    shell + 命令

  • 修改变量值

    print i=10

  • 搜索源代码

    局部搜索:
        向后搜索:search <regexp>
        向前搜素:forward-search <regexp> 
    全文搜索:
    	reverse-search <regexp> 
    其中,<regexp>就是正则表达式,也可以是一个字符串的匹配模式
    
    

暂停调试

  • 查看断点信息

    info breakpoints

  • 打断点

    设置普通断点:
    	break [文件名]:行数 或者 break 函数名 或者 break 地址
    设置条件断点:
    	break 行数 if 条件
    
  • 设定观察点:在内存出现变动的是后,马上断下来

    当值被写的时候:
    	watch 变量 或者 watch 函数::变量
    当值被读的时候:
    	rwatch 变量 或者 rwatch 函数::变量
    当值被写或被读的时候:
    	awatch 变量 或者 awatch 函数::变量
    
  • 设定捕捉点

    catch <event>
    当event发生时,停住程序。event可以是下面的内容:
    1、throw 一个C++抛出的异常。(throw为关键字)
    2、catch 一个C++捕捉到的异常。(catch为关键字)
    3、exec 调用系统调用exec时。(exec为关键字,目前此功能只在HP-UX下有用)
    4、fork 调用系统调用fork时。(fork为关键字,目前此功能只在HP-UX下有用)
    5、vfork 调用系统调用vfork时。(vfork为关键字,目前此功能只在HP-UX下有用)
    6、load 或 load <libname> 载入共享库(动态链接库)时。(load为关键字,目前此功能只在HP-UX下有用)
    7、unload 或 unload <libname> 卸载共享库(动态链接库)时。(unload为关键字,目前此功能只在HP-UX下有用)
    
    tcatch <event>   只设置一次捕捉点,当程序停住以后,应点被自动删除
    
  • 断点失效

    失效:disable 断点号
    开启:enable 断点号
    删除:delete 断点号
    
  • 在断点处自动化执行命令

    commands 断点号
    .
    .
    .
    end 
    输入end结束输入命令
    
  • 自动显示变量值

    添加自动变量:
    display expr
    display /fmt expr
    display /fmt addr
    
    例:读取数组
    display /x *array@4 
    
    
    删除:
    undisplay nums
    

多进程调试

  • gdb跟踪模式

    查看:
    	show follow-fork-mode
    设置:
    	set follow-fork-mode [parent|child]
    
  • 多线程执行模式

    查看:
    	show detach-on-fork  
    设置:
    	set detach-on-fork [on|off]    
    on: 只调试父进程或子进程的其中一个(根据follow-fork-mode来决定),这是默认的模式。
    off: 父子进程都在gdb的控制之下,其中一个进程正常调试(根据follow-fork-mode来决定),另一个进程会被设置为暂停状态。
    
  • 进入某进程

    attach <PID>

  • 查看当前运行在那个进程上

    info inferiors

  • 切换进程

    inferior <进程在当前gdb的编号>

  • 清除进程

    remove-inferiors 编号

    detach inferiors 编号

    kill inferiors 编号

  • 新添加进程(复制或者执行新程序)

    add-inferiors [-copies n] [-exec executable]

多线程调试

  • 查看线程

    info threads

  • 切换线程

    thread <ID>

  • 对线程执行的地方打断点

    break file.c:<rownum> thread <all|num>

  • 设置线程调试执行模式

    查看:
    	show scheduler-locking 
    设置:
    	set scheduler-locking [off|on|step]
    off 不锁定任何线程,所有线程都执行,默认值。 
    on 只有当前被调试程序会执行。 
    step 在单步的时候,只有当前线程会执行。