2.调试方法和策略
1)断点
很多平台提供了断点调试的功能,这种调试方法比较直观,所以很多开发
人员都过分依赖它。
断点的功能主要包括设置断点,单步执行,更改
PC
指针,运行到光标处,
查看及修改寄存器或者内存值(
watch window
,
memory window
),查看
堆栈,查看汇编代码。有的还可以设置地址断点,条件断点,这在内存越
界的调试的时候非常有用。
应该说,断点调试在开发调试流程中起着很大的作用,但是在断点调试
中也应该多想办法来提高调试的效率,特别是嵌入式系统中,找到一个
问题,编译下载可能是一件挺费时的事情,所以,一次下载要能够有计划
的同时调试多个问题。
另外,断点调试笔者认为主要针对问题已经有疑点了,对根本还未发现问题或者问题不清晰,建议用其它的调试方法,以提高效率。还有,在有些情况下,可能不允许打断点调试(可能会破坏时序)
2)trace工具
很多平台通过
PC
的串口实现了调试信息的输出,这种调试工具需要在代码中调用相应的接口打印调试信息,所有调试效率的高低就取决于你对程序流程的把握上,如果你在流程关键处能够合理的输出调试信息,会大大提高你的调试效率,还有,
trace
消息一般是可以方便得进行保存,比较利于让异地的合作方分析问题。当然,
trace
工具也有他的缺点,首先他不如单步调试直观,当问题范围已经比较小的时候,他的效率可能不及单步,其次则是个比较严重的问题,那就是当你
trace
消息比较多的时候,容易丢消息,所以
trace
工具的可靠性就大打折扣。
3)输出内存
有的平台支持断点调试,又可以将某块内存的内容输出到
PC
上,这时就可以利用该工具进行调试在断点不太允许,
trace
又变得很不可靠的条件下,可以利用一块静态缓冲区来作为
trace
缓冲,将非常重要的
trace
消息写到该缓冲中,然后在需要看
trace
的时候打断点,将内存内容也就是
trace
信息输出到
PC
上来进行分析
4)输出文件
有的平台支持将
flash
上的文件下载到
PC
上,此时可以利用这个特性来输出调试信息在断点不允许,
trace
不可靠,静态缓冲开不出的请况下,可以将
trace
消息写到文件中,然后通过相应的下载工具,将
trace
消息写入的文件下载到
pc
上,进行分析
5)调试策略
a.
重现
bug
b.
分析现象,找出
bug
出现的条件(每次必现或者是一定条件下出现),尽可能地推测
及估计错误产生的原因,可能的位置
c.
仔细地检查相关的代码,很多错误都可以从代码上直接看出来
d.
如果无法定位到问题,则采用一步步缩小范围的策略,将相关的代码或者程序一步步分离开来,简化程序和程序运行的环境及条件,一步步逼近疑点
e.
结合各种调试手段分析问题
6
)一些常见
bug
的分析(待补充)
a.
程序跑飞的可能情况:堆栈溢出;非法地址操作;某些变量被不正常改写;有些平台的全局变量在声明时赋值就是全局变量,对这些变量重新赋值也会跑飞
案例
6
:
移植程序,移植接口疏忽大意,导致相互嵌套,如
A
中调用了
B
,
B
中调用了
C
,
C
在某些情况下又调用到了
A
,且没有终止嵌套的条件,结果导致堆栈溢出,程序跑飞
案例
7
:
测试代码
for(i=0;i<buflen;i++)
{
sprintf(TestBuf,buf,"%d");
}
其中由于
buf
里面的数据是以
16
进制存的,而
sprintf
将其以
10
进制存成字符串,因此可能
buf
一个字节写到
TestBuf
中就变成了两个字节,导致了缓冲溢出
b.
内存泄漏的调试
a.
如果有监测工具,则利用调试工具,在加上必要的测试代码
b.
如果没有监测工具,自己书写一套内存分配监测的接口,调试的时候打开接口,运行是观察内存分配的情况,分析是否有泄漏出现
3.其它
1)
双方或者多方合作的项目,由于你根本无法预测对方的软件、代码可靠性,集成以后的环境又比较复杂,所以必须做好自己的单元测试和模块测试,有可能的话,你可以以一个最简单的方式模拟他方的行为或者程序,脱离他方的代码进行单独的调试,这在集成以后出现问题查起来的时候会对你相当有帮助