0%

ENOS上段错调试记录

写在前面

移植ENOS过程中发现某些系统编译生成的命令运行过程中报segmentation fault,报错信息如下。这里记录一下调试过程中遇到的问题,涉及到weak属性,-pthreadstrace等。

段错调试手段记录

产生段错首先想到的自然是通过gdb进行错误分析,由于toolchain中并没有提供,所以自行下载了一个gdb源码,通过经典configure, make, make install三部曲后移到板子上,gdb调试信息如下:

gdb中并不能看出什么有效的信息,但看起来函数栈的调用还没有到ccs的main函数中(没有与ccs相关的打印),上一篇文章《关于动态库以及constructor属性的使用》中有提到。
通过dmesg查看内核报错信息:

可以看到pc寄存器取址的地址为全0 ,这一般是因为空指针导致,我们知道cpu指令的执行顺序为取址,分析,执行三个步骤,没取到指令后续自然是啥都没有了。

通过strace ccs命令来查看ccs的详细调用过程关于动态库的调用过程就不表了,这里直接看报错的位置:

发现执行完write指令之后就挂了,经过一番曲折之后定位到代码中:

iv_fd_set_cloexec中有两次fnctl的调用,与strace中的4次fnctl调用刚好对上,而函数iv_signal_initconstructor属性修饰,而该函数所在模块(libtask)是被编译成so供其它模块调用的,即所有调用该动态库的模块在执行main函数之前都会执行一遍iv_signal_init,进一步追查Makefile发现报错的命令全部都依赖与该动态库,一切都说通了,没有玄学。

在进一步排查,init中最可疑的就是pthr_atfork这个函数了,查看该函数定义,发现一个从没见过的用法#pragma weak pthread_atfork

后面会再写一篇关于这个属性的用法,简单说就是被weak修饰的符号即使不存在编译也不会报错。

weak之后的调试

这里发现libtask中既没有自己实现pthread_atfork,也没有在Makefile中链接-pthread,而是使用ifdef HAVE_PRAGMA_WEAK(后来我改成ifndef了)来进行屏蔽,在运行过程中自然会报错,在调用之前打印该函数的地址,不出意料的是NULL,维护人员最初的用意已经不可考证了,直接去掉HAVE_PRAGMA_WEAK,编译中加上-pthread

这里有必要顺嘴提一下-lpthread-pthread,如果使用-lpthread的时候会报一些undefined reference to的错误,错误原因可以自行百度,换成-pthread即可。