嵌入式Linux應用崩潰調試-難以追蹤的棧信息

在進行嵌入式Linux應用程序開發時,經常會用到gdb對崩潰日誌進行分析,一般情況下,可以直接定位到崩潰的位置。但有時分析core文件時,卻看不到有意義的崩潰棧,這時問題就有點複雜了,出現這種現象的原因可能有這麼幾個:

  1. 應用程序在編譯時沒有指定-g選項,導致可執行程序沒有調試信息。
  2. 應用程序所依賴的動態庫和靜態庫沒有調試信息。
  3. 應用程序的運行時環境沒有調試信息,比如libc等。
  4. 嵌入式Linux系統應用程序運行時環境和交叉編譯工具鏈的運行時環境版本不一致,比如,嵌入式Linux環境中所使用的libc庫和交叉編譯器所使用的libc庫版本不一致。

對於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<string.h>

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得到的信息,注意下面幾點:

  1. test加載成功,並且其有調試信息。
  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?),說的是通過core文件的信息在交叉編譯環境的libc中找不到.dynamic section,最後的結論是wrong library or version mismatch?即,庫文件被損壞或者版本不一致。這是解決問題的關鍵。
  3. 這時如果通過bt,查看崩潰棧信息,會得到一些莫名其妙的信息,比如這裏的tr_freehook。如果沒有注意到2中提示的警告信息,可能會沿着這個錯誤的棧信息去查找問題原因,這時就會走很多的彎路,最終無功而返。

解決思路

通過第二節對於core的分析,可以看出問題的關鍵是運行環境和編譯環境的libc版本庫不一致導致的,那麼解決問題的思路就明顯了:

  1. 要麼修改交叉編譯的運行時環境。
  2. 要麼修改運行時環境。

很明顯,肯定是第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時的一些警告信息。

所以,這裏再次強調一下,開發過程中的任何警告信息都不能輕易放過,必須仔細分析,問題的解決線索往往蘊含其中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章