在进行嵌入式Linux应用程序开发时,经常会用到gdb对崩溃日志进行分析,一般情况下,可以直接定位到崩溃的位置。但有时分析core文件时,却看不到有意义的崩溃栈,这时问题就有点复杂了,出现这种现象的原因可能有这么几个:
对于1-3条所列出的问题,可以很容易的通过gdb提供的提示信息获得,比如,如果应用程序test编译时没有添加-g选项,当使用gdb调试时,会提示如下信息:
Reading symbols from /home/jetpack/test/test...(no debugging symbols found)...done.
对于动态库提示信息也是类似的。
今天,重点说一下,第四种情况。
下面以一个具体的场景来说明这个问题。
第4条说的是,Linux系统运行时环境与交叉工具链环境不一致,这里就以libc中的strlen为例来说明问题。
strlen用于计算c字符串的长度,其中不包括字符串结束符’\0’。但是,strlen传入NULL指针时,会导致段错误。我们通过模拟这种场景来看一下,系统运行环境与编译环境不一致带来的问题。
下面是会导致崩溃的代码:
#include
int main(int argc, char* argv[])
{
int rlen = strlen(NULL);
return 0;
}
注意:编译时指定-g,否则test没有调试信息。
嵌入式Linux运行环境libc信息:
root@zpd /lib$ ll libc.so.6
lrwxrwxrwx 1 root root 12 Jan 1 00:00 libc.so.6 -> libc-2.13.so
root@zpd /lib$ ll libc-2.13.so
-rwxr-xr-x 1 root root 1409189 Jan 1 22:08 libc-2.13.so
交叉编译器libc信息:
lrwxrwxrwx 1 jetpack jetpack 12 3月 9 12:07 libc.so.6 -> libc-2.13.so*
-rwxr-xr-x 1 jetpack jetpack 1496962 3月 15 2012 libc-2.13.so*
将test编译之后,拷贝到嵌入式Linux环境中运行。注意,需要重新配置shell环境的ulimit关于core文件的限制,否则不会出现core文件。具体命令如下:
ulimit -c unlimited
./test
Segmentation fault (core dumped)
将core文件拷贝到开发环境,使用gdb查看core文件信息。
1. Reading symbols from /home/jetpack/test/test...done.
[New Thread 852]
2. warning: .dynamic section for "/home/jetpack/work/OKMX6UL-C2/fsl-linaro-toolchain/arm-fsl-linux-gnueabi/multi-libs/lib/libc.so.6" is not at the expected address (wrong library or version mismatch?)
Reading symbols from /home/jetpack/work/OKMX6UL-C2/fsl-linaro-toolchain/arm-fsl-linux-gnueabi/multi-libs/lib/libc.so.6...done.
Loaded symbols for /home/jetpack/work/OKMX6UL-C2/fsl-linaro-toolchain/arm-fsl-linux-gnueabi/multi-libs/lib/libc.so.6
Reading symbols from /home/jetpack/work/OKMX6UL-C2/fsl-linaro-toolchain/arm-fsl-linux-gnueabi/multi-libs/lib/ld-linux.so.3...done.
Loaded symbols for /home/jetpack/work/OKMX6UL-C2/fsl-linaro-toolchain/arm-fsl-linux-gnueabi/multi-libs/lib/ld-linux.so.3
Core was generated by `./test'.
Program terminated with signal 11, Segmentation fault.
#0 0x76e8d864 in tr_freehook () from /home/jetpack/work/OKMX6UL-C2/fsl-linaro-toolchain/arm-fsl-linux-gnueabi/multi-libs/lib/libc.so.6
(gdb) bt
3. #0 0x76e8d864 in tr_freehook () from /home/jetpack/work/OKMX6UL-C2/fsl-linaro-toolchain/arm-fsl-linux-gnueabi/multi-libs/lib/libc.so.6
#1 0x7ec97dd4 in ?? ()
#2 0x7ec97dd4 in ?? ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
上面是gdb通过core得到的信息,注意下面几点:
通过第二节对于core的分析,可以看出问题的关键是运行环境和编译环境的libc版本库不一致导致的,那么解决问题的思路就明显了:
很明显,肯定是第2种思路,将交叉编译器的libc-2.13.so库拷贝到嵌入式Linux环境,替换之前的libc-2.13.so,再次运行test,得到core文件,gdb调试之,core文件信息如下:
1. Reading symbols from /home/jetpack/test/test...done.
[New Thread 858]
2. Reading symbols from /home/jetpack/work/OKMX6UL-C2/fsl-linaro-toolchain/arm-fsl-linux-gnueabi/multi-libs/lib/libc.so.6...done.
Loaded symbols for /home/jetpack/work/OKMX6UL-C2/fsl-linaro-toolchain/arm-fsl-linux-gnueabi/multi-libs/lib/libc.so.6
Reading symbols from /home/jetpack/work/OKMX6UL-C2/fsl-linaro-toolchain/arm-fsl-linux-gnueabi/multi-libs/lib/ld-linux.so.3...done.
Loaded symbols for /home/jetpack/work/OKMX6UL-C2/fsl-linaro-toolchain/arm-fsl-linux-gnueabi/multi-libs/lib/ld-linux.so.3
Core was generated by `./test'.
Program terminated with signal 11, Segmentation fault.
3. #0 0x76e5e864 in strlen () from /home/jetpack/work/OKMX6UL-C2/fsl-linaro-toolchain/arm-fsl-linux-gnueabi/multi-libs/lib/libc.so.6
(gdb) bt
#0 0x76e5e864 in strlen () from /home/jetpack/work/OKMX6UL-C2/fsl-linaro-toolchain/arm-fsl-linux-gnueabi/multi-libs/lib/libc.so.6
#1 0x00008390 in main (argc=1, argv=0x7ef85dc4) at test.c:5
对照上面的1、2、3条,可以看到第2条可以正确的加载libc.so.6库;第3条可以看到由于崩溃位置在strlen。
本文通过一个案例,简要说明了在嵌入式Linux应用开发时,由于运行时环境和交叉编译环境不一致导致的core文件分析失败的问题,并说明了如何解决这个问题。有的人会问,为什么会导致环境不一致呢?在构建嵌入式Linux环境时,肯定会涉及到根文件系统的构建过程,这时会将交叉编译器的环境整体拷贝到根文件系统中,这样的话就不会出现上述问题。是的,如果按照这个流程中应该不会有问题,但是,实际情况是,我们拿的是一个构建好的Linux系统,如果这时交叉编译工具链升级了,而嵌入式Linux运行时环境未升级,那问题就出现了。这时,就需要根据各种信息,来分析问题的根源了,这里就是gdb分析core时的一些警告信息。
所以,这里再次强调一下,开发过程中的任何警告信息都不能轻易放过,必须仔细分析,问题的解决线索往往蕴含其中。