C++ 如何在addr2line运行期间从偏移量中的回溯_symbols()解析cpp符号
为了在运行时捕获诸如分段错误之类的致命错误,我编写了一个定制的SignalHandler,它将把堆栈跟踪打印到控制台并写入日志文件 为了实现这一点,我将C++ 如何在addr2line运行期间从偏移量中的回溯_symbols()解析cpp符号,c++,c,linux,debugging,backtrace,C++,C,Linux,Debugging,Backtrace,为了在运行时捕获诸如分段错误之类的致命错误,我编写了一个定制的SignalHandler,它将把堆栈跟踪打印到控制台并写入日志文件 为了实现这一点,我将backtrace()和backtrace\u symbols()函数与addr2line结合使用 调用backtrace\u symbols()将生成以下输出: Obtained 8 stack frames. ./Mainboard_Software(+0xb1af5) [0x56184991baf5] ./Mainboard_Softwar
backtrace()
和backtrace\u symbols()
函数与addr2line
结合使用
调用backtrace\u 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模块)中,我将偏移量作为sybols和hex的组合,比如\u 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
但我想在运行时执行最后两个步骤。是否有办法在运行时解析这些符号(例如,\u Z13MainboardInit7QString+0xf3
),以便我可以将它们直接传递给addr2line?
我的程序由.c和.cpp模块组成。您可以使用库cxxabi在运行时调用符号:
#include <cxxabi.h>
//...
char *symbolName = "_Z13MainboardInit7QString";
int st;
char* cxx_sname = abi::__cxa_demangle
(
symbolName,
nullptr,
0,
&st
);
#包括
//...
char*symbolName=“\u Z13MainboardInit7QString”;
int st;
char*cxx\u sname=abi::\uu cxa\u demangle
(
符号名,
nullptr,
0,
&圣
);
返回的cxx\u name
数组包含demangled符号
地址(基址和偏移量)可以通过使用括号作为开始和结束分隔符的简单解析从初始字符串中恢复。花了我一段时间,但在Linux中,可以使用
dlfcn.h
GNU库。
只需确保在所有头文件包含的头文件之上定义\u GNU\u SOURCE
。
注意,此包含将使您的程序POSIX不符合格式
对于链接器标志,为两种体系结构添加-ldl
,为x86和-g3
添加-g3
,为ARM添加-funwind tables
,-mapcs frame
定义GNU源
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义堆栈\帧\缓冲区大小(int)128
静态无效*堆栈帧缓冲区[128];
静态无效*偏移帧缓冲区[128];
静态字符执行\u文件名[32]=“主板\u软件”;
/*-----------------------------------------------------------------------------------*/
/*
*函数将尝试通过收集最后调用的地址来回溯信号原因。
*然后,地址将通过addr2line转换为可读的stings
*/
静态void打印回溯(void)
{
const char errorString[]=“无法解析偏移量:不存在偏移量?\n\0?”;
char printary[100]={0};
缓冲区条目的大小;
字符**堆栈帧字符串;
大小\u t帧迭代器;
//回溯最后的通话
bufferEntries=回溯(堆栈帧缓冲区、堆栈帧缓冲区大小);
StackFrameString=回溯符号(堆栈帧缓冲区,(int)缓冲项);
//打印获得的帧数
sprintf(printArray,“\n包含%zd个堆栈帧。\n\r”,bufferEntries);
(void)写入(STDERR_文件号、打印数组、strlen(打印数组));
//迭代地址并打印stings
对于(frameIterator=0;frameIteratorObtained 11 stack frames.
0x00000000000b1ba5: PrintBacktrace at SignalModule.c:524
0x00000000000b1aeb: HandleBacktraceSignals at SignalModule.c:494
0x0000000000012dd0: ?? ??:0
0x00000000000aea85: baz at testFunctions.c:75
0x00000000000aea6b: bar at testFunctions.c:70
0x00000000000aea5f: foo at testFunctions.c:65
0x00000000000aea53: causeSIGSEGV at testFunctions.c:53
0x00000000000a412f: MainboardInit(QString) at MainboardInit.cpp:218
0x00000000000ae2f3: main at Main.cpp:142 (discriminator 2)
0x000000000002409b: ?? ??:0
0x00000000000950fa: _start at ??:?