GDB的使用(3)

前情提要:

GDB的基本使用(1)

GDB的基础使用(2)

跳转执行

命令功能
jump <line>跳转到第line行

jump [+ | -] <num>

跳转当当前行向下 \ 上 num行
jump *<addr>跳转到addr地址的代码处,地址前要加*号
jump <label>跳转到指定标签,该标签是goto语句的标签
jump <function>跳转到指定函数内,跳转的函数可以没有出现在当前函数中。只推荐在当前函数内跳转,跳转到其他函数可能会出问题

        中间跳过的代码是不会执行的,跳到的位置如果没有断点,那么GDB会自动继续往后执行,所以一般会在跳转到的地方添加断点,且跳转命令不会更改当前栈帧、堆栈指针、程序计数器以外的任何寄存器。


反向调试

        Ubuntu 24.04、gdb (Ubuntu 15.0.50.20240403-0ubuntu1)环境下,在record模式下无法执行cout、printf等与外设有关的函数,其他环境没有测试。

命令功能
record开始录制回放,只有录制了回放的部分才能反向调试
record-stop结束录制回放
reverse-finish回退执行到在所选函数被调用之前
reverse-next / rn倒退执行,不进入函数
reverse-setp / rs倒退执行,进入函数
reverse-continue / rc倒退执行到上一个断点处

多进程调试

命令功能
set follow-fork-mode <child | parent>设置多进程的跟随模式,child为fork后跟随子进程,parent为跟随父进程,默认为parent模式
show follow-fork-mode查询当前多进程跟随模式
set detach-on-fork <on | off>设置在fork函数创建进程后,gdb是否会detach另一个不被跟随的进程,默认为on,如果想调试多进程,必须设置为off
i inferiors查看当前被调试的进程,id旁的*号代表是当前进程。
gdb用inferior来表示一个被调试进程的状态信息(包括内存空间,进程空间等)。通常情况下,一个inferior代表一个进程,有时候一个inferior不一定会绑定一个进程。这是gdb内部的概念与定义,inferior可以为空。
add-inferior添加一个空inferior,空inferior可以用于attch另一个需要调试的进程,但必须先切换到空inferior
remove-inferiors <id>移除一个空inferior,且不能删除当前inferior
inferior <id>切换到对应inferior
detach inferiors <id>detach对应inferior的进程,也可以切换到对应inferior让然后直接detach
show schedule-multiple显示当前多进程运行模式
set schedule-multiple <on | off>设置多进程运行模式,如果为off,那么只有当前inferior绑定的进程才会受gdb控制运行,其余进程都会被阻塞。如果为on,那么所有inferior对应的进程都会受gdb命令控制,而不是一直阻塞在一个地方。
为on模式下,n就是所有进程一起向下执行一步,c就是所有进程一起执行到下一个断点处。在off模式下,n和c就只有当前进程会执行命令,其余进程全部阻塞

调用程序内外部函数

命令功能
p / call <expression>对表达式求值,并打印结果值。表达式可以是被调试程序中的自定义函数,也可以是C库函数和操作符(即使是在原程序中没有调用这些函数也可以直接调用)。如果是执行函数,需要在函数中传入参数

         在调用sum(int, int)时直接传入参数:

        

         如果是通过p调用,那么即使返回值是void也会显示出来;如果是通过call调用,如果返回值是void就不会显示

        

        这种调用方式会真实地执行一次函数,所以可以通过在函数内加断点来调试函数
        

        调用C库函数malloc示例

        在release程序(没有调试符号很多事都做不了)中仍然可以通过p和call来调用函数,如果不知掉程序中有哪些函数,可以通过 i functions来打印程序中的全部函数


调试时跳过指定函数

        s命令不会进入该函数,但是仍然会执行,用于跳过构造函数等一些不重要或不需要关注或连环调用的函数(如srand(static_cast<unsigned int>(time(nullptr))),调用srand的过程中连环调用了time)。

命令功能
skip <function>如果存在同名函数就会跳过所有同名函数,可以通过添加限定符来解决这个问题,如 skip test()就只会跳过无参的test函数,skip test(int)就只会跳过int类型的test函数
skip file <filename>跳过目标文件中的所有函数
skip -gfi <dir> / <*.*>通过通配符的方式来跳过函数,*可以替换。
如:skip -gfi lib/*.cpp就是跳过lib目录中所有后缀为cpp的文件中的所有函数

调试发行版程序

命令(以下都是在bash中执行的命令)功能
objcopy --only-keep-debug <debug file> <debuginfo file>将debug版本程序中的调试符号单独提取出来存到一个文件中
gdb --symbol=<debug file | debuginfo file> -exec=<release file>通过加载debug版本的调试符号来调试release版本的程序
gdb <debug file> <core file>调试release或debug版本的core dump文件

修改可执行文件

流程功能
gdb -write <exe>通过写方式来调试程序,可以是debug程序,也可以是release程序,一般情况下gdb都是以只读方式调试的
disassemble /mr <function>查看需要修改的函数的反汇编
然后通过 p / set来修改内存,记住要判断机器是大端字节序还是小端字节序
q退出


内存泄漏检查

命令功能
call malloc_stats()查看当前进程和当前线程的内存分配情况.主要用于检查某个函数是否发生了内存泄漏,在函数执行前调用一下,在函数执行后调用一下,看看二者是否相同,如果不相同那么就内存泄漏了
call malloc_info(0, stdout)malloc_info的输出格式为xml,主要需要关心的字段为rest(剩了多少)。然后也是通过比较被检查函数调用前后的rest字段对应数值的大小是否变化来判断是否内存泄漏

内存检查(通过gcc-g++编译器来实现)

命令功能
gcc / g++ -fsanitize=address检查内存泄漏,检查栈溢出,检查堆溢出,检查全局内存溢出,检查释放后再使用

        该选项只有在debug模式下支持(即加上-g选项)。


远程调试

服务端 / 被调试机

命令功能
gdbserver <本机ip:gdbserver将使用的端口> <exe>通过gdbserver新启动一个程序来调试
gdbserver <本机ip:gdbserver将使用的端口> --attach <pid>通过gdbserver附上一个已经启动的程序来调试

        被调试机在启动gdbserver后就不能自主退出了,只有在连接上调试机且调试机退出后才会自动退出(kill除外)。

客户端 / 调试机

流程功能 / 解释
gdb(在bash中)直接启动gdb
target remote <被调试机ip:被调试机gsbserver使用的端口)连接被调试机
调试远端调试几乎与本机调试一模一样,但是
远端调试不能使用run,是使用continue来开始执行程序的
远程调试需要需要两端配合起来调试,因为虽然gdb的控制权在调试机手上,但是输入、输出都在被调试机器上
quit / q / detach退出调试,调试机退出了,被调试机会自动退出

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值