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