gdb调试技巧分享

gdb调试技巧

线程切换控制

set scheduler-locking on|off|step

  • on:启用线程切换
  • off:禁止线程切换
  • step:单步调试时禁止线程切换

处理信号

handle SIGCONT nostop noprint

core文件调试

当进程崩溃时,通过系统dump出来的core文件来排查程序崩溃原因,如果不确定是否开启,可以通过ulimit -c命令查看,如果输出为0,则表示未开启,可以通过ulimit -c unlimited命令开启。
dump的core文件放置目录的格式,由/proc4/sys/kernel/core_pattern设置

echo "/corefile/core-%p-%t" > /proc/sys/kernel/core_pattern

通过gdb 进程文件路径 core文件路径来调试,然后输入bt打印调用堆栈,查看程序崩溃时的代码位置。

gdb调试

gdb链接正在运行的进程以进行调试

gdb -p `pgrep 进程名`

单步调试

  • step
    就是单步执行,遇到子函数就进入并且继续单步执行;在其他调试其中相当于step-into命令,作用是移动到下一个可执行的代码行。如果当前行是一个函数调用,则调试器进入函数并停止在函数体的第一行。step可以帮助初步揭开代码位置的谜团,例如:函数调用和函数本身可能在不同的文件中。
  • next
    是在单步执行时,在函数内遇到子函数时不会进入子函数内单步执行,而是将子函数整个执行完再停止,也就是把子函数整个作为一步。在其他调试器中相当于step-over,作用是在同一个调用栈层中移动到下一个可执行的代码行。调试器不会进入函数体。如果当前行是函数的最后一行,则,next将进入下一个栈层,并在调用函数的下一行停止。
  • finish
    就是但单步执行到子函数内时,用step out就可以执行完子函数余下部分,并返回到上一层函数。在其他调试器中相当于step-out,作用是在栈中前进到到下一层,并在调用函数的下一行停止。
  • ni/si
    汇编级别的next/step

断点

  • break <断点表达式>设置断点,支持

    1. 类名::成员函数 b class_a::function
    2. 源码文件:行数 b file_1:12
    3. 函数名 b function
    4. 指定地址 b *0x00000000004004ee
    5. 源码文件:函数 b file_1:function
  • info break 查看断点

  • delete <断点号>删除指定断点

  • clear 删除所有断点

  • watch <变量名> 监视变量,变量改变时程序暂停

条件断点

break 断点 if 条件
条件支持c语法,可以调用程序中的函数,例如

  • break func if a == 10
  • break func if strcmp(a, b) == 0
  • condition 断点号 [条件表达式]: 用来修改一个断点的条件,可增删改

打印变量p、x

支持c++语法打印变量,如

  1. p/fu 实例名.成员
  2. p/fu *(指针)
  3. p/fu $rsp 打印寄存器或gdb定义的变量
  4. x/nfu 打印内存

n、f、u格式见后表格

代号意义取值范围
n打印的数据单元数整数
f打印的数据单元长度b(byte), h(halfword), w(word), g(giant, 8 bytes)
u打印的格式o(octal), x(hex), d(decimal), u(unsigned decimal),t(binary), f(float), a(address), i(instruction), c(char) and s(string)

上表信息可以通过 help x 获取
打印字符串时,字符串过长会省略显示,可以通过以下命令解决

(gdb) show print elements
Limit on string chars or array elements to print is 200.
(gdb) set print elements 0
(gdb) show print elements
Limit on string chars or array elements to print is unlimited.

变量的格式特征

  1. 如果value为指针,打印出来的是0x开头
  2. 如果是对象(结构体或类),打印出来是以{}包裹起来的

有时候程序中存在同名变量,打印出来的值很可能不是你想要的,这时可以首先通过gdb打印变量的格式来判断下是否打的是其他同名变量
一个程序可能链接多个动态库,这些库中可能使用了同名变量,这时打印出来的值很可能出乎你意料,解决办法,利用工具修改库中的同名符号(未验证)

变量自动打印

  • display 变量名 程序暂停时自动打印该变量
  • undisplay 变量编号 取消变量的自动打印,通过display可以查看编号

命令脚本

把需要的序列化的命令操作直接一行行写到一个文件,然后直接

gdb 程序 --command=命令文件

环境变量

  • show paths: 展示当前程序系统PATH路径
  • show environment [varname]:展示当前程序指定或全部环境变量的值
  • set environment varname[=varlue]: 设置环境变量
  • environment可以缩写为env

多线程调试

  • thread aplly all bt:查看所有线程的调用栈
  • info threads [id]:查看所有(或指定)线程的信息,id是指序号,不是指线程id,多个id用空格隔开

查看栈信息

  • backtrace(bt): 打印函数调用栈
  • frame <n>: 打印当前栈帧信息或跳转到第n号调用栈帧
  • up/down <n>:向上/下移动一个或n个栈帧
  • info frame: 这个命令会打印出更为详细的当前栈层的信息,只不过,大多数都是运行时的内内地址。比如:函数地址,调用函数的地址,被调用函数的地址,目前的函数是由什么样的程序语言写成的、函数参数地址及值、局部变量的地址等等
  • info args: 打印出当前函数的参数名及其值。
  • info locals: 打印出当前函数中所有局部变量及其值。
  • info catch: 打印出当前的函数中的异常处理信息。

查看CPU寄存器

  • info all-reg:查看所有CPU寄存器
  • info float:查看浮点寄存器
  • info registers:查看CPU通用和特殊功能寄存器

修改寄存器或内存值

  • set $eax=0
  • set {unsigned int}0x8048481=50

查看源程序

  • list <linenum>: 显示程序第linenum行的周围的源程序。
  • list <function>: 显示函数名为function的函数的源程序。
  • list: 显示当前行后面的源程序。
  • list -: 显示当前行前面的源程序。
  • list <first>, <last>: 显示从first行到last行之间的源代码。
  • list , <last>: 显示从当前行到last行之间的源代码。
  • list +: 往后显示源代码。

指定源文件的路径

某些时候,用-g编译过后的执行程序中只是包括了源文件的名字,没有路径名。GDB提供了可以让你指定源文件的路径的命令,以便GDB进行搜索。
directory <dirname … >: 加一个源文件路径到当前路径的前面。如果你要指定多个路径,UNIX下你可以使用“:”,Windows下你可以使用“;”。
directory: 清除所有的自定义的源文件搜索路径信息。
show directories: 显示定义了的源文件搜索路径。

源代码的内存

你可以使用info line命令来查看源代码在内存中的地址。info line后面可以跟“行号”,“函数名”,“文件名:行号”,“文件名:函数名”,这个命令会打印出所指定的源码在运行时的内存地址,如:
info line tst.c:func

  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值