当前位置: 首页 > article >正文

Linux_调试器-gdb/cgdb的使用

目录

一、调试器 - gdb/cgdb使⽤

1.调试样例:

2 预备

makefile文件:

📌 安装cgdb:

3.常见的调试命令:

cgbd+[可执行文件] ;

b+[行号] 加断点:

r(run)跑程序

info b 查看断点的信息:

d + [断点编号] 删除断点:

next / n 逐语句:

step / s 进入函数内部

backtrace / bt 查看函数调用栈的结构顺序:

finish 执行到当前函数返回位置:

p + [变量],指定打印变量的值;

b + [函数名] 就是给函数的入口处打上断点:

disable + [断点编号] 禁用断点:

enable + [断点编号] 启用断点:

quit 退出程序:

调试的本质:

1.找到问题

 continue / c 从当前位置开始连续执行,直到下一个断点处:

until + [行号] 直接跳转到某一行:本质是跑完前面的行数再进行跳转:

display + [变量名] :像vs一样直接进行常显示变量:

watch + [变量值]:能够每次都查看变量的新旧值的变换;

📌 注意:

set var + [变量名] = 修改值  直接在调试过程中进行修改变量值

b + [行号] if + [条件] :设置条件断点:

📌 注意:

总结一下吧~以上就是Linux常用工具的最后一部分内容,vim调式工具cgdb,我自认为还是总结的非常全面的,对我自己有着很大的帮助与收获,希望对你也是~!!!


一、调试器 - gdb/cgdb使⽤

1.调试样例:

#include <stdio.h>
int Sum(int s, int e)
{
    int result = 0;
    for(int i = s; i <= e; i++)
    {
        result += i;
    }
    return result;
}
int main()
{
    int start = 1;
    int end = 100;
    printf("I will begin\n");
    int n = Sum(start, end);
    printf("running done, result is: [%d-%d]=%d\n", start, end, n);
    return 0;
}

2 预备

程序的发布⽅式有两种, debug 模式和 release 模式, Linux gcc/g++ 出来的⼆进制程
序,默认是 release 模式。
要使⽤gdb调试,必须在源代码⽣成⼆进制程序的时候, 加上 -g 选项,如果没有添加,程序⽆法被编译
$ gcc mycmd.c -o mycmd # 默认模式,不⽀持调试
$ file mycmd
mycmd: ELF 64 -bit LSB shared object, x86 -64 , version 1 (SYSV), dynamically
linked, interpreter /lib64/ld-linux-x86 -64. so .2 ,
BuildID[sha1]= 82f 5cbaada10a9987d9f325384861a88d278b160, for GNU/Linux
3.2.0 , not stripped
$ gcc mycmd.c -o mycmd -g # debug模式
$ file mycmd
mycmd: ELF 64 -bit LSB shared object, x86 -64 , version 1 (SYSV), dynamically
linked, interpreter /lib64/ld-linux-x86 -64. so .2 ,
BuildID[sha1]= 3 d5a2317809ef86c7827e9199cfefa622e3c187f, for GNU/Linux
3.2.0 , with debug_info, not stripped

makefile文件:

编译通过后加了-g选项,就是debug版本,可以通过cgdb来进行调试:

查看程序是否右debug信息:注意这里的S是大写

readelf -S mycode | grep -i debug

有debug信息就说明可以进行调试;

📌 安装cgdb:

推荐安装cgdb:
Ubuntu: sudo apt-get install -y cgdb
Centos: sudo yum install -y cgdb

3.常见的调试命令:

cgbd+[可执行文件] ;

不是跟源文件,一定要跟可执行文件!!!

进入cgbd模式,进行调试;

b+[行号] 加断点:

b 16

可以看到,我现在16好添加了一个断点,然后就让程序开始跑起来了;

r(run)跑程序

程序跑起来后就在断点出停下来,所以断点的本质,就是让程序能够停在断点处;

info b 查看断点的信息:

info b

d + [断点编号] 删除断点:

跟行数没有关系,是要看具体删除的是第几个断点:

添加一个端点后,删除第一个断点:

d 1

再次查看就没有断点了;

next / n 逐语句:

不进入函数内部

n

可以看到n一下就是走一步,直到越过printf语句,打印出程序结果;

当越过return 0;时程序就会结束;

看到图中程序已经结束,然后再次info b查看断点,可以发现断点还是存在,并且已经被命中了一次;

当程序再次跑起来的时候,可以发现,程序仍然回到了断点处;所以这就可以证明,如果在调试过程中发现前面信息有漏洞,没能调试好,那么就直接无脑run就可以了,让程序再回到 最初的起点~

step / s 进入函数内部

逐过程:

s

backtrace / bt 查看函数调用栈的结构顺序:

bt

能够看到,函数先完成Sum的出栈,然后再结束main函数;

finish 执行到当前函数返回位置:

现在我的程序正在Sum函数内部一步步运行,但是我现在就想一步直接结束这个Sum函数:

finish

finish后,执行过程直接结束掉Sum函数,回到main函数内部;

 

这一步 n 要取值其实是通过两步进行的,首先return 返回result后的结果要先存入寄存器(%eax),然后再通过寄存器(%eax)取值传给n这个变量;

此时结束完Sum函数后,想观察n有没有取到Sum返回的值,就 :

p + [变量],指定打印变量的值;

p n

发现再16行时,并没有执行完这个过程,n=0;
17行时,n取到了寄存器里面的值,n=5050;

b + [函数名] 就是给函数的入口处打上断点:

断点被使能:

Enb,表示当前断点是否被禁用:

disable + [断点编号] 禁用断点:

disable + [断点编号]

出来打断点是+[断点行号] , 其余的都是加断点编号;

enable + [断点编号] 启用断点:

enable + [断点编号]

quit 退出程序:

quit

调试的本质:

1.找到问题

找到问题的命令;

断点的本质就是把代码进行划分,以块为单位进行快速定位有问题的区域;

finish可以单独来确认是否是哪一个函数出现了问题;

until 直接跳过局部区域,快速执行;

 continue / c 从当前位置开始连续执行,直到下一个断点处:

until + [行号] 直接跳转到某一行:本质是跑完前面的行数再进行跳转:

until + [行号]

当我想直接结束这个循环的时候,可以选择直接跳过这个循环;

display + [变量名] :像vs一样直接进行常显示变量:

display + [变量名]

如果不想查看该变量了,就直接undisplay + [变量编号] :

undisplay + [变量编号]

2.查看上下文代码

3.调试技巧:

watch + [变量值]:能够每次都查看变量的新旧值的变换;

如果当前变量被修改了,watch就会通知我

watch + [变量值]

可以看到info b断点内有一个当前断点值,watchpoint  result , 如果不想观察了,就把他当作断点直接删掉就ok

📌 注意:

如果你有⼀些变量不应该修改,但是你怀疑它修改导致了问题,你可以watch它,如果变化了,就会通知你.

set var + [变量名] = 修改值  直接在调试过程中进行修改变量值

在调试期间,如果能够发现错误,但是又不想返回到源文件进行修改,然后又要重新进行编译,那么就可以直接用set var + [变量名] = 修改值 ;直接进行修改即可;

b + [行号] if + [条件] :设置条件断点:

如果在调试过程中,不使用单步调式,直接c/continue,那么就会直接跳转到条件断点处:

📌 注意:

条件断点添加常⻅两种⽅式:1. 新增 2. 给已有断点追加
注意两者的语法有区别,不要写错了。
新增: b ⾏号/⽂件名:⾏号/函数名 if i == 30(条件)
给已有断点追加:condition 2 i==30, 其中2是已有断点编号,没有if

总结一下吧~以上就是Linux常用工具的最后一部分内容,vim调式工具cgdb,我自认为还是总结的非常全面的,对我自己有着很大的帮助与收获,希望对你也是~!!!


http://www.kler.cn/a/389121.html

相关文章:

  • PHP搭建开发环境(Windows系统)
  • 蓝牙BLE开发——iOS 每次写入数据超过200字节报错?
  • Spark 的容错机制:保障数据处理的稳定性与高效性
  • OpenHarmony4.1蓝牙芯片如何适配?触觉智能RK3568主板SBC3568演示
  • 深入剖析【C++继承】:单一继承与多重继承的策略与实践,解锁代码复用和多态的编程精髓,迈向高级C++编程之旅
  • 区块链技术在电子政务中的应用
  • 境内部署DIfy(上篇)
  • 软件工程中的创建型设计模式:工厂方法模式与抽象工厂模式
  • Java抽象类与接口
  • openresty入门教程:init_by_lua_block
  • ctfshow web入门黑盒测试web380-384
  • 每周算法2:数学+模拟+哈希表+栈+线性dp+贪心(简单)
  • 两个链表求并集、交集、差集
  • 微信小程序开发(二)登录流程
  • CMAKE 编译CUDA项目失败 “/usr/bin/nvcc“ is not able to compile a simple test program.
  • 通义千问API调用测试 (colab-python,vue)
  • 【机器学习】数学知识:指数
  • Android 延时操作的常用方法
  • Linux软件包管理
  • 分布式——BASE理论
  • 【harbor】离线安装2.9.0-arm64架构服务制作和升级部署
  • Java:JVM
  • 解决:使用EasyExcel导入Excel模板时出现数据导入不进去的问题
  • React前端框架:现代网页开发的基石(附带构建简单任务管理应用案例代码)
  • 栈(Stack)和队列(Deque、Queue)
  • 16.useForm