您现在的位置是:首页 > 正文

还不会gdb?看这一篇就够了

2024-02-29 13:24:06阅读 2

目录

gdb是什么?它有啥威力

gdb常用命令

gdb实战

基本使用

解决coredump!

总结


大家好,我是小李。

今天这一篇博客来跟大家介绍一个非常有用的工具 —— gdb,不管是学习还是工作中,用好gdb,能让你的程序更加丝滑!

gdb是什么?它有啥威力

首先,简单介绍下gdb。gdb的全称是GNU debugger,看名字就知道 gdb 是用来对程序进行 debug 的。

具体来说,gdb有啥用呢?想想这个场景,当我们满心欢喜的写了若干 h 的代码,并且review了好久之后,终于要开始运行了,结果发现输出和预期咋不一样捏?怎么还coredump了捏?当然,有小伙伴会说了,我在可能发生错误的地方用printf把一些可能出错的变量都打出来不就好了吗?这种方式的确也是一种debug 的方式,但是这种方式非常麻烦,对于小程序尚且可以很好地debug,但是对于大型程序来说,这种方式就显得非常“玩具”了。

printf对比于gdb来说:

  • 首先,你可能要加上数不清的 printf 语句,重新编译运行,调试完又得把这些printf语句全部删除,很麻烦;

  • 其次,printf不够灵活,如果我想当某个变量满足一定条件的时候,就让它正常执行,否则单步观察它是怎么影响后续程序的。此时,printf无法达到这样的效果,但是gdb可以。

gdb常用命令

小李相信任何一种工具都是设计者耗费大量精力设计编码出来的,我们作为使用者无法做到面面俱到,完全深入。但是我们能做到的是掌握它的一些常见用法,熟练运用到学习和工作中提升生产效率。

gdb博大精深,但是常用到的命令其实也不多。接下来,小李给大家简单介绍下一些常用命令:

  • 首先,我们在编译的时候要加上 -g 参数,这样编译器才会在生成的 ELF 格式文件中加上一些必要的信息以供gdb进行识别和响应,这是使用gdb的前提;

    gcc -o filename -g filename.c
  • 然后,启用 gdb 进行调试:

    gdb --args filename arglist # 进入调试,并传入参数 arglist
  • start / run —— 在gdb里面让程序跑起来:使用 run 或者 start 命令可以在gdb里面让程序运行起来,其中 start 默认在main函数开头有个断点,让程序在 main 函数开头停下来;而 run 则会在遇到第一个手动设置的断点时才停下来;

  • break —— 强大的断点命令:gdb中最核心的部分之一就是打断点,我们可以使用 break 命令在任意想要让程序停下来的地方打断点,其中断点可以设置为函数名,也可以是指定的代码行:

    b funcName # break可以简写为b,其中funcName是想要断点的函数名,程序执行到funcName的时候会自动停下 
    b lineNum # lineNum是代码行号 
    info b # 查看当前程序的所有断点信息 
    delete bID # 通过 info b 可以查看到断点信息bID,使用delete删除某个断点 
    disable bID # 关闭断点bID 
    enable bID # 开启断点bID tbreak # 设置临时断点
  • next / step —— 让程序往下走“一步”:当程序执行到我们设置断点的地方然后停下来了,这个时候我们想要看看程序接下来是怎么变化的,可以使用 next / step命令。其中step和next都表示让程序单步执行一行代码,但是它们的主要区别在于如果下一行是函数调用的话,step会跳进函数里面继续执行,而next命令则直接执行完这个函数;

    n # next 可以简写为n 
    s # step 可以简写为s
  • finish —— 跳出这个函数:当我们使用step进入某个函数后,通过观察发现这个函数没啥问题,现在想要从这个函数跳出去,而这个函数里面有个循环了若干次的for/while语句,如果使用next命令单步执行到函数末尾的话就有点太慢了。此时可以使用 finish 命令直接执行完这个函数,返回到被调用的地方。

  • watch —— 监视某个变量:我们如果只是想观察程序中某个变量是怎么变化的,那么可以使用 watch 命令,当被观察的值发生变化的时候,程序会自动打印出观察量变化前后的值。

    watch var # 观察变量 var 
    watch (var > 20) # 当var的值大于20的时候,watch才会进行观察
  • backtrace + frame —— 查看调用栈:当我们执行到某个断点时发现了异常值,那么这个异常值是怎么一步一步变成这样的呢?此时可以使用backtrace命令查看函数调用栈,函数调用关系被压在数据结构栈中,当前函数在栈中的下标是 0,调用链往上的函数编号递增;然后搭配 frame 命令可以进入函数调用栈中其他任意函数

    bt # backtrace 可以缩写为 bt 
    frame btID # 使用frame 加上函数在栈中的编号可以跳到调用栈中的某个函数进行观察
  • info —— 强大的查看命令:使用info 命令可以查看局部变量、断点信息、线程信息、寄存器信息等...

    info b 
    info locals 
    info threads 
    info registers
  • quit —— 退出gdb调试

gdb实战

基本使用

掌握了上述基本命令之后,我们可以使用它们的组合进行快乐地 debug 了,一般的流程和组合如下:

  • -g编译

    gcc -o finename -g filename.c
  • --args 带参数gdb:我们可以给执行文件传入参数进行debug

    gdb --args ./filename arg_lists
  • break 设置断点并运行:我们在想要进行观察的函数或者代码行打断点,然后运行程序

    b lineNum run
  • print / bt 查看关键信息:

    print var # 打印想要观察的变量 var 
    bt # 查看函数调用栈,并获取函数在栈中的编号 btId 
    frame btID # 进入调用栈中的函数,继续使用 print 观察

解决coredump!

写代码最怕遇到的是什么?segmentation fault!

一般产生segmentation fault是因为访问了不该被访问的内存地址,此时,linux会在/proc/sys/kernel/core_pattern指定目录下生成一个 coredump 文件,其中包含了产生异常时的进程空间信息。

有同学会说了 “小李啊,我没找到coredump文件啊”,使用 ulimit -c unlimited 设置完再试试捏?然后搭配上面提到的基本命令,就可以快乐地进行错误定位啦!

ulimit -a # 查看系统给core文件配置的大小 
ulimit -c unlimited # 给 core 文件配置无上限,便于生成 coredump 文件 
gdb filename coredump # 对core文件进行gdb 
bt # 查看产生异常时的调用栈关系 
frame btID # 进入调用栈中的某个函数 
info locals # 查看函数的局部变量信息 
up n/ down n # 当前函数栈往前 or 往后几步

总结

以上就是 gdb 的基本使用方法了,掌握了上述基本命令和基本场景使用就能应对学习和工作中的大部分问题了。工具的使用关键在于熟能生巧,希望同学们能多多使用,但也祝大家都能写出没有bug的代码!

 

小李也是在不断地学习与总结中,非常欢迎同学们和小李进行留言交流,大家一起学习进步。

本文将根据工作场景进行持续更新,欢迎同学们关注我呀!

网站文章

  • poj 2376 清洗的转变 set实现 (程序设计竞赛题集)

    时间限制: 1000MS 内存限制: 65536 K 共提交: 24198 接受: 6056 描述 农夫约翰分配一些他 N (1 < = N < = 25,000) 牛要做一些清洁家务的谷仓。他总是想要一只奶牛,工作的东西清理,已将一天分为 T 的变化 (1 < = T < = 1,000,000),第一次被转移 1 和最后一次是转移 T.

    2024-02-29 13:23:58
  • java数据结构书籍推荐,已拿offer附真题解析

    java数据结构书籍推荐,已拿offer附真题解析

    前言Linux 网络协议栈是根据 TCP/IP 模型来实现的,TCP/IP 模型由应用层、传输层、网络层和网络接口层,共四层组成,每一层都有各自的职责。应用程序要发送数据包时,通常是通过 socket...

    2024-02-29 13:23:27
  • 【目标检测】Cascade R-CNN: Delving into High Quality Object Detection论文理解

    【目标检测】Cascade R-CNN: Delving into High Quality Object Detection论文理解

    文章目录摘要1 介绍2 相关工作3 目标检测3.1 边界框回归3.2 分类3.3 检测质量4 Cascade R-CNN4.1 级联边界框回归4.2 级联检测5 实验结果5.1 实现细节5.1.1 b...

    2024-02-29 13:23:19
  • Hive开窗函数(窗口函数)_四大类型实战案例

    Hive开窗函数(窗口函数)_四大类型实战案例

    去年分别给大家整理了Oracle和HIve开窗函数的相关知识,文见 Hive分析函数整理(开窗函数、窗口函数) 今天再进一步整理窗口函数常用四大类型用法 测试数据集 -- 建表 CREATE DATA...

    2024-02-29 13:23:12
  • jupyter notebook 上传文件夹问题

    jupyter notebook本地直接解压缩后,只能上传单个或多个文件,多个文件夹无法上传。 直接在本地的文件夹下:C:\Users\Administrator(自己的电脑路径),直接拷贝文件夹即可。 ...

    2024-02-29 13:22:42
  • http://www.xueh188.top/index.php/archives/35/

    在 /** * 初始化事件 */ initEvent: function () {}添加table.on('tool(bsDepartmentTable)', page.option);即 init: function () { myTable.on('tool(bsEnterp...

    2024-02-29 13:22:35
  • Linked List Cycle II的总结

    Linked List Cycle II的总结

    文章目录Linked List Cycle II的总结关键知识解题思路简单做法最佳解法题目简答做法最优解法题目地址Linked List Cycle II的总结关键知识链表的处理解题思路一种简单的做法就是顺序遍历每个结点,然后每次都判断该点是否在前面遍历过的结点中,可以采用两层遍历的做法或者是采用set来存储前面的结点,然后每次在set中find这个结点。但是set会将空间复杂度大大增加...

    2024-02-29 13:22:27
  • SOA 和微服务有何区别?

    SOA 和微服务有何区别?

    玩过 Dubbo 的小伙伴应该都有听说过一个概念叫做 SOA,每当我们说起微服务的时候,很多人就会去纠结这和 SOA 有啥关系呀?感觉换汤不换药呀。今天松哥来稍微和小伙伴们讨论下这个话题,我们一起来看看 SOA 和微服务到底有何异同。

    2024-02-29 13:21:58
  • kafka入门教程

    kafka入门教程

    一、下载安装 kafka官网:http://kafka.apache.org/intro (可选)看下官网的introduction 选择get started-quick start ,按照步骤来(...

    2024-02-29 13:21:53
  • ssh 客户端登陆报 No further authentication methods available

    No further authentication methods available

    2024-02-29 13:21:46