嵌入式Linux应用崩溃调试-难以追踪的栈信息

简介: 在进行嵌入式Linux应用程序开发时,经常会用到gdb对崩溃日志进行分析,一般情况下,可以直接定位到崩溃的位置。但有时分析core文件时,却看不到有意义的崩溃栈,这时问题就有点复杂了,出现这种现象的原因可能有这么几个

在进行嵌入式Linux应用程序开发时,经常会用到gdb对崩溃日志进行分析,一般情况下,可以直接定位到崩溃的位置。但有时分析core文件时,却看不到有意义的崩溃栈,这时问题就有点复杂了,出现这种现象的原因可能有这么几个:


  1. 应用程序在编译时没有指定-g选项,导致可执行程序没有调试信息。


  1. 应用程序所依赖的动态库和静态库没有调试信息。


  1. 应用程序的运行时环境没有调试信息,比如libc等。


  1. 嵌入式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加载成功,并且其有调试信息。


  1. 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?即,库文件被损坏或者版本不一致。这是解决问题的关键。


  1. 这时如果通过bt,查看崩溃栈信息,会得到一些莫名其妙的信息,比如这里的tr_freehook。如果没有注意到2中提示的警告信息,可能会沿着这个错误的栈信息去查找问题原因,这时就会走很多的弯路,最终无功而返。


解决思路


通过第二节对于core的分析,可以看出问题的关键是运行环境和编译环境的libc版本库不一致导致的,那么解决问题的思路就明显了:


  1. 要么修改交叉编译的运行时环境。


  1. 要么修改运行时环境。


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


所以,这里再次强调一下,开发过程中的任何警告信息都不能轻易放过,必须仔细分析,问题的解决线索往往蕴含其中。


相关实践学习
阿里云图数据库GDB入门与应用
图数据库(Graph Database,简称GDB)是一种支持Property Graph图模型、用于处理高度连接数据查询与存储的实时、可靠的在线数据库服务。它支持Apache TinkerPop Gremlin查询语言,可以帮您快速构建基于高度连接的数据集的应用程序。GDB非常适合社交网络、欺诈检测、推荐引擎、实时图谱、网络/IT运营这类高度互连数据集的场景。 GDB由阿里云自主研发,具备如下优势: 标准图查询语言:支持属性图,高度兼容Gremlin图查询语言。 高度优化的自研引擎:高度优化的自研图计算层和存储层,云盘多副本保障数据超高可靠,支持ACID事务。 服务高可用:支持高可用实例,节点故障迅速转移,保障业务连续性。 易运维:提供备份恢复、自动升级、监控告警、故障切换等丰富的运维功能,大幅降低运维成本。 产品主页:https://www.aliyun.com/product/gdb
相关文章
|
10天前
|
缓存 NoSQL Linux
Linux调试
本文介绍了Linux调试、性能分析和追踪的培训资料,涵盖调试、性能分析和追踪的基础知识及常用工具。
168 6
Linux调试
|
14天前
|
缓存 监控 Linux
|
3月前
|
存储 监控 安全
在Linux中,⼀个EXT3的文件分区,当使用touch test.file命令创建⼀个新文件时报错,报错的信息是提示磁盘已满,但是采用df -h命令查看磁盘大小时,只使用了,60%的磁盘空间,为什么会出现这个情况?
在Linux中,⼀个EXT3的文件分区,当使用touch test.file命令创建⼀个新文件时报错,报错的信息是提示磁盘已满,但是采用df -h命令查看磁盘大小时,只使用了,60%的磁盘空间,为什么会出现这个情况?
|
21天前
|
缓存 监控 Linux
Python 实时获取Linux服务器信息
Python 实时获取Linux服务器信息
|
3月前
|
NoSQL Linux C语言
Linux GDB 调试
Linux GDB 调试
62 10
|
3月前
|
NoSQL Linux C语言
嵌入式GDB调试Linux C程序或交叉编译(开发板)
【8月更文挑战第24天】本文档介绍了如何在嵌入式环境下使用GDB调试Linux C程序及进行交叉编译。调试步骤包括:编译程序时加入`-g`选项以生成调试信息;启动GDB并加载程序;设置断点;运行程序至断点;单步执行代码;查看变量值;继续执行或退出GDB。对于交叉编译,需安装对应架构的交叉编译工具链,配置编译环境,使用工具链编译程序,并将程序传输到开发板进行调试。过程中可能遇到工具链不匹配等问题,需针对性解决。
|
3月前
|
Ubuntu Linux
内核实验(四):Qemu调试Linux内核,实现NFS挂载
本文介绍了在Qemu虚拟机中配置NFS挂载的过程,包括服务端的NFS服务器安装、配置和启动,客户端的DHCP脚本添加和开机脚本修改,以及在Qemu中挂载NFS、测试连通性和解决挂载失败的方法。
189 0
内核实验(四):Qemu调试Linux内核,实现NFS挂载
|
2月前
|
Linux API 开发工具
Linux内核开发流程指南 - 8. 获取更多信息【ChatGPT】
Linux内核开发流程指南 - 8. 获取更多信息【ChatGPT】
|
3月前
|
传感器 人工智能 网络协议
:嵌入式 Linux 及其用途
【8月更文挑战第24天】
170 0
|
3月前
|
监控 Linux
在Linux中,有⼀个脚本运行时间可能超过2天,如何做才能使其不间断的运行,而且还可以随时观察脚本运行时的输出信息?
在Linux中,有⼀个脚本运行时间可能超过2天,如何做才能使其不间断的运行,而且还可以随时观察脚本运行时的输出信息?