【软件开发底层知识修炼】十五 快速学习GDB调试二 使用GDB进行断点调试

  • 上一篇文章我们学习了使用GDB的最基本方法:【软件开发底层知识修炼】十四 快速学习GDB调试一
    入门使用

  • 本篇文章将学习GDB的断点调试。断点调试是一种非常重要的调试方法。

文章目录

  • 1 断点类型
  • 2 GDB软件断点调试相关操作
    • 2.1 通过函数名设置断点
    • 2.2 通过文件名行号设置断点
    • 2.3 其他操作
  • 3 GDB硬件断点及其应用
  • 4 GDB断点调试实际案例
    • 4.1 GDB软件断点调试实际案例
    • 4.2 GDB硬件断点调试实际案例
  • 5 总结

1 断点类型

在具体学习GDB的断点调试之前,先简单了解断点的几种类型:

  • 软件断点:由非法指令异常实现(软件实现,适用于在内存中的程序的调试)
  • 硬件断点:由硬件特性实现(数量有限,适用于FLASH中运行的程序调试)
  • 数据断点:由硬件特性实现(数量有限,用于监视一段内存,该内存中的内容被读或者写,该程序就会被停下来)

2 GDB软件断点调试相关操作

2.1 通过函数名设置断点

  • break func_name [if var = value]
  • 这种方法设置的断点一直有效,程序运行一次后下次运行断点还存在。
  • 如果加上后面方括号里面的内容,就必须在方括号里面的条件成立的时候才能够暂停程序的执行
  • tbreak func_name [if var = value]
  • 设置的断点只有这一次有效,下一次重新运行该程序就没有效果了
  • 如果加上后面方括号里面的内容,就必须在方括号里面的条件成立的时候才能够暂停程序的执行

2.2 通过文件名行号设置断点

  • break filen_name:line_num [if var = value ]
  • 这种方法设置的断点一直有效,程序运行一次后下次运行断点还存在。
  • 如果加上后面方括号里面的内容,就必须在方括号里面的条件成立的时候才能够暂停程序的执行
  • tbreak filen_name:line_num [if var = value ]
  • 设置的断点只有这一次有效,下一次重新运行该程序就没有效果了
  • 如果加上后面方括号里面的内容,就必须在方括号里面的条件成立的时候才能够暂停程序的执行

2.3 其他操作

上面是软件断点调试时的设置断点的操作。下面再给一个表格看看软件断点调试中的一些其他操作:

在这里插入图片描述

  • 其中enable 是将断点使能,使断点可以使用
  • disable是将断点给暂时关闭,但是它还存在,不能使用了而已,下次想使用的时候不需要在重新打断点,直接使用enable使能它即可

还有一些调试时常用的操作:
在这里插入图片描述

3 GDB硬件断点及其应用

  • 当代码位于只读存储器时(FLASH,一般在在嵌入式软件开发中用的比较多),只能通过硬件断点调试
  • 硬件断点需要硬件支持,数量有限
  • GDB中通过使用hbreak命令支持硬件断点
  • hbreakbreak使用方法完全一样

4 GDB断点调试实际案例

本次调试的程序还是和上一篇文章的程序是一样的:

  • test.c
#include <stdio.h>
#include <unistd.h>
extern int* g_pointer;
extern void func();void test_1()
{printf("test_1() : %p\n", test_1);
}void test_2()
{printf("test_2() : %p\n", test_2);
}void test_3()
{printf("test_3() : %p\n", test_3);
}
int main(int argc, char *argv[])
{typedef void(TFunc)();TFunc* fa[] = {test_1, test_2, test_3};int i = 0;printf("main() : begin...\n");for(i=0; i<argc; i++)   //argc代表命令行参数的个数{printf("argv[%d] = %s\n", i, argv[i]);}for(i=0; i<100; i++){fa[i%3]();sleep(argc > 1);    // 如果argc大于1,则执行睡眠函数}printf("g_pointer = %p\n", g_pointer);func();printf("main() : end...\n");return 0;
}
  • func.c
#include <stdio.h>int* g_pointer;void func()
{*g_pointer = (int)"D.T.Software"; //注意,这里是出错的地方,g_pointer是指向0地址,但是在这里却对0地址赋值return;
}
  • 首先对上述程序编译并且运行:
  • gcc func.c test.c -o test.out
  • ./test.out
  • 毫无疑问,程序肯定会产生错误,如下图:
    在这里插入图片描述
  • 这是在意料之中的,毕竟在func.c程序中,我们对0地址进行写内容了。
  • 那么现在我们开始使用gdb来定位出错误,在开启gdb调试之前,需要在编译源程序的时候加上-g选项,并将程序的崩溃信息转储的core文件(这在【软件开发底层知识修炼】六 Binutils辅助工具之- addr2line与strip工具这篇文章中有讲解过)。
  • gcc -g test.c func.c -o test.out //重新编译加上调试信息
  • ulimit -c unlimited //让程序在崩溃时产生core文件
  • ./test.out //重新运行看看是否产生core文件
    在这里插入图片描述
  • 很明显核心已转出,生成了core文件----注意,这是GDB调试需要用的文件
  • 现在就是出现了段错误,我们需要使用GDB的断点调试来找出问题所在。那么我们上面介绍了软件断点调试,硬件断点调试,下面我们就分别使用软件断点调试与硬件断点调试找出我们程序中出现的问题。

4.1 GDB软件断点调试实际案例

注意:下面的调试示例可能过于繁复,其实可以一两步就能定位到bug所在,但是这里我做的比较多是想借此来学习一些GDB的一些调试手段。

  • 首先按照下图中的命令输入顺序在终端中输入:
    在这里插入图片描述
  • 其中start命令与上一篇文章我们使用过的run命令的区别是start后,程序已启动就立马停止,GDB会自动在程序开始出打上一个断点。而run命令执行后程序会直接跑起来
  • 然后我们使用命令:break test.c:37 // 这个命令在test.c的37行打断点
  • 使用命令:info breakpoints //查看我们的断点数量如下图所示:
    在这里插入图片描述
  • 可以看到有一个断点,是刚才我们再test.c程序中37行打的断点。
  • 输入continue命令继续执行程序,程序肯定会在37行停下来,如下图:
    在这里插入图片描述
  • 这很正常因为我们在test.c的37行打了断点。又因为37行是for循环的结尾处,所以此时才相当于执行了一次for循环但是还没完全循环一次,此时i=0。
    在这里插入图片描述
  • 想要单步执行,就继续输入next,则程序就会一步一步执行。我们输入了很多个next,发现这个for循环一直可以正常执行,所以这个for循环肯定是没有问题的。那么我们就不必在for循环内部执行了,可以直接将i设置为100,执行完for循环。
  • 输入命令set var i=100.然后输入两次next,就跳出了for循环
  • 现在已经确定for循环没有产生错误,那么段错误就是在for循环之后。for循环之后只有两个printf语句和一个func函数调用。现在我们怀疑是func函数内部出现了段错误。我们在func函数调用所对应的行(41行)打一个断点:tbreak test.c:41
  • 然后continue执行,执行到func函数时停下来了,然后使用jump test.c:45 ,程序直接正常退出:
    在这里插入图片描述
    在这里插入图片描述
  • 上述图中没有执行continue。实际需要在打完断点后要执行以下,然后再jump
  • 从上述结果可以知道除了func函数,其他地方都是没有问题的。所以问题应该就是出现在func函数中。
  • 上述是没有调用func函数,然后程序正常退出所以我们怀疑是func函数的问题。现在还可以这样,我们调用func函数但是不执行func函数体内的代码,而是直接强制func函数返回,看看会怎么样?如下动态图模式:
    在这里插入图片描述
  • 上述动态图只是想展示几个命令的用法~~~~注意学会使用。

4.2 GDB硬件断点调试实际案例

注意:下面的调试示例可能过于繁复,其实可以一两步就能定位到bug所在,但是这里我做的比较多是想借此来学习一些GDB的一些调试手段。

  • 硬件断点调试实际上是与软件断点调试的步骤是一样的,只不过使用的是hbreak命令而已。
  • 依次输入:
    • gdb test.out
    • start
  • 进入到调试模式,然后我们想要硬件断点调试,就得需要知道硬件我们的系统中有没有硬件断点可以使用。输入:show can-use-hw-watchpoints 查看本机是否有硬件断点可以使用。显示如下图:
    在这里插入图片描述
  • 很明显,我们有一个硬件断点可以使用。
  • 输入:hbreak func并查看当前断点个数看我们的断点是否打上了:
    在这里插入图片描述
  • 然后输入continue运行到断点处。
  • 然后我们可以查询func函数中的g_pointer的值是多少。发现它是0。也就是0地址。我们在func函数中对0地址进行赋值,肯定会产生段错误。我们改变g_pointer的值,让它指向一块可读写的堆空间,然后再执行程序,应该就不会有段错误了。如下图,正是我们的操作步骤:
    在这里插入图片描述
  • 至此,我们已经找到了导致段错误的原因。实际上是在软件断点调试中找到的大概出错范围是func函数,而在硬件断点调试中找到了具体的原因是g_pointer指向0地址,但是我们对它进行赋值。
  • 我们之所以这么大费周章的使用这么多方法来找出出错的原因,纯粹是想学习使用GDB 的更多的调试命令,你完全可以几个步骤就找到出错的原因。我们只是为了学习。

5 总结

我们还注意到了一个问题就是在整个调试过程中我们没有修改过一句代码,也没有重新编译程序。这样很方便的找到源代码中的问题所在。实在是非常的方便。

  • 学会使用软件断点调试
  • 学会使用硬件断点调试

本文章参考狄泰软件学院相关课程
想学习的可以加狄泰软件学院群,
群聊号码:199546072

学习探讨加个人(可以免费帮忙下载CSDN资源):
qq:1126137994
微信:liu1126137994

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/422927.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Informix IDS 11体系操持(918测验)认证指南,第 4 部门: 机能调优(1)

对 IBM Informix Dynamic Server (IDS) 和它的分比如子体系举行调优&#xff0c;以失掉最佳机能。在一个冗长的概述之后&#xff0c;本教程给出了一些关于怎样检查数据库做事器及其子体系的例子。本文是这个分 8 部门的 系列教程 的第 4 部门&#xff0c;这个教程可以帮手您筹办…

前端学习(220):伪元素选择器

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/ html4/strict.dtd"> <html><head><meta http-equiv"content-type" content"text/html; charsetutf-8"><title>CSS伪元素&l…

【软件开发底层知识修炼】十六 快速学习GDB调试三 使用GDB的数据断点监测变量是否改变

上一篇文章我们学习了如何使用GDB进行软件断点调试和硬件断点调试&#xff1a;【软件开发底层知识修炼】十五 快速学习GDB调试二 使用GDB进行断点调试本篇文章继续上一篇文章的学习&#xff0c;如何使用GDB的数据断点监测内存中的变量是否被改变 文章目录1 GDB的数据断点1.1 利…

AllTray-将办法最小化到琐细托盘

Toy Posted in AppsAllTray 是一个很有效的小办法&#xff0c;操纵它你可以将办法的窗口最小化到琐细托盘&#xff0c;从而腾出桌面空间以作它用。此办法主要为那些没有原生供给最小化到琐细托盘成效的办法而预备的。今朝&#xff0c;AllTray 可以在 GNOME、KDE、Xfce、Fluxbox…

【软件开发底层知识修炼】十七 快速学习GDB调试四 使用GDB进行函数调用栈的查看

上一篇文章学习了如何使用GDB数据断点进行内存监测&#xff1a;【软件开发底层知识修炼】十五 快速学习GDB调试三 使用GDB的数据断点监测变量是否改变本篇文章继续上一篇文章的学习&#xff1a;如何使用GDB进行函数调用栈的查看 文章目录1 backtrace和frame2 使用GDB进行函数调…

前端学习(221):字体属性

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/ html4/strict.dtd"> <html><head><meta http-equiv"content-type" content"text/html; charsetutf-8"><title>CSS字体属性…

前端学习(222):文本属性

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/ html4/strict.dtd"> <html><head><meta http-equiv"content-type" content"text/html; charsetutf-8"><title>CSS文本属性…

【软件开发底层知识修炼】十八 快速学习GDB调试五 使用GDB进行调试的一些小技巧

上一篇文章学习了如何使用GDB进行函数调用栈的查看&#xff1a;【软件开发底层知识修炼】十六 快速学习GDB调试四 使用GDB进行函数调用栈的查看本篇文章是GDB调试快速学习系列的最后一篇。将综合前几篇文章做一个小的总结以及介绍一些在调试中使用的小技巧 文章目录1 调试中的小…

MongoDB学习笔记(一) MongoDB介绍及安装

系列目录 MongoDB学习笔记(一) MongoDB介绍及安装MongoDB学习笔记(二) 通过samus驱动实现基本数据操作MongoDB学习笔记(三) 在MVC模式下通过Jqgrid表格操作MongoDB数据MongoDB学习笔记(四) 用MongoDB的文档结构描述数据关系MongoDB学习笔记(五) MongoDB文件存取操作MongoDB…

前端学习(224):iconfont矢量库

矢量库 一、如何下载iconfont图标。 在iconfont-阿里巴巴矢量图标库中有多种图标供你选择。比如我们选择其中的一个作为示例。 鼠标悬浮上后会出现三种选择&#xff1a; 1.添加入库&#xff1a;功能和淘宝中的购物…

如何转载别人的博客

前言 对于喜欢逛CSDN的人来说&#xff0c;看别人的博客确实能够对自己有不小的提高&#xff0c;有时候看到特别好的博客想转载下载&#xff0c;但是不能一个字一个字的敲了&#xff0c;这时候我们就想快速转载别人的博客&#xff0c;把别人的博客移到自己的空间里面&#xff0c…

【软件开发底层知识修炼】二十 深入理解可执行程序的结构

上一篇文章记录了GDB调试从入门到熟练掌握的学习全过程。点击链接查看&#xff1a;【软件开发底层知识修炼】十九 GDB调试从入门到熟练掌握超级详细实战教程学习目录 还记得在以前的学习Binutils工具的时候&#xff0c;学习了很多工具来查看可执行程序的结构&#xff0c;那个时…

前端学习(225):尺寸属性

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/ html4/strict.dtd"> <html><head><meta http-equiv"content-type" content"text/html; charsetutf-8"><title>CSS尺寸属性…

前端学习(226):定位使用

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/ html4/strict.dtd"> <html><head><meta http-equiv"content-type" content"text/html; charsetutf-8"><title>CSS定位<…

【数据结构与算法-java实现】三 Java数组类实现

上一篇文章学习了&#xff1a;最好、最坏、平均、均摊时间复杂度的计算与分析方法.本片文章学习数组这种结构。由于数组这种结构比较简单&#xff0c;本文直接简单介绍&#xff0c;然后给出两种实现数组类的Java代码:整形数组类与通用性的数组类 由于数组是相比于其他数据结构实…

解决VMware6.5 以上版本安装RHEL 5的自动安装的问题

解决VMware6.5 以上版本安装RHEL 5的自动安装的问题记得在学习 RHEL5的时候&#xff0c;教室里用的VMware5.5.3的版本&#xff0c;在教室里安装的时候是很正常的有步骤的那种&#xff0c;回到寝室后&#xff0c;用我的VMware6.5 安装的时候却发现&#xff0c;完全变成了自动安装…

【软件开发底层知识修炼】二十一 ABI-应用程序二进制接口一

前面学习了可执行程序的结构&#xff0c;点击链接查看上一篇文章&#xff1a;【软件开发底层知识修炼】二十 深入理解可执行程序的结构本篇文章开始新的篇章&#xff0c;学习应用程序的二进制接口-ABI。 文章目录1 什么是ABI&#xff08;Application Binary Interface&#xff…

【软件开发底层知识修炼】二十二 ABI-应用程序二进制接口 二

上一篇文章学习了ABI的相关内容&#xff0c;具体最后分析了不同ABI下结构体的对齐方式的不同。点击链接查看上一篇文章&#xff1a;【软件开发底层知识修炼】二十一 ABI-应用程序二进制接口一本篇文章继续学习ABI相关内容。是上一篇文章的补充&#xff0c;如果没有看过上一篇文…

asp.net中RegularExpressionValidator控件中正则表达式用法

验证数字&#xff1a; 只能输入1个数字 表达式 ^\d$ 描述 匹配一个数字 匹配的例子 0,1,2,3 不匹配的例子 只能输入n个数字 表达式 ^\d{n}$ 例如^\d{8}$ 描述 匹配8个数字 匹配的例子 12345678,22223334,12344321 不匹配的例子 只能输入至少n个数字 表达式 ^\d{n,}$ 例如^\d{8…

VS2017社区版30天到期无法使用的激活方法

VS2017社区版30天到期无法使用的激活方法VS2017社区版是免费的&#xff0c;但是第一次安装时&#xff0c;没有登录&#xff0c;导致只要30天的试用期&#xff0c;现在试用期结束&#xff0c;无法使用&#xff0c;本教程就是解决这个问题。我先在控制面板中将2017社区版软件卸载…