在Unix系统上自动获取堆栈跟踪有哪些方法?我并不是指获取核心文件或以GDB交互方式附加,而是使用SIGSEGV处理程序将回溯转储到文本文件.
以下可选功能的奖励积分:
在崩溃时收集额外信息(例如配置文件).
将崩溃信息包发送给开发人员.
能够在dlopen
ed共享库中添加它
不需要GUI
小智.. 15
仅供参考,
建议的解决方案(在信号处理程序中使用backtrace_symbols)被危险地破坏了.不要使用它 -
是的,backtrace和backtrace_symbols将产生一个回溯并将其转换为符号名称,但是:
backtrace_symbols使用malloc分配内存,你可以使用free来释放它 - 如果由于内存损坏而崩溃,你的malloc竞技场很可能会被破坏并导致双重故障.
malloc和内部锁定免费保护malloc竞技场.你可能在malloc/free中间出现故障并锁定,这将导致这些函数或任何调用它们的死锁.
您使用使用标准流的puts,它也受锁保护.如果你在printf中间出现故障,你又会陷入僵局.
在32位平台上(例如2年前的普通PC),内核会为你的堆栈中的内部glibc函数而不是你的错误函数设置一个返回地址,这是你感兴趣的最重要的一条信息 - 其中函数做了程序错误,实际上会在那些平台上被破坏.
因此,示例中的代码是最糟糕的错误 - 它看起来像是在工作,但它会在生产中以意想不到的方式让您失败.
BTW,有兴趣做对吗?看看这个.
干杯,吉拉德.
仅供参考,
建议的解决方案(在信号处理程序中使用backtrace_symbols)被危险地破坏了.不要使用它 -
是的,backtrace和backtrace_symbols将产生一个回溯并将其转换为符号名称,但是:
backtrace_symbols使用malloc分配内存,你可以使用free来释放它 - 如果由于内存损坏而崩溃,你的malloc竞技场很可能会被破坏并导致双重故障.
malloc和内部锁定免费保护malloc竞技场.你可能在malloc/free中间出现故障并锁定,这将导致这些函数或任何调用它们的死锁.
您使用使用标准流的puts,它也受锁保护.如果你在printf中间出现故障,你又会陷入僵局.
在32位平台上(例如2年前的普通PC),内核会为你的堆栈中的内部glibc函数而不是你的错误函数设置一个返回地址,这是你感兴趣的最重要的一条信息 - 其中函数做了程序错误,实际上会在那些平台上被破坏.
因此,示例中的代码是最糟糕的错误 - 它看起来像是在工作,但它会在生产中以意想不到的方式让您失败.
BTW,有兴趣做对吗?看看这个.
干杯,吉拉德.
如果您使用的是具有BSD backtrace
功能的系统(Linux,OSX 1.5,BSD),则可以在信号处理程序中以编程方式执行此操作.
例如(backtrace
从IBM示例派生的代码):
#include
#include
#include
#include
void sig_handler(int sig)
{
void * array[25];
int nSize = backtrace(array, 25);
char ** symbols = backtrace_symbols(array, nSize);
for (int i = 0; i < nSize; i++)
{
puts(symbols[i]);;
}
free(symbols);
signal(sig, &sig_handler);
}
void h()
{
kill(0, SIGSEGV);
}
void g()
{
h();
}
void f()
{
g();
}
int main(int argc, char ** argv)
{
signal(SIGSEGV, &sig_handler);
f();
}
输出:
0 a.out 0x00001f2d sig_handler + 35 1 libSystem.B.dylib 0x95f8f09b _sigtramp + 43 2 ??? 0xffffffff 0x0 + 4294967295 3 a.out 0x00001fb1 h + 26 4 a.out 0x00001fbe g + 11 5 a.out 0x00001fcb f + 11 6 a.out 0x00001ff5 main + 40 7 a.out 0x00001ede start + 54
这不会获得可选功能的奖励积分(除了不需要GUI),但是它确实具有非常简单的优点,并且不需要任何额外的库或程序.