400行程序写一个实时操作系统(八):(必看!)使用gdb调试错误的程序

news2024/11/24 17:37:54

上一篇笔者讲完了内存管理算法的完整实现,不过差点忘了,直接上这一部分是不是有点不友好,要知道笔者当初写内存算法可是调试得死去活来,奇奇怪怪的问题不断出现。

就比如笔者当初写了一个内存池算法,结果奇葩的事情发生了。如果内存数组的命名不恰当(例如mempool),而且内存的大小定义为800,如果你访问内存后八个字节,程序就会报segmentfault,但是改成mempool1,程序又能跑了,而且这并不能稳定复现,换一个编译器bug就消失了。这当时直接把笔者整懵逼了,以前看到有人说程序删除掉注释就能跑了,笔者内心是一点也不相信,但是自从自己经历了奇怪的bug,现在写程序命名都要小心翼翼了。

为了让读者面对bug时不至于茫然不知所措,笔者觉得有必要介绍一些调试方法。(不仅仅是gdb,也包括keil,由于keil偏图形化,不需要过多介绍,所以笔者会重点讲gdb命令)

gdb调试

本小节笔者会介绍各种gdb的小命令,例如b, s, p, n, list, x/10x,disassemble,bt 等等命令。也介绍栈回溯等技术。

gdb是一个非常强大的工具,但是笔者发现网上没有什么教程讲使用gdb调试嵌入式程序,而且发现很多人对调试技术并不重视,所以笔者觉得有必要讲一讲gdb的使用。

让我们在实战中学习gdb的使用!

笔者修改了内存管理算法,使它成为了一个错误的工程,现在该如何调试它呢?

在HardFault_Handler函数内部打上断点

HardFault_Handler函数是一个非常重要的函数,当我们的单片机出现各种奇怪的问题时,此时单片机就会触发这个中断,然后我们会发现程序一直在这里转圈圈,这其实是官方为了帮助我们debug而设置的一个功能:(断点最好打在while(1)上面)

b命令

b命令的作用就是打上断点,在clion下,读者可以手动点击87行打上断点,也可以使用b 87命令打上断点

添加图片注释,不超过 140 字(可选)

r命令

r命令是运行命令,不过在clion的gdb里面,点击右边那个小虫子,程序就自动运行到断点处了,如果是在linux环境下使用gdb是需要使用r命令运行程序的,但是在clion下是不用的。

添加图片注释,不超过 140 字(可选)

调试错误的内存管理算法

当我们运行错误的内存管理算法的程序时,会发现程序跑进了HardFault_Handler,那么,是哪里导致了问题呢?

寻找案发现场

栈回溯

“ ⽬前的主流CPU架构都是⽤栈来进⾏函数调⽤的,栈上记录了函 数的返回地址,因此通过递归式寻找放在栈上的函数返回地址,便可 以追溯出当前线程的函数调⽤序列,这便是栈回溯(stack backtrace) 的基本原理。通过栈回溯产⽣的函数调⽤信息称为call stack(函数调 ⽤栈)。 栈回溯是记录和探索程序执⾏踪迹的极佳⽅法,使⽤这种⽅法, 可以快速了解程序的运⾏轨迹,看其“从哪⾥来,向哪⾥去”。”

以上解释来自张银奎老师的《软件调试》。

笔者简单解释,就是看进入HardFault_Handler之前是哪些函数在不断嵌套调用。

bt命令

添加图片注释,不超过 140 字(可选)

(话说笔者是不是应该把Sparrow程序全部删除比较好,不过考虑到实际情况,还是先保留,因为笔者将会用这些多余的程序引出调试的原则)

我们现在发现了,在进入HardFault_Handler之前,程序一路嵌套调用,最后在heap_init处发生了错误。

现在该引出调试的两大原则了:问题简化原则和问题追踪原则。

问题简化原则

我们现在已经知道了,是heap_init导致了错误,也就是说,很有可能是我们的内存管理算法出现了问题。为了验证我们的猜想,我们需要单独debug内存管理算法部分:

添加图片注释,不超过 140 字(可选)

在main函数中,笔者删除了sparrow的其他程序,单独debug内存管理算法,让我们看看是不是它引起了错误:

添加图片注释,不超过 140 字(可选)

问题依旧存在!这说明确实是内存管理算法有问题。

案发现场的确认

为了搞清楚是那一行命令导致的问题,我们需要查看跳转到HardFault_Handler前程序在执行那一行程序,为此,我们可以借助堆栈指针。

arm cm3架构的单片机采用的是双堆栈,也就是有两个stack指针(psp和msp),分别在不同场合使用。

我们需要查看寄存器R14(LR)的值。如果R14(LR) = 0xFFFFFFE9,继续查看MSP(主堆栈指针)的值,如果R14(LR) = 0xFFFFFFFD,继续查看PSP(进程栈指针)的值。

info registers 命令

使用该命令,可以帮助我们快速查看arm所有寄存器的值:

添加图片注释,不超过 140 字(可选)

x/10x $msp命令

笔者的lr是0xFFFFFFE9,所以需要查看msp后面的的内存。

x/10x $msp命令会从$msp寄存器的值开始,检查并显示接下来10个内存单元的内容,每个单元的值以十六进制格式显示:

添加图片注释,不超过 140 字(可选)

看着这些十六进制的数字不要慌,想一想我们的程序地址一般是从哪里开头的?一般不是在0x08后面吗?所以我们只需要查看0x080开头的地址的内容即可。

list命令

0x08000281处的程序:

我们已经知道了错误是在heap_init内存发生的,因此我们还需要进一步查看。

添加图片注释,不超过 140 字(可选)

0x08000218处:

添加图片注释,不超过 140 字(可选)

disassemble 命令

如果读者懂汇编语言,也可以查看汇编程序:

添加图片注释,不超过 140 字(可选)

观察程序执行发现具体问题

问题追踪原则

s和n命令

到现在,我们找到了案发现场,但是如果案发现场也仅仅是受害者呢?比如一个函数的错误执行导致修改了某个指针,案发现场的程序对这个指针进行了解引用,这个时候该怎么办呢?

此时我们需要重新梳理程序的执行,遵守问题追踪原则,使用s和n命令一步步执行程序,找出问题。

s命令:

一行行执行程序,遇到函数会进入函数内部继续一行行执行命令。

n命令:

一行行执行程序,但是遇到函数不会进入函数内部,而是执行完这一行后转到下一行。

使用s命令,我们来到了malloc内部:

添加图片注释,不超过 140 字(可选)

继续使用s命令,我们进入到了heap_init函数内部:

其实到这里读者应该都看得出了,笔者并没有给start_heap传递allheap这片内存的地址,导致程序出错了。

添加图片注释,不超过 140 字(可选)

修改了之后程序就能继续跑了:

添加图片注释,不超过 140 字(可选)

keil调试

使用keil调试是一样的,keil只要点击这个放大镜即可进入调试。

keil的右边会自动显示各个寄存器的值:(笔者很久没用keil了,没找到有bug的工程。随便打开的一个工程,凑合着看吧(><))

添加图片注释,不超过 140 字(可选)

调试方法是一样的:我们需要查看寄存器R14(LR)的值。如果R14(LR) = 0xFFFFFFE9,继续查看MSP(主堆栈指针)的值,如果R14(LR) = 0xFFFFFFFD,继续查看PSP(进程栈指针)的值。

假设此时LR是0xFFFFFFE9,我们把0x200004F4输入右下角的Memory1这里:

添加图片注释,不超过 140 字(可选)

现在我们已经获得了出错程序的地址,我们打开这个窗口,右键然后点击Show Disassembly at Address:

添加图片注释,不超过 140 字(可选)

输入地址:

添加图片注释,不超过 140 字(可选)

现在我们就可以找到出错的程序现场!

总结

笔者介绍了如何使用gdb进行嵌入式调试,并且使用错误的内存管理算法作为案例,带领读者一点点找出问题所在,希望读者能够学有所得!

本章的程序地址:skaiui2/SKRTOS_sparrow at memory (github.com)

读者可以下载后跟着文章进行调试。地址中的heapmem.c和heapmem.h是笔者进行了简单的修改后的内存管理算法。它可以作为一个库被广泛使用在嵌入式单片机程序中,并且比通用的c语言malloc效率更高,执行时间也相对固定,能够提高程序的性能。

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

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

相关文章

大模型之三十二-语音合成TTS(coqui) 之二 fine-tune

在 大模型之三十-语音合成TTS(coqui)[shichaog CSDN]中提到了xttsv2的fine-tune。 数据情况&#xff1a; 我是从bilibili up主小Lin说提取了一些视频&#xff0c;然后进行了重新的fine-tune。 训练结果 如下图所示&#xff0c;上面波形幅度较大的是xttsv2原始模型的结果&am…

u盘被写保护怎么解除?u盘写保护怎么去掉?

我们平时在使用U盘的过程中&#xff0c;可能会遇到U盘无法写入文件、删除数据或是格式化的情况。同时还可能收到提示“改磁盘已写保护”。U盘被写保护可能是有意的设置&#xff0c;也可能是无疑的操作。那么U盘被写保护了该怎么解除呢&#xff1f;本期内容&#xff0c;我们将介…

最新版 Winows下如何安装Redis?

最新版 Winows下如何安装Redis&#xff1f; 一、Redis介绍 Redis是一个广泛使用的开源非关系型数据库&#xff0c;它在现代软件开发中扮演着重要角色。**作为一个基于内存的数据库&#xff0c;Redis的底层代码是用ANSI C编写的&#xff0c;这使得它在性能上非常出色。**Redis…

【AIF-C01认证】亚马逊云科技生成式 AI 认证正式上线啦

文章目录 一、AIF-C01简介二、考试概览三、考试知识点3.1 AI 和 ML 基础知识3.2 生成式人工智能基础3.3 基础模型的应用3.4 负责任 AI 准则3.5 AI 解决方案的安全性、合规性和监管 四、备考课程4.1 「备考训练营」 在线直播课4.2 「SkillBuilder」学习课程 五、常见问题六、参考…

前端开发攻略---使用ocr识别图片进行文字提取功能

1、引入资源 通过链接引用 <script src"https://cdn.bootcdn.net/ajax/libs/tesseract.js/5.1.0/tesseract.min.js"></script> npm或其他方式下载 npm i tesseract 2、示例 <!DOCTYPE html> <html lang"en"><head><meta…

从纸质到云端:3C产品说明书的电子化进程与影响

在科技日新月异的今天&#xff0c;3C产品&#xff08;计算机类、通信类和消费类电子产品&#xff09;作为现代生活不可或缺的一部分&#xff0c;其说明书的演变也见证了技术进步的足迹。从最初的纸质文档到如今的电子说明书&#xff0c;这一转变不仅仅是物理形态的转换&#xf…

UE5 圆周运动、贝塞尔曲线运动、贝塞尔曲线点

圆周运动 贝塞尔曲线路径运动 蓝图函数库创建贝塞尔曲线点 // Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "CoreMinimal.h" #include "Kismet/BlueprintFunctionLibrary.h" #include "MyBlu…

文件IO知识梳理及练习

1> 使用fread和fwrite完成两个文件的拷贝&#xff0c;要求源文件和目标文件由外界输入 #include <myhead.h> typedef struct sockaddr_in addr_in_t; typedef struct sockaddr addr_t; typedef struct sockaddr_un addr_un_t; int main(int argc, const char *argv[])…

使用OpenCV实现基于FisherFaces的人脸识别

引言 随着人工智能技术的发展&#xff0c;人脸识别已经成为日常生活中不可或缺的一部分。在众多的人脸识别算法中&#xff0c;FisherFaces 方法因其简单易用且具有良好的识别效果而备受青睐。本文将详细介绍如何使用Python和OpenCV库实现基于FisherFaces的人脸识别系统&#x…

Flink On kubernetes

Apache Flink 是一个分布式流处理引擎&#xff0c;它提供了丰富且易用的API来处理有状态的流处理应用&#xff0c;并且在支持容错的前提下&#xff0c;高效、大规模的运行此类应用。通过支持事件时间&#xff08;event-time&#xff09;、计算状态&#xff08;state&#xff09…

知道ip地址怎么看网络地址

在计算机网络的世界里&#xff0c;IP地址是设备之间通信的基础。然而&#xff0c;仅仅知道一个设备的IP地址并不足以完全理解它在网络中的位置和作用。网络地址&#xff0c;作为IP地址的一个重要组成部分&#xff0c;为我们提供了关于设备所属网络的更多信息。本文将深入探讨如…

从零开始搭建:基于在线教育系统源码的线上网校开发详解

本文将通过详细的技术分析&#xff0c;帮助你了解如何基于在线教育系统源码搭建线上网校&#xff0c;从而帮助你更好地构建稳定且高效的线上教育平台。 一、为什么选择在线教育系统源码&#xff1f; 在搭建线上网校时&#xff0c;使用成熟的在线教育系统源码是一个快速且高效…

【LwIP源码学习3】TCP协议栈分析——数据接收流程

前言 本文介绍代码在lwip的tcp_in.c文件中&#xff0c;主要介绍TCP协议栈中数据的接收流程。 正文 1、一个正常的TCP数据&#xff0c;首先会传入到 tcp_input(struct pbuf *p, struct netif *inp)函数&#xff0c;其中指针p指向传入的数据流。 2、从数据流中获取TCP头部 …

mysql的一点理解

1、mysql B树 B树非叶子结点中的key存储的是页的用户记录中最小/最大的主键值&#xff0c;之前不知道非叶子结点中的key存的是最小/最大&#xff0c;以为随便存的一个。 2、mysql范围查询 如果对多个列都进行范围查询&#xff0c;只有对索引最左边的那个列索引才生效。 比如…

字符串和字符数组

1.字符串和\0 c语言中有字符类型&#xff0c;但没有字符串类型&#xff0c;c语言中字符串就是由双引号引起来的一串字符&#xff0c;比如&#xff1a;“abcdef” 字符串常量在末尾隐藏了一个’\0’的转义字符&#xff0c;\0’是作为字符串的结束标志存在的 库函数printf与str…

隔离器“芯”实力,华普微荣获“2024年度硬核信号链芯片奖”

10月14日&#xff0c;由深圳市芯师爷科技有限公司和慕尼黑华南电子展携手主办&#xff0c;深圳市半导体行业协会支持的“第六届硬核芯生态大会暨颁奖典礼”&#xff0c;已于深圳国际会展中心&#xff08;宝安新馆&#xff09;成功举办。值此盛会之际&#xff0c;华普微受邀参会…

热成像人像算法呈现方式!

一、热红外成像技术 热红外成像技术利用物体发出的红外辐射进行成像&#xff0c;这种辐射与物体的温度有关。因此&#xff0c;热红外成像可以不受光照条件的影响&#xff0c;且在图像中&#xff0c;人体由于温度较高&#xff0c;通常会比背景显得更亮。 二、图像处理算法 阈…

Python爬虫必备的8大技巧,学习爬虫技巧必看!

想要快速学习爬虫&#xff0c;最值得学习的语言一定是Python&#xff0c;Python应用场景比较多&#xff0c;比如&#xff1a;Web快速开发、爬虫、自动化运维等等&#xff0c;可以做简单网站、自动发帖脚本、收发邮件脚本、简单验证码识别脚本。 爬虫在开发过程中也有很多复用的…

如何有效进行主机加固?深信达MCK提供答案

在数字化时代&#xff0c;企业面临的网络安全威胁日益严峻&#xff0c;尤其是勒索病毒等恶意软件的攻击&#xff0c;给企业带来了巨大的挑战。为了有效应对这些威胁&#xff0c;企业需要采取全面的网络安全防护措施&#xff0c;其中主机加固成为了关键的一环。深信达的MCK主机加…

【Arthas】【持续更新】三分钟掌握arthas常用查询命令,入门到实战

Arthas 一、下载和启动1、官网地址2、下载3、启动4、退出 二、常用命令1、dashboard&#xff1a;当前系统的实时数据面板2、profiler&#xff1a;监控进程的cpu\内存使用情况。细致到某个方法采集与生成报告查看 profiling 状态查看 profiler 自身的内存占用 3、thread&#xf…