【Linux】Linux下调试器gdb的使用

简介: 【Linux】Linux下调试器gdb的使用

一、前言


前几篇 Linux 博客中,我们分别学习了与编辑、编译、自动化构建代码、上传代码的工具。而今天,我们将学习最后一个工具 —— Linux 下的调试器 gdb 。


而 gdb 这个调试工具的指令有很多,且在 Linux 下并没有图形化界面,所以 gdb 调试的体验并不是很好。


所以对于 gdb ,我们的学习目标就是会常用的操作。对于生僻的操作,我们简单介绍,对于常用的操作,我们进行演示。做到学习了前几篇博客之后能在 Linux 上,进行简单的线上开发。


这样也减少了我们学习的成本。


好了,我们这就开始今天的学习。


网络异常,图片无法展示
|



二、铺垫


在讲解使用之前,我们先进行一下铺垫:

程序的发布方式有两种,debug 模式和 release 模式 ,分别是调试版本和发布版本。


debug 模式是程序员在自主编写代码时的模式,在 debug 模式下是 含有调试信息 的;而 release 模式下是 不含调试信息 的 ,且 release 进行了各种优化,方便用户使用。


在 Linux 的 gcc/g++ 编译器下编译的代码往往都是 release 版本 。其实对于这点也很容易想通,我们平常的开发一般是在 ide 上进行,当产品发布时再到 Linux 上进行线上发布,且测试人员测的也是 release 版本的代码。所以为什么是 release 版本就很容易想通了。


事实胜于雄辩,我们再证明一下 :


调试代码:

#include <stdio.h>
int addToTop(int top)
{
    printf("enter addToTop\n");
    int sum = 0;
    for (int i = 1; i <= top; ++i) 
    {
        sum += i;  
    }
    printf("quit addToTop\n");
    return sum;
}
int main()
{
    int top = 100;
    int res = addToTop(top);
    printf("result = %d\n", res);
    return 0;
}


Makefile:

test:test.c
    gcc test.c -o test -std=c99
.PHONY:clean
clean:
    rm -f test



(注:在循环内定义变量为 c99 标准,所以编译时需要加上 -std=c99 )

Release


编译一下文件,并将生成可执行程序改名为 test-release

gdb test-release 进入调试:

e00ad15f5715cbb51545a7d4a372ba4b.png


no debugging symbols found:没有调试信息


而 release 版本是没有调试信息的,没有调试信息就无法调试。


按 quit 退出调试。

   在 Linux 中,编译时添加 -g 选项,就是让 gcc/g++ 编译时以 debug 形式编译 。

Debug :


所以修改一下 Makefile

gcc test.c -o test -g -std=c99


然后继续进行编译,并将编译出的内容改名为 test-debug :

cc10eaba45f7ce0ffa9761aed46e7120.png


gdb-test-debug 开始调试:

bda04b6a33d9ee92fa3137052e8367da.png


这时就可以调试了,验证完毕,按 quit 退出调试。

对比生成文件大小

6816132588ebe9d2c935ce6a5dcf65bc.png


debug 的文件,比 release 大。就是因为里面包含了调试信息等内容。

拓展 :

readelf 指令:读取可执行程序的二进制构成,可执行程序遵守二进制排布规则:elf

用 readelf -S test-debug | grep -i debug 忽略大小写筛一下含有 debug 的信息:


adab0e38b43e5829c7a01dbf6b8c582d.png



当然如果直接查看 test-debug 的二进制排布的话,也可以看到 .data .bss .rodata 等字段,这些也都是我们的老熟人:已初始化全局数据区、未初始化全局数据区以及常量字符串所在的只读全局数据区。


由于图比较大,我就不放出来了,大家感兴趣可以下去查看一下。


好了,讲了这么多,我们的铺垫总结起来无非就是三点 :


       程序有两种发布方式:debug 模式 和 release模式

       Linux 下 gcc/g++ 编译处的二进制程序默认是 release 模式

       要启用 gdb 调试,必须在编译生成可执行程序时加上 -g 选项



三、指令集和使用


1、指令集


/ 代表的就是或者,比如 list / l 就是两者都可以,后一个通常为简写,一般使用简写。


       gdb file :开始调试


       list/l 行号:显示源代码,接着上次的位置往下列,每次列10行。list 通常简写为 l 。


       list 0/1 :从源代码的第一行开始显示代码,每次列 10 行


       list/l 函数名:列出某个函数的源代码,10行


       r / run:运行程序,类似于 vs 上的 f5 ,如果有断点就停在第一个断点处,否则直接执行程序


       n / next:单条执行。也被叫做 逐过程 ,和 vs 上的 f5 一样,遇到函数会直接把函数执行完


       s /step:进入函数调用。也被叫做 逐语句 ,按住会进入函数,包括库函数


       break / 行号:在某一行设置断点


       break 函数名:在某个函数开头设置断点


       info breakpoints/break/b :查看断点信息,查看的断点以编号形式排布,从 1 开始。


       finish:执行到当前函数返回,然后停下来等待命令


       print / p:打印表达式的值,通过表达式可以修改变量的值或者调用函数


       p 变量:打印变量值,类比于短暂监视窗口


       set var:修改变量的值。常用语循环,比如跳转到第 n 次循环


       continue / c:从当前位置开始连续而非单步执行程序。说白了就是从一个断点处,直接运行到下一个断点处,类比于 vs 上的 f5 在断点进行跳转


       delete breakpoints:删除所有断点


       delete breakpoints n:删除序号为 n 的断点


       disable breakpoints:禁用断点,改变断点使能


       enable breakpoints:启用断点


       display 变量名:跟踪查看一个变量,每次停下来都显示它的值(监视窗口常显示)


       undisplay 编号:取消对先前设置的那些变量的跟踪,若使用 undisplag 则全部取消


       until 行号:在函数内进行指定位置跳转,执行完区间代码


       breaktrace / bt:查看各级函数调用及参数。说白了就是查看调用链


       info / i locals:查看当前栈帧局部变量的值


       quit:退出gdb调试


提示:gdb 会记住最近一次的指令,比如上次 l 0 进行翻阅查看,之后一直回车就可以显示出内容。



2、演示


list / l :显示内容

a8f545e26bc5fcb2675dc3ccfca6b773.png


显示函数部分的话,只要求显示片段含有函数名。

list 是查看内容的指令,它不影响实际的调试指令,也就是说 list 显示的内容并不会干扰到当前的调试次序。

断点操作


b 行号 和 b 函数名:打断点

38914a401af57297fc1c2bcb9f57a9a1.png


info breakpoints/break/b :查看断点信息

0112f11e0c7914cbff639ea62aaaaf6b.png


解释:


  • num:断点编号,从 1 开始
  • enb:代表着断点使能。y代表打开;n代表关闭
  • what:说明断点是什么,在哪个函数中,在哪个文件,第几行。

过渡步骤:运行 r 跳转到断点,在断点处停下来

此刻 info b 查看断点信息:

3e76692922b67f50fbef30fc2761340b.png



显示信息:breakpoint already hit 1 time 代表断点命中一次

d 断点编号:删除断点(是编号不是行号) d break :删除所有断点


c4ee2b788fc40fe7bd6471f4f1a83536.png


d break 可以删除所有断点,同理 d breakpoints 和 break breakpoints 也都对

删除时会询问是否删除,y 代表 yes ,n 代表 no

disable b num :关闭断点使能 enable b num :打开断点使能


56051613439580e30e333aa810994650.png

分别显示了断点打开和关闭的过程

info b :可以直接关闭所有的断点使能

这一过程就像 vs 上设置空断点一样

info :查看 info 可以查阅的信息


d9a0096b076a51882fa1656b0d7e1f98.png


逐过程和逐语句

next/n :逐过程,一步可以走掉一个函数,相当于 vs 中的 f10

7b935570f54041a04ec1e5226b7c8639.png


一次走过了函数,函数中打印的内容也会显示出来

还会显示当前行数,以及当前行的内容

s :逐语句,一次走一条代码,可进入函数,同样的库函数也会进入


8800774196e5c619d1660974c5ff286d.png


调用一个函数,就要把函数调用的数据进行压栈

调试位置变成整个代码的第一行

addToTop函数第一行为整个程序的第五行

显示行号和内容

bt :查看调用链

71043d4f88bd91ce72c9a670c82aa01b.png


看到一个函数调用的过程,压栈的过程,main函数在栈底,addtotop就像被压栈了,被压到栈顶

查询数据和常显示数据

p 变量名/地址:暂时查询变量


614bff80ba44d4cb3c0a22e41ff63d2d.png


使用完该指令之后,会给变量一个对应的编号

这个数据只是短暂显示,下次执行指令会消失

display 变量名:常显示变量的数据

1e8f3ef404e02f1d0d5242d2b4bfba99.png


常显示变量数据,类似于 vs 中的监视窗口,display 显示的数据伴随着调试过程一直存在

且会按照 display 的顺序给上相应的编号,显示为倒序显示

undisplay 编号 :取消变量的显示


9b13c4843b5d79189e2b6315ce88aec8.png


undisplay 取消显示后,每次执行不会显示刚刚取消的变量

until 行号:不打断点,在函数内进行指定位置跳转,执行完区间代码


a7ec1b5896697a750add09538b49a9dc.png



刚刚还在执行循环中的内容,使用 until 直接跳转到 11 行,把循环执行完毕

finish:执行到当前函数返回,然后停下来等待命令

假设当前已经进入行数,想要直接跑完这个函数,函数中没有任何断点,跑完之后就停下来:


718535dc9c4f1443c91d83c7dfc33493.png


这样就直接跑完了函数,并显示了返回结果

再次 n 就是返回主函数,并执行完调用函数的语句,返回下一行

continue / c:从一个断点处,直接运行至下一个断点


c4e7b316807a8b3a03a72504fdbd5b2d.png


跳转到下一个断点处,并把跳转过程中打印的内容显示出来

set var :修改变量的值,很适用与循环跳转到指定循环次


bdfcc462bcf639f4767494d22f2eca74.png



在循环中使用 set var i=100 ,直接跳转到 i=99 时的循环次




四、结语


到这里本篇文章就到此结束了。


其实调试本质上就是查找问题的过程,调试完成再根据查找到的问题,修改程序,随后再进行测试,看问题是否已经解决 。


而调试一个程序员必备的技能,我们在日常写代码时,就要慢慢培养自己调试和快速定位错误,即排错的能力。


所以专门讲一下调试器的使用还是很有必要的。


但是对于 gdb ,这个调试器其实使用起来还是挺有难度的。一是因为它没有图形化界面;二是因为它指令繁杂。所以使用 gdb 调试只需要掌握基本就好,看完文章也就差不多了。


而我们的日常开发和调试还是在平常用的 I D E IDE IDE 上,所以不必担心。


建议看完文章的小伙伴也可以下去实操一下,只有操作过才知道会不会。


如果觉得 a n d u i n anduin anduin 写的不错的话,可以 点赞 + 收藏 + 评论 支持一下哦!我们下期见~






































相关实践学习
阿里云图数据库GDB入门与应用
图数据库(Graph Database,简称GDB)是一种支持Property Graph图模型、用于处理高度连接数据查询与存储的实时、可靠的在线数据库服务。它支持Apache TinkerPop Gremlin查询语言,可以帮您快速构建基于高度连接的数据集的应用程序。GDB非常适合社交网络、欺诈检测、推荐引擎、实时图谱、网络/IT运营这类高度互连数据集的场景。 GDB由阿里云自主研发,具备如下优势: 标准图查询语言:支持属性图,高度兼容Gremlin图查询语言。 高度优化的自研引擎:高度优化的自研图计算层和存储层,云盘多副本保障数据超高可靠,支持ACID事务。 服务高可用:支持高可用实例,节点故障迅速转移,保障业务连续性。 易运维:提供备份恢复、自动升级、监控告警、故障切换等丰富的运维功能,大幅降低运维成本。 产品主页:https://www.aliyun.com/product/gdb
相关文章
|
4月前
|
NoSQL Linux C语言
Linux GDB 调试
Linux GDB 调试
68 10
|
4月前
|
NoSQL Linux C语言
嵌入式GDB调试Linux C程序或交叉编译(开发板)
【8月更文挑战第24天】本文档介绍了如何在嵌入式环境下使用GDB调试Linux C程序及进行交叉编译。调试步骤包括:编译程序时加入`-g`选项以生成调试信息;启动GDB并加载程序;设置断点;运行程序至断点;单步执行代码;查看变量值;继续执行或退出GDB。对于交叉编译,需安装对应架构的交叉编译工具链,配置编译环境,使用工具链编译程序,并将程序传输到开发板进行调试。过程中可能遇到工具链不匹配等问题,需针对性解决。
130 3
|
4月前
|
NoSQL Linux 编译器
内核实验(一):使用QEMU+GDB断点调试Linux内核代码
如何配置环境并使用QEMU虚拟机结合GDB进行Linux内核代码的断点调试,包括安装QEMU、交叉编译工具链,编译内核以及通过GDB远程连接进行调试的详细步骤。
188 0
内核实验(一):使用QEMU+GDB断点调试Linux内核代码
|
6月前
|
NoSQL Linux C语言
GDB:强大的GNU调试器
GDB:强大的GNU调试器
|
6月前
|
NoSQL 编译器 Linux
【Linux】--- Linux编译器-gcc/g++、调试器-gdb、项目自动化构建工具-make/Makefile 使用
【Linux】--- Linux编译器-gcc/g++、调试器-gdb、项目自动化构建工具-make/Makefile 使用
101 0
|
7月前
|
NoSQL 搜索推荐 openCL
【C/C++ 调试 GDB指南 】gdb调试基本操作
【C/C++ 调试 GDB指南 】gdb调试基本操作
418 2
|
7月前
|
NoSQL Linux 开发工具
【深入解析git和gdb:版本控制与调试利器的终极指南】(下)
【深入解析git和gdb:版本控制与调试利器的终极指南】
104 0
|
21天前
|
NoSQL 编译器 C语言
C语言调试是开发中的重要技能,涵盖基本技巧如打印输出、断点调试和单步执行,以及使用GCC、GDB、Visual Studio和Eclipse CDT等工具。
C语言调试是开发中的重要技能,涵盖基本技巧如打印输出、断点调试和单步执行,以及使用GCC、GDB、Visual Studio和Eclipse CDT等工具。高级技巧包括内存检查、性能分析和符号调试。通过实践案例学习如何有效定位和解决问题,同时注意保持耐心、合理利用工具、记录过程并避免过度调试,以提高编程能力和开发效率。
36 1
|
4月前
|
NoSQL
技术分享:如何使用GDB调试不带调试信息的可执行程序
【8月更文挑战第27天】在软件开发和调试过程中,我们有时会遇到需要调试没有调试信息的可执行程序的情况。这可能是由于程序在编译时没有加入调试信息,或者调试信息被剥离了。然而,即使面对这样的挑战,GDB(GNU Debugger)仍然提供了一些方法和技术来帮助我们进行调试。以下将详细介绍如何使用GDB调试不带调试信息的可执行程序。
131 0
|
6月前
|
NoSQL Linux C语言
Linux gdb调试的时候没有对应的c调试信息库怎么办?
Linux gdb调试的时候没有对应的c调试信息库怎么办?
53 1
下一篇
DataWorks