แม้ว่าจะมีการให้คำตอบที่ถูกต้องซึ่งอธิบายถึงวิธีการใช้backtrace()
ฟังก์ชันGNU libc 1และฉันได้ให้คำตอบของตัวเองที่อธิบายถึงวิธีการตรวจสอบย้อนหลังจากจุดจัดการสัญญาณไปยังตำแหน่งที่แท้จริงของความผิด2ฉันไม่เห็น การเอ่ยถึงการถอดสัญลักษณ์ C ++ ใด ๆ ออกมาจาก backtrace
เมื่อได้รับ backtraces จากโปรแกรม C ++ เอาต์พุตสามารถรันผ่านc++filt
1เพื่อลดสถานะของสัญลักษณ์หรือโดยใช้1โดยตรงabi::__cxa_demangle
- 1 Linux & OS X
โปรดสังเกตว่า
c++filt
และ__cxa_demangle
เฉพาะ GCC
- 2 ลินุกซ์
ตัวอย่าง C ++ Linux ต่อไปนี้ใช้ตัวจัดการสัญญาณเดียวกับคำตอบอื่น ๆของฉันและแสดงให้เห็นถึงวิธีการที่c++filt
สามารถนำมาใช้เพื่อลดความซับซ้อนของสัญลักษณ์
รหัส :
class foo
{
public:
foo() { foo1(); }
private:
void foo1() { foo2(); }
void foo2() { foo3(); }
void foo3() { foo4(); }
void foo4() { crash(); }
void crash() { char * p = NULL; *p = 0; }
};
int main(int argc, char ** argv)
{
// Setup signal handler for SIGSEGV
...
foo * f = new foo();
return 0;
}
ผลลัพธ์ ( ./test
):
signal 11 (Segmentation fault), address is (nil) from 0x8048e07
[bt]: (1) ./test(crash__3foo+0x13) [0x8048e07]
[bt]: (2) ./test(foo4__3foo+0x12) [0x8048dee]
[bt]: (3) ./test(foo3__3foo+0x12) [0x8048dd6]
[bt]: (4) ./test(foo2__3foo+0x12) [0x8048dbe]
[bt]: (5) ./test(foo1__3foo+0x12) [0x8048da6]
[bt]: (6) ./test(__3foo+0x12) [0x8048d8e]
[bt]: (7) ./test(main+0xe0) [0x8048d18]
[bt]: (8) ./test(__libc_start_main+0x95) [0x42017589]
[bt]: (9) ./test(__register_frame_info+0x3d) [0x8048981]
Demangled Output ( ./test 2>&1 | c++filt
):
signal 11 (Segmentation fault), address is (nil) from 0x8048e07
[bt]: (1) ./test(foo::crash(void)+0x13) [0x8048e07]
[bt]: (2) ./test(foo::foo4(void)+0x12) [0x8048dee]
[bt]: (3) ./test(foo::foo3(void)+0x12) [0x8048dd6]
[bt]: (4) ./test(foo::foo2(void)+0x12) [0x8048dbe]
[bt]: (5) ./test(foo::foo1(void)+0x12) [0x8048da6]
[bt]: (6) ./test(foo::foo(void)+0x12) [0x8048d8e]
[bt]: (7) ./test(main+0xe0) [0x8048d18]
[bt]: (8) ./test(__libc_start_main+0x95) [0x42017589]
[bt]: (9) ./test(__register_frame_info+0x3d) [0x8048981]
บิลด์ต่อไปนี้สร้างขึ้นบนตัวจัดการสัญญาณจากคำตอบดั้งเดิมของฉันและสามารถแทนที่ตัวจัดการสัญญาณในตัวอย่างข้างต้นเพื่อสาธิตวิธีที่abi::__cxa_demangle
สามารถใช้ในการทำให้สถานะสัญลักษณ์ลดลง ตัวจัดการสัญญาณนี้สร้างเอาต์พุต demangled เดียวกันกับตัวอย่างข้างต้น
รหัส :
void crit_err_hdlr(int sig_num, siginfo_t * info, void * ucontext)
{
sig_ucontext_t * uc = (sig_ucontext_t *)ucontext;
void * caller_address = (void *) uc->uc_mcontext.eip; // x86 specific
std::cerr << "signal " << sig_num
<< " (" << strsignal(sig_num) << "), address is "
<< info->si_addr << " from " << caller_address
<< std::endl << std::endl;
void * array[50];
int size = backtrace(array, 50);
array[1] = caller_address;
char ** messages = backtrace_symbols(array, size);
// skip first stack frame (points here)
for (int i = 1; i < size && messages != NULL; ++i)
{
char *mangled_name = 0, *offset_begin = 0, *offset_end = 0;
// find parantheses and +address offset surrounding mangled name
for (char *p = messages[i]; *p; ++p)
{
if (*p == '(')
{
mangled_name = p;
}
else if (*p == '+')
{
offset_begin = p;
}
else if (*p == ')')
{
offset_end = p;
break;
}
}
// if the line could be processed, attempt to demangle the symbol
if (mangled_name && offset_begin && offset_end &&
mangled_name < offset_begin)
{
*mangled_name++ = '\0';
*offset_begin++ = '\0';
*offset_end++ = '\0';
int status;
char * real_name = abi::__cxa_demangle(mangled_name, 0, 0, &status);
// if demangling is successful, output the demangled function name
if (status == 0)
{
std::cerr << "[bt]: (" << i << ") " << messages[i] << " : "
<< real_name << "+" << offset_begin << offset_end
<< std::endl;
}
// otherwise, output the mangled function name
else
{
std::cerr << "[bt]: (" << i << ") " << messages[i] << " : "
<< mangled_name << "+" << offset_begin << offset_end
<< std::endl;
}
free(real_name);
}
// otherwise, print the whole line
else
{
std::cerr << "[bt]: (" << i << ") " << messages[i] << std::endl;
}
}
std::cerr << std::endl;
free(messages);
exit(EXIT_FAILURE);
}