嵌入式开发中难免出现这样或那样的问题, 因而软件的调试手段会直接影响到开发的进度, 本节将总结一些常用的调试方法:
(1) 联机调试
对于在操作系统上(windows 或Linux)运行的内核态程序可以通过windbg或kgdb进行调试, 对于规模小一些的开发板也可以用JTAG调试器进行调试。
该方法适用于软件开发初期的流程调试, 但缺点如下:
a. 对于小概率的Bug, 有时很难联机跟踪
b. 某些硬件功能与时序相关, 联机和导致bug无法复现或硬件超时
c. 反复执行一段时间后才出现的问题, 虽然可以在错误分支设断点, 但可能是积累性(即最终错误时前面错误积累导致的)
d. 系统死机或失灵
(2) 基于日志的调试
设计分级的日志输出机制,输出的信息多少可以通过开关控制。 调试时可打开相应输出开关, 根据出错点的log向前分析。
该方法要求设计好日志输出格式,与控制标志。 最好将该机制在软件设计阶段就确定下来。对于一些较小型的设备可以通过网络, 串口将log输出到上位机。
对于一些对代码szie有限制的嵌入式设备,因为空间限制需要对输出信息进行编码以减少size.
该方法的缺点如下:
a. 小型嵌入式系统由于代码size限制,输出信息可能较少,只能启到辅助作用,这时需要结合其它方法调试。
b. 日志设计不足, 无法定位问题
c. 突然死机等问题, 日志输出不完整
(3) 基于日志的调试升级方法
基于日志的调试的一个变种是将一部分重要日志存到一片内存环形缓冲区中,出错时可查看该内存区域。 该方法适用于叫底层的体系结构代码和对时序要求较高的嵌入式模块。log输出甚至可以是一个我几个led灯。
基于日志调试的另一个变种就是Verify,在程序中建立检查点, Debug版本可以开启该功能. 一旦检查点未通过则dump 出系统调用与状态信息.
Verify的内容可以是软件条件,或硬件状态, 还可以是堆栈的检查等较底层功能。
基于操作系统的项目还可以通过系统层的lon或信息来进行调试, 如windows 的ETW, Linux下其他模块的log输出。
(4)辅助工具调试
如调试协议相关软件可以通过抓包软硬件, 如tcp/ip包, usb协议包等。
调试硬件时序可采用示波器甚至逻辑分析仪。
调试内存泄露,可采用分析软件。
(5) dump 信息分析
对于windows或Linux下的一些严重错误为产生系统dump文件, 这时需要对dump进行分析。 对于几层的驱动程序, 也可以在出错点让操作系统生成dump这样有利于全局调试。
(6) 对比分析法
某些bug是由于一些case我们未处理好而造成的,但有时由于一些局限性,在自身的测试平台上未能发现这些问题; 且通过其他方法未能发现问题, 这时 可以对比自身平台与能复现的平台的差异性(软件或硬件), 来推断可能的原因。
(6) 代码审查
代码审查也是一种调试方法,自己的代码有时自己难以发现问题, 可以请他人或小组讨论的形式进行(也可使用自动代码检查工具), 2类问题较容易通过该方法发现:
a.低级错误
b. 未处理的异常case
(7) 猜测验证法
对于原因不易定位的问题, 可以通过提出一些怀疑点,并每次修改一个怀疑点;逐一排查的方法。 这种方法在万不得已时可以使用, 带最终最好找到根本原因。
下面是一些需要学习的调试相关的技能
(1) Arch相关的调试, 如硬件断点,cpu branch记录等。 为此需要了解CPU级的调试机制(可通过Cpu spec)学习
(2) 理解调试器的的基本工作原理
(3) 调试器的使用如gdb, windbg等
(4) Dump文件的分析方法
最后推荐基本关于软件调试的书籍 <<软件调试>> (偏windows) <<软件调试修炼之道>>(思考方法) 《DebugHacks中文版》(偏Linux)