为了在运行时捕获像Segmentation Fault这样的致命错误,我编写了一个自定义的SignalHandler,它将把堆栈跟踪打印到控制台和日志文件中。
为了实现这一点,我使用了backtrace()
和backtrace_symbols()
函数与addr2line
的组合(就像我之前的数百个函数一样)。
呼叫backtrace_symbols()
会产生下列输出:
Obtained 8 stack frames.
./Mainboard_Software(+0xb1af5) [0x56184991baf5]
./Mainboard_Software(+0xb1a79) [0x56184991ba79]
/lib/x86_64-linux-gnu/libpthread.so.0(+0x12dd0) [0x7fe72948bdd0]
./Mainboard_Software(causeSIGFPE+0x16) [0x561849918a10]
./Mainboard_Software(_Z13MainboardInit7QString+0xf3) [0x56184990e0df]
./Mainboard_Software(main+0x386) [0x5618499182a3]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xeb) [0x7fe727fd909b]
./Mainboard_Software(_start+0x2a) [0x5618498ff0aa]
我需要将偏移量传递给addr2line,以获得我的模块名称和行号。
$ addr2line -C -a -s -f -p -e ./D098_Mainboard_Software 0xb1a79
0x00000000000b1a79: HandleBacktraceSignals at SignalModule.c:492
然而,在某些模块(尤其是cpp模块)中,我得到的偏移量是符号和十六进制的组合,比如_Z13MainboardInit7QString+0xf3
我可以通过调用nm
将符号解析为十六进制:
$ nm Mainboard_Software | grep _Z13MainboardInit7QString
00000000000a3fec T _Z13MainboardInit7QString
现在我可以把这两个十六进制数相加,把它们传递给addr2line,得到我的模块名和行号,如果我想的话,甚至可以解包:
$ addr2line -C -a -s -f -p -e ./D098_Mainboard_Software 0xa40df
0x00000000000a40df: MainboardInit(QString) at MainboardInit.cpp:219
但是我想在运行时完成最后两步。有没有办法在运行时解析这些符号(例如_Z13MainboardInit7QString+0xf3
),这样我就可以直接将它们传递给addr2line?我的程序由.c和. cpp模块组成。
3条答案
按热度按时间62o28rlo1#
您可以使用cxxabi库在运行时解除符号的混乱:
返回的
cxx_name
数组包含解角符号。通过使用方括号作为开始和结束分隔符进行简单的解析,可以从初始字符串恢复地址(基址和偏移量)。
r7s23pms2#
我花了一段时间,但在Linux上,可以使用
dlfcn.h
GNU库。只是一定要定义_GNU_SOURCE
以上的所有头文件包含。小心这个包含将使您的程序POSIX不符合。对于链接器标志,对于两种体系结构,添加
-ldl
;对于x86,添加-g3
;对于ARM,添加-g3
、-funwind-tables
、-mapcs-frame
。调用此函数将在控制台上生成如下输出:
8i9zcol23#
另一个简单的回答:
构建和运行:
其结果是: