背景
虽然才刚进入新环境,但是由于项目交付节点临近,领导主要让我分析、解决以前遗留的问题,保证软件的稳定性。
其中有一个问题现象是:片间通信进程(负责SOC和MCU交互的服务)偶现阻塞问题。经过短暂的分析,我怀疑是因为资源竞争导致的死锁问题。针对死锁问题,我认为有两种分析方式。
- 分析代码。分析各线程、进程之间的临界资源,在时序上,是否存在死锁的情况。若对代码架构比较熟悉,该方式应该是不错的方式。
- gdb调试。当时出现死锁时,肯定是存在了2个以上的线程在等待资源的释放,此时,我们可以通过
gdb -p
查看对应进程、线程的堆栈信息,在wait哪一个临界资源。这样能够很快的定位到资源竞争的逻辑,但是需要问题复现。
因为是偶现问题,理论上应该采取方式一。但是因为此时我还有别的问题需要处理,于是选择了方式二:准备一个拷机环境,当问题复现时,直接用gdb调试分析,应该能节约很多时间。
计划是美好的,但是在搭建拷机环境中,遇到了gdb使用的问题,一直会提示Backtrace stopped: previous frame identical to this frame (corrupt stack?)
错误,导致无法查看完整的堆栈信息,心想:若gdb无法使用,及时问题复现,也不能定位到阻塞点,应该优先解决该问题。
最终经过查阅资料以及咨询模组供应商,最终解决了。这个过程包括分析的思路,以及和供应商之间的battle。希望能给遇到的朋友一些建议、帮助🤡。
问题复现
当我使用TBOX中自带的gdb(7.9.1版本)工具时,结合gdb -p
查看一个正常运行的进程堆栈信息时,输出如下:
看到这个Backtrace stopped
错误提示,我是很意外的。因为根据【程序员的自我修养11】栈与函数调用过程内容中可知,函数的调用回溯是依靠堆栈信息的。若出现Backtrace stopped
,那么该线程的函数调用回溯就会出现问题,必然会导致crash。但实际上,我们并不会存在该问题。
于是我的第一反应是:TBOX自带的gdb(7.9.1版本)版本过低,导致无法正常使用。
于是我就选择gdb-9.2版本,通过交叉编译,看看是否存在同样的问题。如何交叉编译,可参考我的另一篇文章:工作中如何编译开源工具(gdb)
最终调试输出如下:
异常现象:
- 程序在编译过程中,选择了-g选项,并且没有
stripped
,为什么还是没有符号信息。 Backtrace stopped
错误依然存在。- gdb-9.2加载时,提示:
warning: Unable to find libthread_db matching inferior's thread library, thread debugging will not be available.
综上所述,我目前怀疑是TBOX的环境有问题:因为无论是core文件,还是gdb动态调试,通过bt指令查看堆栈信息。都是将内存中的相关数据,按照一定的规则进行记录或解析。因为程序运行没有问题,只是gdb解析时异常,因此我认为是gdb的记录和解析规则有问题。
最终由于时间有限,我就没有继续跟进下去,而是将该问题以及我的分析思路反馈给模组供应商,希望他们能够协助解决。
在这过程中,其实也涉及到与供应商之间的battle。人都是有惰性的,能推脱的尽量会去推卸,供应商也不例外。常见的手段就是:
- 面对界限不清晰的问题,一般都会回复比较模糊。比如:这不一定是我们的问题、在其他客户上并没有出现该问题等等。
- 想到一个思路,就让客户去尝试,是否有效也不确定。让客户去做小白鼠。
对于这两种行为,我是深恶痛绝的。我的处理方式一般为:
- 拿出确定证据,明确是他们的问题。可以通过抓包、查阅资料、排除我们的因素等方式。
- 面对供应商的方法、思路。我一般都会咨询其操作原因,如果不能说清楚,我只会配合一次,若明显不对,我就会要求他们自己先自测,再进行和我反馈。否则进行投诉。
最终在两周的催促下,客户为我们提供了三个库:
- ld-2.22.so,动态链接器
- libpthread-2.22.so,线程库
- libc-2.22.so,C标准库
将这三个库替换到文件系统/lib
目录下,再使用gdb-7.9.1版本进行调试,则一切正常。
我最终比对了之前的库与新库的区别,从属性上看,主要就是附加debug信息以及not stripped。如下:
//old
ld-2.22.so: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, stripped
libpthread-2.22.so: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (GNU/Linux), dynamically linked, interpreter /lib/ld-linux.so.3, for GNU/Linux 2.6.32, stripped
libc-2.22.so: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.3, for GNU/Linux 2.6.32, stripped
// new
ld-2.22.so: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, with debug_info, not stripped
libc-2.22.so: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.3, for GNU/Linux 2.6.32, with debug_info, not stripped
libpthread-2.22.so: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (GNU/Linux), dynamically linked, interpreter /lib/ld-linux.so.3, for GNU/Linux 2.6.32, with debug_info, not stripped
总结
若您与我遇到了相似的问题,不妨试试将以上三个库重新编译一份,替换成具备debug_info,以及not stripped。若依旧不能解决,坚决一点,就是供应商的问题,让他们去解决。
若我的内容对您有所帮助,还请关注我的公众号。不定期分享干活,剖析案例,也可以一起讨论分享。
我的宗旨:
踩完您工作中的所有坑并分享给您,让你的工作无bug,人生尽是坦途