嵌入式系统coredump设计

阴沟翻船,马失前蹄,说明凡事皆有可能。自然,程序设计的再好,也会有crash的时候。开发期还还说,正式交付的系统crash自然更是难以承受的。无论何时,死一次就够了,得有方法查个水落石出。

几年前哥去广州的一家民企呆过些日子。刚到那,就碰上系统毫无线索的crash。咋办?哥想静下心来,花点时间做个工具去定位,但无奈硬件出生的领导天天赶着大家守在机房。唉,无知啊,天天守在机房,面对crash,哥想到的只有我儿子常常念的诗--来如春梦不多时,去如朝霞无觅处。嗯,crash,哥只能数数又crash了几次。

再后来,哥被请去了另外家公司,挂了个闲职,要求就一个,帮忙解决嵌入式系统开发碰到的,解决不了的问题。在那还是蛮幸福,因为哥那些日子确实需要时间,大把大把时间,来照顾家人。

这当中,就碰到三个最典型的问题:memory leak, system crash, system halt。内存泄漏以后再讲,今天只说crash,当然,halt跟crash的解决方法有很大重叠,明天有空就简单的说一说。

首先,简单定义下讨论对象:嵌入式操作系统,使用ucos,vxworks,nucleus等操作系统。Linux自带coredump功能,不在讨论范围。

接下来,普及下CPU的寄存器知识。以ARM为例,处理器存在几个不同的寄存器组,对应不同的模式:用户模式,中断模式,数据访问终止模式,未定义指令模式undef等。系统crash,除去硬件原因(比如电不足等),都是先触发异常:数据异常,取指异常,或者未定义异常。未定义异常一般来说是没有的,除非故意改掉指令的opcode,比如野指针,咱不谈它,那太难了!

有兴趣了解更多,可以读一读ARM的文档:
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0344f/Beiibjca.html

当Data aboat或是Prefetch abort出现后,CPU即切换到数据访问终止模式。我们要做的,就是抢在系统开始处理前,把用户寄存器信息保存下来。以及abort模式下LR寄存器内容。接下来,把控制权还给系统的正常流程。当然也不是绝对,哥碰到的系统,总是可以在异常里挂coredump处理函数。万一系统没给你留这个钩子,那就麻烦些,需要修改cpsr到用户模式,调用coredump处理函数;完成后,再返回abort模式,将处理权交还系统。当然,你不想交权也可以,coredump完了,就直接复位CPU。反正你该收集的信息都收集了,系统接下来的异常处理也没什么价值。

Coredump处理函数做的事,也很简单,首先确定当前运行的task和tcb。操作系统一定会提供这个全局变量,或是获取接口。然后,就是把堆栈信息保存起来。很多时候,堆栈会很大,很难保存所有数据。这时,就有几个策略:遍历堆栈,找出所有函数调用;提取栈顶的一段数据。其中原理等下再讲。

系统复位了,刚刚存的数据还在么?当然在,我们用SRAM来保存这些数据。CPU复位但不掉电的情况下,SRAM数据会完整的保留着。不过,系统要带SRAM。当然,没SRAM也可以,只不过做起来有点难度,需要flash驱动做些特别支持。数据需要先保存到内存中,然后在coredump处理函数中写入flash。写flash需要时间,因此要记得喂狗和写flash两不误;还有就是flash一般不能是文件系统,应该是直接的地址映射。flash的驱动必须配这种特俗的写操作。

然后,系统重新启动运行。这时候,我们先赶紧把刚才存在SRAM或是flash的数据复制出来,写入到coredump文件,免得夜长梦多。这个过程就很简单了!

接下来,解释几个技术问题。

怎么遍历堆栈,找到所有函数调用?
很简单。用readelf,objdump一类工具打开编译出来的软件包,你就能发现,函数地址总是在某个区间内。如果是动态加载的系统,则会提供代码段的区间范围。提前找到这个范围就好了,硬编码在你的程序里,且不需要精确,多一点没关系,毕竟相对于32位系统的地址空间来说,这段地址占的比例总是可以忽略不计,误抓取的信息也就非常有限。记得,宁可错杀一千一万!

为什么要保存栈顶数据?
一般来说,最后的一些列操作有更大的嫌疑。从分析角度来说,较远位置的错误,堆栈数据分析的难度非常大。其实,就经验来看,只要能找到函数调用的层次关系,再加上代码走读,基本上都能确定故障原因。堆栈数据分析,也就是不得已才做的,尤其是面对编译使用了优化选项的故障。

如何使用coredump文件?
coredump文件包含三个内容:寄存器信息,函数调用信息,堆栈数据。函数调用信息可以在线翻译,只要利用cshell里的符号表就可以直接查询那些地址,并翻译成可读的函数名。当然,最好的办法是离线处理。这里需要明确,编译时必须带-g参数用以产生addr2line需要的符号表内容。正式发布的软件包可以额外使用strip方法去掉符号表,但需要同时保存带符号表的原始编译软件包和发布软件包。利用addr2line对coredump保存的疑似地址检查,可以梳理出完整的系统调用层次。记得用Perl,或是Python等写个脚本来做这个!

很遗憾,哥找了半天,也没找到以前做的那段搞寄存器的汇编代码段,也没那段异常处理的函数代码,更也没找打coredump分析的perl脚本。早知道就该在给上家做这个的时候,偷偷复制一份供日后参考的。当然,也没什么,在弄清楚具体系统的工作原理后,相关实现估计只要一两个工作日来完成,只是没SRAM的方式,蛮复杂的,需要时间也多点,尤其测试会麻烦很多。

时间: 2024-10-10 10:12:02

嵌入式系统coredump设计的相关文章

<转>Nios II 嵌入式系统硬件设计(一)

原帖地址:http://bbs.ednchina.com/BLOG_ARTICLE_182065.HTM SDRAM Controller参数设置 SOPC通过SDRAM controller与板上的SDRAM进行通信,在SOPC中加入SDRAM控制器,弹出如下对话框,里面具体参数说明如下. 一.Memory Profile参数设置   Presets:在该下拉菜单中预设了一些常用的SDRAM的参数,选定某个型号的SDRAM后,会自动修改相应的设置.预设的SDRAM信号有: ■ Micron M

基于ARM9的指纹识别系统的设计和实现

生物识别技术是利用人体固有的生理特性(如指纹.脸象.红膜等)和行为特征(如笔迹.声音.步态等)来进行个人身份的鉴定. 生物识别技术比传统的身份鉴定方法更具安全.保密和方便性.生物特征识别技术具有不易遗忘.防伪性能好.不易伪造或被盗.随身"携带"和随时随地可用等优点. 生物识别的工作原理是利用生物识别设备对生物特征进行取样,提取其唯一的特征并将其转化成数字代码,并进一步将这些代码组成特征模板,人们同识别设备交互进行身份认证时,识别设备获取其特征并与数据库中的特征模板进行比对,以确定是否匹

嵌入式系统硬件组成

嵌入式系统的硬件主要包括:嵌入式处理芯片.嵌入式系统存储器.I/O接口及常用的I/O设备.典型ARM处理芯片以及嵌入式互连通信接口. 嵌入式最小硬件系统有: 1.电源电路 2.时钟电路 3.复位电路 4.JTAG测试接口 典型的嵌入式系统硬件有嵌入式最小系统.前向通道.后向通道.人机交互通到以及相互互联通信通道等组成. 嵌入式系统的设计步骤 嵌入式系统设计步骤 1. 系统需求分析:确定设计任务和设计目标,并提炼出设计规格说明书,作为正式设计指导和验收的标准.系统的需求一般分功能性需求和非功能性需

嵌入式系统学习开发指导

本文转自迅为开发板论坛:http://www.topeetboard.com 注:本文章部分参考摘录自:<嵌入式系统Linux内核开发实战指南(ARM平台)> 初级阶段:熟悉基本开发流程和方法阶段. 这一阶段需要掌握的知识和技能包括:1.)嵌入式系统硬件设计流程:2.)嵌入式系统硬件调试:3.)嵌入式系统软件下载.调试.固化:4.)Bootloader编译.移植.裁剪.调试.固化:5.)Linux内核交叉编译环境创建:6.)Linux内核编译:7.)Linux内核下载.调试.固化. 这一阶段需

SoC嵌入式软件架构设计之七:嵌入式系统固件的系统区文件系统设计

嵌入式固件的系统区(system disk,SD)包括操作系统.驱动.中间件.应用和字库.UI资源等文件,本文讲述SD区的文件系统设计.文件系统最主要的目标是为了实现单个文件的定位和读写.因为一般代码都是不可自修改的,即量产之后不会有写操作,嵌入式系统的SD文件系统就是为了能够简单.高效地定位某个文件和读取文件中的数据.设计原则和要点有以下几方面: 1. 逻辑连续存储单个文件,以扇区对齐. SD区的单个代码和资源文件一般都不大,所以不必要像fat32文件系统那样用fat表把文件簇串起来,直接逻辑

如何在裸机下设计一个嵌入式系统架构?

如何在裸机下设计一个嵌入式系统架构? 如何不使用操作系统的情况下设计一个嵌入式系统的架构呢?比如串口数据如何接受,串口数据协议在什么地方解析,SPI总线的数据如何有效的接收?等等问题.如何设计,才能尽量保证各个模块的效率呢?自己有一些设计,想一起讨论下.比如串口的数据先在中断程序中放入一个大数组中,然后在主程序中解析接收到的数据,等等--还有哪些技巧呢? 关注者 157 被浏览 7,457 关注问题写回答 ?添加评论 ?分享 ?邀请回答?举报 ? 收起 8 个回答 默认排序? Tony Ho 嵌

嵌入式系统编程和调试技巧

嵌入式系统的开发,软件的运行稳定可靠是非常重要的.在芯片中,软件是没有质量的,但软件的质量可以决定一颗芯片的成败.芯片设计中,性能能否满足设计要求,除了硬件设计.软硬件配合的设计技巧,对于软件来说,编程的一些技术和技巧同样重要. 本文讲述我在芯片固件开发过程中使用的一些编程调试技巧.针对在嵌入式系统开发中常见的问题,如实时系统下的同步问题,动态内存分配的内存泄漏问题,如何在编程阶段预防BUG出现,调试阶段如何及时发现问题和定位问题.总结下经验,目的是开发一个稳定运行的固件,提高开发效率,提高运行

智能家居系统-软件设计

1 智能家居远程控制系统的软件实现 1.1 基于uC/OS-II的中央控制器的软件设计 1.1.1 uC/OS-II系统移植 本设计使用uC/OS-II操作系统,uC/OS-II是一个源码公开.可移植.可固化.可剪裁和抢占式的实时多任务操作系统,uC/OS-II的大部分源码是用标准ANSI C编写,并且编程规范,可读性很高,内核中只有少量的与硬件相关的代码使用汇编语言编写,总共200余行,移植非常方便[37].uC/OS-II软件体系结构如图5-1所示.移植工作主要包括以下几个方面的内容: 1)

[转]给嵌入式系统工程师的十个建议

从更熟悉以开放源码软体来开发应用程式(Apps),产业专家鼓励嵌入式工程师走出舒适圈.学习新技能,才能与时俱进.回顾1980年代的嵌入式 领域,当时的工程师主要是设计混合讯号电路.连接微控制器.撰写低阶编码.从外面拿回产品原型…只要一个工程师就能做好以上所有事情.但是现在,嵌入式系 统变得更大.更复杂,一台装置可能有数百万行软体程式码:嵌入式技术也被区分为硬体开发.韧体开发与软体开发. 在很多大公司仍然是如此,但趋势似乎又有回头的迹象:有越来越多业者开始整合工程师的角色,寻找既熟悉软体也熟悉硬体