首页 > 代码库 > QT程序出现Bus Error问题的调试
QT程序出现Bus Error问题的调试
原文
1.文档目的
本文档目的在于探究部分QT程序在嵌入式板子上出现BusError问题的调试及解决方法;
以数码相框程序出现的BusError为例;
2.原因分析
2.1产生BusError的可能原因:
BusError即总线错误,BusError通常都是因为非对齐访问造成的。CPU在设计上为了性能上的考虑,要求待访问,操作的数据地址都要对齐。如果发现没有对齐的访问,就会向当前进程发出SIGBUS信号,使程序崩溃。RISC包括MIPS都是这种类型的芯片。而X86架构就没有这种对齐要求。所以代码在嵌入式环境下有总线错误而在X86下面可能就没有问题,当然这是有性能的代价。
BusError的产生除了上边提到的访问数据地址对齐问题之外,还可能是因为一下原因:
1机器物理问题或者访问无效物理地址,但这种情况非常少见。
2Linux平台上执行malloc(),如果没有足够的RAM,Linux不是让malloc()失败返回,
而是向当前进程分发SIGBUS信号。
3某些架构上访问数据时有对齐的要求,比如只能从4字节边界上读取一个4字节的数据类型。IA-32架构没有硬性要求对齐,尽管未对齐的访问降低执行效率。另外一些架构,比如SPARC、m68k,要求对齐访问,否则向当前进程分发SIGBUS信号。
SIGBUS与SIGSEGV(产生段错误Segmentfault)信号一样,可以正常捕获。SIGBUS的缺省行为是终止当前进程并产生coredump。
SIGBUS与SIGSEGV信号的一般区别如下:
1SIGBUS(Buserror)意味着指针所对应的地址是有效地址,但总线不能正常使用该
指针。通常是未对齐的数据访问所致。
2SIGSEGV(Segmentfault)意味着指针所对应的地址是无效地址,没有物理内存对
应该地址。
2.2数码相框产生BusError的调试:
经过查找资料:嵌入式板子上如果程序初始化运行无任何调试数据输出即马上出现BusError,则很大原因是由于交叉编译环境中的库和文件系统里库的不一致,或者编译的参数有问题之类的原因导致的非对齐访问数据地址。重新配置好编译参数及更新文件系统内的库一般都能解决问题;
而数码相框出现的BusError问题并不是上边提到的情况,而是当板上数码相框程序在运行后,自动播放图片并有特效切换时不定时间出现BusError,经过打印调试信息,并未定位到BusError出现的确定位置,但是分析调试信息,可定位到两个位置,其一为在定时器QTimer或者动画类QtimeLine触发的特效实现槽函数运行结束时出现,其运行结束后会调用系统的画图事件函数,然后数码相框在画图事件中实现图片的显示;另一个位置为在画图事件中实现填充区域的QPainter成员函数fillRect()时出现BusError。
QT中QTimer类提供了定时器信号和单触发定时器。它在内部使用定时器事件来提供更通用的定时器。QTimer很容易使用:创建一个QTimer,使用start()来开始并且把它的timeout()连接到适当的槽。当这段时间过去了,它将会发射timeout()信号。而QtimeLine也有相同的机制。我们通过连接信号与槽函数,实现了时间间隔改变图片的显示,从而实现图片切换特效。
从实际出发,分析数码相框程序中代码的执行效率,可以发现数码相框从图片文件中加载数据到缓存,以及画图事件中图片的显示均需要占用系统大部分资源来实现,由于数码相框程序中为了实现比较流畅的特效,定时器及动画的间隔均设置的很短,时间约10ms~30ms出发一次画图,这时候便要求系统在这个时间间隔内能顺利的实现图片的显示,若在这个时间间隔内系统无法完全执行完画图事件,则定时到时间系统又重新调用槽函数进入画图事件,可能会导致重入的问题。
由于当系统试图访问一块无文件内容对应的内存区域,比如超过文件尾的内存区域,或者以前有文件内容对应,现在为另一进程截断过的内存区域则会发生BusError,那么可以猜测数码相框可能是由于函数重入问题导致的BusError,调试一下,先在数码相框中对定期器及动画类触发的槽函数做以下处理:定时器定时触发槽函数,进入槽函数关闭定时器,实现槽函数后再开启定时器,同理,动画类可以用暂停的方式;用此方法避免函数重入的问题,再交叉编译到板子上进行测试,发现程序稳定性有所提高,但是依然有BusError问题出现,分析调试信息,此时发现第一种情况出现BusError的问题得到解决,现在程序的BusError集中到第二个位置,即在画图事件中实现填充区域的QPainter成员函数fillRect()时出现BusError。
分析QT源码,fillRect实现方式如下:
fillRect(r,Qt::SolidPattern);
--->
setBrush(Qt::SolidPattern);drawRect(r);
--->
inlinevoidQPainter::drawRect(constQRectF&rect)
{
drawRects(&rect,1);
}
--->
voidQPainter::drawRects(constQRect*rects,intrectCount)
{
…
}
QT源码中对于类的包装导致我们比较难分析出其如何具体操作硬件,而且并不是每一次执行此行代码都会导致BusError,故猜测可能程序某些客观存在的指针导致其实现fillRect偶然性出现未对齐的数据访问。故对于数码相框项目而言,我们暂时采取用其他方式填充屏幕区域:设置黑色背景图的方式,再经过测试,数码相框程序终于能比较稳定的运行了。
由于并未联系loongson1B开发板底层的实现来分析BusError,故并没有真正探究到BusError出现的原因是硬件上、底层软件上或者确实是程序本身的原因,所以此文档有待补充。