如何自动生成一个堆栈跟踪的时候我的程序崩溃了
-
09-06-2019 - |
题
我的工作Linux与海湾合作委员会编译器。当我的C++程序崩溃了,我想它来自动产生一个堆栈跟踪.
我的程序是由许多不同的用户和它也运行在Linux上,窗户和Macintosh(所有版本的编制使用 gcc
).
我想我的节目能够产生一堆跟踪在它崩溃,并在下一次的用户运行,它将要求他们,如果它是确定发送堆跟踪我这样我就可以追踪的问题。我可以处理的发送信息给我的但我不知道如何产生的微量串。任何想法?
解决方案
为Linux而且我相信Mac OS X,如果使用的海湾合作委员会,或任何编译器使用的glibc,可以使用的回溯追踪()职能 execinfo.h
打印一个堆栈跟踪和退出正常的时候你会得到一个分割的错误。文件中可以找到 在libc手册.
这里有一个例子程序,安装了一个 SIGSEGV
处理和打印一个堆栈跟踪到 stderr
当它segfaults.的 baz()
能这里会导致出现段错误触发的处理程序:
#include <stdio.h>
#include <execinfo.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
void handler(int sig) {
void *array[10];
size_t size;
// get void*'s for all entries on the stack
size = backtrace(array, 10);
// print out all the frames to stderr
fprintf(stderr, "Error: signal %d:\n", sig);
backtrace_symbols_fd(array, size, STDERR_FILENO);
exit(1);
}
void baz() {
int *foo = (int*)-1; // make a bad pointer
printf("%d\n", *foo); // causes segfault
}
void bar() { baz(); }
void foo() { bar(); }
int main(int argc, char **argv) {
signal(SIGSEGV, handler); // install our handler
foo(); // this will call foo, bar, and baz. baz segfaults.
}
编译 -g -rdynamic
得到你的符号的信息在输出,这glibc可以用来做一个很好的堆栈跟踪:
$ gcc -g -rdynamic ./test.c -o test
执行这得到你这个输出:
$ ./test
Error: signal 11:
./test(handler+0x19)[0x400911]
/lib64/tls/libc.so.6[0x3a9b92e380]
./test(baz+0x14)[0x400962]
./test(bar+0xe)[0x400983]
./test(foo+0xe)[0x400993]
./test(main+0x28)[0x4009bd]
/lib64/tls/libc.so.6(__libc_start_main+0xdb)[0x3a9b91c4bb]
./test[0x40086a]
这显示了载荷的模块,偏移和功能,每个框架中叠。在这里你可以看到信号处理程序上的堆,并libc功能之前 main
除了 main
, foo
, bar
, , baz
.
其他提示
Linux
而采用的回溯追踪()职能在execinfo.h以打印一个堆栈跟踪和退出正常的时候你会得到一个分割的一个错误 已经建议, 我看到没有提及的复杂性,有必要确保所得到的回溯点的实际位置的错误(至少对于一些结构-x86&臂)。
前两项在栈框架链时得到的信号处理程序包含一个退回的地址内的信号处理程序和一个内部sigaction()在libc.堆框架的最后一个功能称之前的号(其故障的位置)损失。
代码
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#ifndef __USE_GNU
#define __USE_GNU
#endif
#include <execinfo.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ucontext.h>
#include <unistd.h>
/* This structure mirrors the one found in /usr/include/asm/ucontext.h */
typedef struct _sig_ucontext {
unsigned long uc_flags;
struct ucontext *uc_link;
stack_t uc_stack;
struct sigcontext uc_mcontext;
sigset_t uc_sigmask;
} sig_ucontext_t;
void crit_err_hdlr(int sig_num, siginfo_t * info, void * ucontext)
{
void * array[50];
void * caller_address;
char ** messages;
int size, i;
sig_ucontext_t * uc;
uc = (sig_ucontext_t *)ucontext;
/* Get the address at the time the signal was raised */
#if defined(__i386__) // gcc specific
caller_address = (void *) uc->uc_mcontext.eip; // EIP: x86 specific
#elif defined(__x86_64__) // gcc specific
caller_address = (void *) uc->uc_mcontext.rip; // RIP: x86_64 specific
#else
#error Unsupported architecture. // TODO: Add support for other arch.
#endif
fprintf(stderr, "signal %d (%s), address is %p from %p\n",
sig_num, strsignal(sig_num), info->si_addr,
(void *)caller_address);
size = backtrace(array, 50);
/* overwrite sigaction with caller's address */
array[1] = caller_address;
messages = backtrace_symbols(array, size);
/* skip first stack frame (points here) */
for (i = 1; i < size && messages != NULL; ++i)
{
fprintf(stderr, "[bt]: (%d) %s\n", i, messages[i]);
}
free(messages);
exit(EXIT_FAILURE);
}
int crash()
{
char * p = NULL;
*p = 0;
return 0;
}
int foo4()
{
crash();
return 0;
}
int foo3()
{
foo4();
return 0;
}
int foo2()
{
foo3();
return 0;
}
int foo1()
{
foo2();
return 0;
}
int main(int argc, char ** argv)
{
struct sigaction sigact;
sigact.sa_sigaction = crit_err_hdlr;
sigact.sa_flags = SA_RESTART | SA_SIGINFO;
if (sigaction(SIGSEGV, &sigact, (struct sigaction *)NULL) != 0)
{
fprintf(stderr, "error setting signal handler for %d (%s)\n",
SIGSEGV, strsignal(SIGSEGV));
exit(EXIT_FAILURE);
}
foo1();
exit(EXIT_SUCCESS);
}
输出
signal 11 (Segmentation fault), address is (nil) from 0x8c50
[bt]: (1) ./test(crash+0x24) [0x8c50]
[bt]: (2) ./test(foo4+0x10) [0x8c70]
[bt]: (3) ./test(foo3+0x10) [0x8c8c]
[bt]: (4) ./test(foo2+0x10) [0x8ca8]
[bt]: (5) ./test(foo1+0x10) [0x8cc4]
[bt]: (6) ./test(main+0x74) [0x8d44]
[bt]: (7) /lib/libc.so.6(__libc_start_main+0xa8) [0x40032e44]
所有的危险的呼吁的回溯追踪()职能在一个信号处理程序仍然存在,并且不应忽视,但是我找到的功能,我所描述的在这里相当有助于调试崩溃。
重要的是要注意,如我提供的是发达的/试验在Linux为x86。我们还成功地实现了这个手臂上使用 uc_mcontext.arm_pc
而不是的 uc_mcontext.eip
.
这里有一个链接到文章里我学到的详细信息对于这一执行情况:http://www.linuxjournal.com/article/6391
它甚至更加容易的不是"男人回溯",有一点点记录的库(GNU具体)发布的glibc为libSegFault.所以,这是我相信是由乌尔里希Drepper支持该方案catchsegv(见"人catchsegv").
这给我们3个可能性。而不是运行的"计划-o海":
内运行catchsegv:
$ catchsegv program -o hai
链接与libSegFault在运行时:
$ LD_PRELOAD=/lib/libSegFault.so program -o hai
链接与libSegFault在编制时间:
$ gcc -g1 -lSegFault -o program program.cc $ program -o hai
在所有3起案件中,你将得到更清晰的跟踪用不优化(海湾合作委员会-O0或-O1)和调试的符号(海湾合作委员会-g)。否则,你可能刚刚结束了一堆存的地址。
你也可以捕捉更多的信号叠的痕迹喜欢的东西:
$ export SEGFAULT_SIGNALS="all" # "all" signals
$ export SEGFAULT_SIGNALS="bus abrt" # SIGBUS and SIGABRT
输出将这样的事情(通知的回溯在底部):
*** Segmentation fault Register dump:
EAX: 0000000c EBX: 00000080 ECX:
00000000 EDX: 0000000c ESI:
bfdbf080 EDI: 080497e0 EBP:
bfdbee38 ESP: bfdbee20
EIP: 0805640f EFLAGS: 00010282
CS: 0073 DS: 007b ES: 007b FS:
0000 GS: 0033 SS: 007b
Trap: 0000000e Error: 00000004
OldMask: 00000000 ESP/signal:
bfdbee20 CR2: 00000024
FPUCW: ffff037f FPUSW: ffff0000
TAG: ffffffff IPOFF: 00000000
CSSEL: 0000 DATAOFF: 00000000
DATASEL: 0000
ST(0) 0000 0000000000000000 ST(1)
0000 0000000000000000 ST(2) 0000
0000000000000000 ST(3) 0000
0000000000000000 ST(4) 0000
0000000000000000 ST(5) 0000
0000000000000000 ST(6) 0000
0000000000000000 ST(7) 0000
0000000000000000
Backtrace:
/lib/libSegFault.so[0xb7f9e100]
??:0(??)[0xb7fa3400]
/usr/include/c++/4.3/bits/stl_queue.h:226(_ZNSt5queueISsSt5dequeISsSaISsEEE4pushERKSs)[0x805647a]
/home/dbingham/src/middle-earth-mud/alpha6/src/engine/player.cpp:73(_ZN6Player5inputESs)[0x805377c]
/home/dbingham/src/middle-earth-mud/alpha6/src/engine/socket.cpp:159(_ZN6Socket4ReadEv)[0x8050698]
/home/dbingham/src/middle-earth-mud/alpha6/src/engine/socket.cpp:413(_ZN12ServerSocket4ReadEv)[0x80507ad]
/home/dbingham/src/middle-earth-mud/alpha6/src/engine/socket.cpp:300(_ZN12ServerSocket4pollEv)[0x8050b44]
/home/dbingham/src/middle-earth-mud/alpha6/src/engine/main.cpp:34(main)[0x8049a72]
/lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe5)[0xb7d1b775]
/build/buildd/glibc-2.9/csu/../sysdeps/i386/elf/start.S:122(_start)[0x8049801]
如果你想知道细节,最佳来源是很不幸的资料来源:看看 http://sourceware.org/git/?p=glibc.git;a=blob;f=debug/出现段错误.c 与其父目录 http://sourceware.org/git/?p=glibc.git;a=树;f="调试"
即使一个 正确的答案 已经提供,介绍如何使用的GNU libc backtrace()
功能1 和我提供的 我自己的答案 介绍了如何确保回溯追踪信号处理点的实际位置的故障2, 我没有看到任何提及 demangling C++符输出的回溯追踪.
当获得的跟踪从C++程序,输出可以通过运行 c++filt
1 到demangle的符号或通过使用 abi::__cxa_demangle
1 直接。
- 1 Linux和OS X
注意,
c++filt
和__cxa_demangle
是海湾合作委员会特 - 2 Linux
以下C++Linux例如使用同一信号处理程序作为我的 其他的答案 和演示如何 c++filt
可以用来demangle的符号。
代码:
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输出 (./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
可以用来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);
}
可能是值得看的 谷歌Breakpad, 截平台崩溃转储生和工具,以处理垃圾场。
你没有指定你的操作系统,因此,这是难以回答。如果您使用的一个系统基于gnu libc,你可能可以使用libc功能 backtrace()
.
海湾合作委员会还有两个内置,可以帮助你,但是可能或可能不能充分实施,在你的架构,而这些都是 __builtin_frame_address
和 __builtin_return_address
.这两者都想要立即整数等级(通过直接的,我的意思是这不可能是一个变量)。如果 __builtin_frame_address
一定水平的非零,它应该是安全的拿回返地址相同的水平。
ulimit -c <value>
套核心文件的尺寸限制unix。默认情况下,该核心文件的尺寸限制为0。你可以看到你 ulimit
值 ulimit -a
.
此外,如果运行程序从内的库,它将停止你的节目在"分割的侵犯"(SIGSEGV
,通常当你访问的一片记忆,你没有分配)或可设定的断点。
ddd和nemiver是前结束对库,这使得与它的工作更加容易的新手。
谢谢你enthusiasticgeek用于绘画我注意到addr2line实用工具。
我已经写了一个快速和肮脏的剧本给过程的输出答复提供 在这里,:(很多感谢jschmier!) 使用addr2line实用工具。
脚本接受一个参数:该文件的名称含有输出jschmier的实用工具。
本应该打印输出的东西喜欢的以下各级的跟踪:
BACKTRACE: testExe 0x8A5db6b
FILE: pathToFile/testExe.C:110
FUNCTION: testFunction(int)
107
108
109 int* i = 0x0;
*110 *i = 5;
111
112 }
113 return i;
代码:
#!/bin/bash
LOGFILE=$1
NUM_SRC_CONTEXT_LINES=3
old_IFS=$IFS # save the field separator
IFS=$'\n' # new field separator, the end of line
for bt in `cat $LOGFILE | grep '\[bt\]'`; do
IFS=$old_IFS # restore default field separator
printf '\n'
EXEC=`echo $bt | cut -d' ' -f3 | cut -d'(' -f1`
ADDR=`echo $bt | cut -d'[' -f3 | cut -d']' -f1`
echo "BACKTRACE: $EXEC $ADDR"
A2L=`addr2line -a $ADDR -e $EXEC -pfC`
#echo "A2L: $A2L"
FUNCTION=`echo $A2L | sed 's/\<at\>.*//' | cut -d' ' -f2-99`
FILE_AND_LINE=`echo $A2L | sed 's/.* at //'`
echo "FILE: $FILE_AND_LINE"
echo "FUNCTION: $FUNCTION"
# print offending source code
SRCFILE=`echo $FILE_AND_LINE | cut -d':' -f1`
LINENUM=`echo $FILE_AND_LINE | cut -d':' -f2`
if ([ -f $SRCFILE ]); then
cat -n $SRCFILE | grep -C $NUM_SRC_CONTEXT_LINES "^ *$LINENUM\>" | sed "s/ $LINENUM/*$LINENUM/"
else
echo "File not found: $SRCFILE"
fi
IFS=$'\n' # new field separator, the end of line
done
IFS=$old_IFS # restore default field separator
重要的是要注意,一旦产生一个核心文件,则需要使用库工具来看待它。对于库,以有意义的核心文件,则必须告诉海湾合作委员会来文书的二进制调试的符号:要做到这一点,你编的-g的标志:
$ g++ -g prog.cpp -o prog
然后,你可以设定"限制-c无限制的"让它倾倒核心,或者只是运行程序的内部库.我喜欢第二种办法更多:
$ gdb ./prog
... gdb startup output ...
(gdb) run
... program runs and crashes ...
(gdb) where
... gdb outputs your stack trace ...
我希望这有所帮助。
我一直在寻找这个问题。
和深埋在谷歌的性能工具的自述
http://code.google.com/p/google-perftools/source/browse/trunk/README
谈libunwind
http://www.nongnu.org/libunwind/
很想听到的意见的这个图书馆。
问题-rdynamic是,它可以增加的大小进制比较显着,在某些情况下
某些版本的libc包含的功能,处理堆跟踪;你可能可以使用它们:
http://www.gnu.org/software/libc/manual/html_node/Backtraces.html
我记得使用 libunwind 很久以前获得堆叠的痕迹,但它不可能支持你的平台。
忘记关于改变你的来源,做一些黑客带回溯()function或macroses-这些都是贫穷的解决方案。
作为一个正常工作的解决方案,我建议:
- 编译程序"g"标志用于嵌入调试的符号是二进制的(不用担心这不会影响你的性能)。
- 运行在linux上的下命令:"限制-c无限"-让系统做出重大崩溃的垃圾场。
- 当你的程序的崩溃,在工作目录的你会看到的文件"核心"。
- 运行下一步命令的打印回溯到stdout:库批-ex"回溯"./your_program_exe./核心
这将打印适当的可读回溯追踪程序的在人可读方式(有源文件的名称和符号码)。而且这种方法会给你自由你的自动化系统:有一个简短的脚本,检查过程中创建了一个核倾倒,然后送跟踪以通过电子邮件开发人员或日志的这些记录系统。
ulimit -c unlimited
系统变量,这将允许建立一个核倾倒在您应用程序的崩溃。在这种情况下无限量。寻找一个文件,称为核心的非常相同的目录中。确保你已编译代码的调试进行的信息启用!
关于
赢得:怎么样StackWalk64 http://msdn.microsoft.com/en-us/library/ms680650.aspx
你可以使用 DeathHandler -小C++类为你做的一切,可靠。
看看:
3人回溯
并且:
#include <exeinfo.h>
int backtrace(void **buffer, int size);
这些都是GNU扩展。
看看这堆跟踪设施 ACE (适应性的通讯环境)。它已经编写涵盖所有主要平台(和更大)。图书馆是BSD式授权的所以你甚至可以复制、粘贴的代码如果你不想使用的王牌。
我可以帮助与Linux版本:功能回溯,backtrace_symbols和backtrace_symbols_fd可以使用。看到相应手册》的网页。
我发现@tgamblin解决方案是不完整的。它无法处理与计算器.我想是因为默认情况下信号处理程序被称为与同一堆和 "SIGSEGV"是引发两次。保护你不需要登记一个独立的堆的信号处理程序。
你可以检查这个代码如下。默认情况下的处理程序失败。与所定义的宏STACK_OVERFLOW它的所有权利。
#include <iostream>
#include <execinfo.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <string>
#include <cassert>
using namespace std;
//#define STACK_OVERFLOW
#ifdef STACK_OVERFLOW
static char stack_body[64*1024];
static stack_t sigseg_stack;
#endif
static struct sigaction sigseg_handler;
void handler(int sig) {
cerr << "sig seg fault handler" << endl;
const int asize = 10;
void *array[asize];
size_t size;
// get void*'s for all entries on the stack
size = backtrace(array, asize);
// print out all the frames to stderr
cerr << "stack trace: " << endl;
backtrace_symbols_fd(array, size, STDERR_FILENO);
cerr << "resend SIGSEGV to get core dump" << endl;
signal(sig, SIG_DFL);
kill(getpid(), sig);
}
void foo() {
foo();
}
int main(int argc, char **argv) {
#ifdef STACK_OVERFLOW
sigseg_stack.ss_sp = stack_body;
sigseg_stack.ss_flags = SS_ONSTACK;
sigseg_stack.ss_size = sizeof(stack_body);
assert(!sigaltstack(&sigseg_stack, nullptr));
sigseg_handler.sa_flags = SA_ONSTACK;
#else
sigseg_handler.sa_flags = SA_RESTART;
#endif
sigseg_handler.sa_handler = &handler;
assert(!sigaction(SIGSEGV, &sigseg_handler, nullptr));
cout << "sig action set" << endl;
foo();
return 0;
}
我会用这代码产生的一叠追踪泄露的存在 视觉的泄漏检测器.这只是工作上的Win32,虽然。
我已经看到了很多答案在这里进行一个信号处理程序,然后退出。这就是要走的道路,但要记住一个非常重要的事实:如果你想得到的核倾倒的产生错误的,你不能打电话 exit(status)
.呼叫 abort()
而不是!
新国王在城镇已经到来 https://github.com/bombela/backward-cpp
1头放在你的代码和1个图书馆安装。
我个人叫它使用这种功能
#include "backward.hpp"
void stacker() {
using namespace backward;
StackTrace st;
st.load_here(99); //Limit the number of trace depth to 99
st.skip_n_firsts(3);//This will skip some backward internal function from the trace
Printer p;
p.snippet = true;
p.object = true;
p.color = true;
p.address = true;
p.print(st, stderr);
}
除了上述答复,这里你怎么做Debian Linux操作系统产生的核心倾倒
- 创建一个"coredumps"文件夹中的用户的文件夹的家
- 去/etc/安全/限制。conf.下面的''线,型"软性核心无限制的",并"根柔软的核心无限制的"如果能使核心垃圾场为根,允许无限的空间核垃圾场。
- 注:"*柔软的核心无限制的"并不涵盖根源,这就是为什么根已被指定在其自己的线。
- 检查这些价值观,登出,登录和类型"限制-a"。"核心文件的尺寸的"应设置限制的。
- 检查。更改的文件(用户,并根如果适用),以确保限制不是设置在那里。否则,该值上面将被复盖上启动。
- 开/etc/则.conf.输入下面的底部:"核心。core_pattern=/home//coredumps/%e_%。转储"。(%的电子会进程名称,并%t将是该系统的时间)
- 出口和类型"时-p"载入新的配置 检查/proc/sys/核心/core_pattern和验证,这种比赛什么你只需输入。
- 核心倾倒可以测试通过执行某一过程的命令行("&"),然后杀了它与"杀死的-11".如果核心倾销是成功的,你会看见"(核心倾销)"之后的分段错误的指示。
作为一个窗户-唯一的解决办法,可以获得相当于一个堆栈(与很多,很多信息)的使用 Windows错误报告.只有几个注册表,它可能被设定为 收集用户模式的垃圾场:
开始带的Windows服务器2008年和Windows Vista with Service Pack1(sp1),Windows错误报告(WER)可以进行配置,以便满的用户模式转储收集和储存在本地的后用户模式应用程序的崩溃。[...]
这个功能未启用的默认。使的功能需要有管理员权限。启用和配置功能,使用以下注册的价值观下 此\软件\微软\Windows\Windows错误报告\LocalDumps 关键。
你可以设置的登记册条目从您的安装,其中有所需的权限。
创建一个用户模式转储有以下优点产生一堆跟踪对客户:
- 它已经实施的系统。你可以使用WER如上文所概述的,或打电话 MiniDumpWriteDump 你自己,如果你需要更多的细化控制的信息量倾倒。(一定要称它从一个不同的处理。)
- 方式 更完整的比堆踪。除其他外,它可以包含地方变量、功能的论点,成堆的其他线,装载的模块等等。数据的数量(和因此大小)是高度定制的。
- 不需要船舶的调试的符号。这两者都大幅减少部署的大小,以及使得它难以逆向工程应用程序。
- 很大程度上独立的编译器的使用。使用WER甚至不需要任何代码。无论哪种方式,具有办法得到一个符号的数据库(PDB)是 非常 用于离线分析。我相信,海湾合作委员会可以产生PDB的,或者有工具转换成符号的数据库,以PDB格式。
注意到,WER只能引发的应用程序的崩溃(即该系统终止一个进程由于未处理的例外)。 MiniDumpWriteDump
可以在任何时间。这可能是有益的,如果您需要转储的当前状态的诊断问题的其他比一个崩溃。
阅读的强制性,如果要评估的适用性的小垃圾场:
在Linux/unix/MacOSX使用的核心文件(你可以使他们能与限制或 兼容的系统,叫).在窗户使用微软的错误报告(你可以成为一个合作伙伴,并获得您的应用程序崩溃的数据)。
我忘了关于侏儒的新技术的"apport",但我不知道很多关于使用它。它是用来生成栈跟踪及其他诊断为处理可自动文件中的错误。这是值得肯定的检查。
它看起来像在一个最后的c++的升版出现了图书馆提供的正是你想要的,可能是代码是多平台.它是 提升::堆栈跟踪, 您可以使用它喜欢 作为在提高样:
#include <filesystem>
#include <sstream>
#include <fstream>
#include <signal.h> // ::signal, ::raise
#include <boost/stacktrace.hpp>
const char* backtraceFileName = "./backtraceFile.dump";
void signalHandler(int)
{
::signal(SIGSEGV, SIG_DFL);
::signal(SIGABRT, SIG_DFL);
boost::stacktrace::safe_dump_to(backtraceFileName);
::raise(SIGABRT);
}
void sendReport()
{
if (std::filesystem::exists(backtraceFileName))
{
std::ifstream file(backtraceFileName);
auto st = boost::stacktrace::stacktrace::from_dump(file);
std::ostringstream backtraceStream;
backtraceStream << st << std::endl;
// sending the code from st
file.close();
std::filesystem::remove(backtraceFileName);
}
}
int main()
{
::signal(SIGSEGV, signalHandler);
::signal(SIGABRT, signalHandler);
sendReport();
// ... rest of code
}
在Linux你汇编上述代码:
g++ --std=c++17 file.cpp -lstdc++fs -lboost_stacktrace_backtrace -ldl -lbacktrace
例回溯复制 提高文件:
0# bar(int) at /path/to/source/file.cpp:70
1# bar(int) at /path/to/source/file.cpp:70
2# bar(int) at /path/to/source/file.cpp:70
3# bar(int) at /path/to/source/file.cpp:70
4# main at /path/to/main.cpp:93
5# __libc_start_main in /lib/x86_64-linux-gnu/libc.so.6
6# _start
如果你仍然想去,因为我没有你可以链接 bfd
和避免使用 addr2line
因为我已经做了这里:
https://github.com/gnif/LookingGlass/blob/master/common/src/crash.linux.c
此产生的产出:
[E] crash.linux.c:170 | crit_err_hdlr | ==== FATAL CRASH (a12-151-g28b12c85f4+1) ====
[E] crash.linux.c:171 | crit_err_hdlr | signal 11 (Segmentation fault), address is (nil)
[E] crash.linux.c:194 | crit_err_hdlr | [trace]: (0) /home/geoff/Projects/LookingGlass/client/src/main.c:936 (register_key_binds)
[E] crash.linux.c:194 | crit_err_hdlr | [trace]: (1) /home/geoff/Projects/LookingGlass/client/src/main.c:1069 (run)
[E] crash.linux.c:194 | crit_err_hdlr | [trace]: (2) /home/geoff/Projects/LookingGlass/client/src/main.c:1314 (main)
[E] crash.linux.c:199 | crit_err_hdlr | [trace]: (3) /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xeb) [0x7f8aa65f809b]
[E] crash.linux.c:199 | crit_err_hdlr | [trace]: (4) ./looking-glass-client(_start+0x2a) [0x55c70fc4aeca]