C++ 当我的程序崩溃时如何自动生成堆栈跟踪
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/77005/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to automatically generate a stacktrace when my program crashes
提问by KPexEA
I am working on Linux with the GCC compiler. When my C++ program crashes I would like it to automatically generate a stacktrace.
我正在使用 GCC 编译器在 Linux 上工作。当我的 C++ 程序崩溃时,我希望它自动生成堆栈跟踪。
My program is being run by many different users and it also runs on Linux, Windows and Macintosh (all versions are compiled using gcc
).
我的程序由许多不同的用户运行,它也可以在 Linux、Windows 和 Macintosh 上运行(所有版本都使用 编译gcc
)。
I would like my program to be able to generate a stack trace when it crashes and the next time the user runs it, it will ask them if it is ok to send the stack trace to me so I can track down the problem. I can handle the sending the info to me but I don't know how to generate the trace string. Any ideas?
我希望我的程序能够在崩溃时生成堆栈跟踪,下次用户运行它时,它会询问他们是否可以将堆栈跟踪发送给我,以便我可以追踪问题。我可以处理向我发送信息,但我不知道如何生成跟踪字符串。有任何想法吗?
采纳答案by Todd Gamblin
For Linux and I believe Mac OS X, if you're using gcc, or any compiler that uses glibc, you can use the backtrace() functions in execinfo.h
to print a stacktrace and exit gracefully when you get a segmentation fault. Documentation can be found in the libc manual.
对于 Linux 和我相信 Mac OS X,如果您使用 gcc 或任何使用 glibc 的编译器,您可以使用 backtrace() 函数execinfo.h
来打印堆栈跟踪并在遇到分段错误时优雅地退出。文档可以在 libc 手册中找到。
Here's an example program that installs a SIGSEGV
handler and prints a stacktrace to stderr
when it segfaults. The baz()
function here causes the segfault that triggers the handler:
这是一个示例程序,它安装SIGSEGV
处理程序并在出现段错误stderr
时打印堆栈跟踪。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.
}
Compiling with -g -rdynamic
gets you symbol info in your output, which glibc can use to make a nice stacktrace:
编译-g -rdynamic
会在你的输出中获取符号信息,glibc 可以使用它来制作一个很好的堆栈跟踪:
$ gcc -g -rdynamic ./test.c -o test
Executing this gets you this output:
执行这个会得到这个输出:
$ ./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]
This shows the load module, offset, and function that each frame in the stack came from. Here you can see the signal handler on top of the stack, and the libc functions before main
in addition to main
, foo
, bar
, and baz
.
这显示了堆栈中每个帧来自的加载模块、偏移量和函数。在这里你可以看到在堆栈的顶部,libc函数信号处理程序之前main
,除了main
,foo
,bar
,和baz
。
回答by jhclark
It's even easier than "man backtrace", there's a little-documented library (GNU specific) distributed with glibc as libSegFault.so, which was I believe was written by Ulrich Drepper to support the program catchsegv (see "man catchsegv").
它比“man backtrace”更容易,有一个很少记录的库(GNU 特定的)与 glibc 一起分发为 libSegFault.so,我相信它是由 Ulrich Drepper 编写的,用于支持程序 catchsegv(参见“man catchsegv”)。
This gives us 3 possibilities. Instead of running "program -o hai":
这给了我们 3 种可能性。而不是运行“program -o hai”:
Run within catchsegv:
$ catchsegv program -o hai
Link with libSegFault at runtime:
$ LD_PRELOAD=/lib/libSegFault.so program -o hai
Link with libSegFault at compile time:
$ gcc -g1 -lSegFault -o program program.cc $ program -o hai
在 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
In all 3 cases, you will get clearer backtraces with less optimization (gcc -O0 or -O1) and debugging symbols (gcc -g). Otherwise, you may just end up with a pile of memory addresses.
在所有 3 种情况下,您将通过较少的优化(gcc -O0 或 -O1)和调试符号(gcc -g)获得更清晰的回溯。否则,您可能只会得到一堆内存地址。
You can also catch more signals for stack traces with something like:
您还可以使用以下内容为堆栈跟踪捕获更多信号:
$ export SEGFAULT_SIGNALS="all" # "all" signals
$ export SEGFAULT_SIGNALS="bus abrt" # SIGBUS and SIGABRT
The output will look something like this (notice the backtrace at the bottom):
输出看起来像这样(注意底部的回溯):
*** 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]
If you want to know the gory details, the best source is unfortunately the source: See http://sourceware.org/git/?p=glibc.git;a=blob;f=debug/segfault.cand its parent directory http://sourceware.org/git/?p=glibc.git;a=tree;f=debug
如果你想知道血腥的细节,不幸的是最好的来源是来源:参见http://sourceware.org/git/?p=glibc.git;a=blob;f=debug/segfault.c及其父目录http://sourceware.org/git/?p=glibc.git;a=tree;f=debug
回答by jschmier
Linux
Linux
While the use of the backtrace() functions in execinfo.h to print a stacktrace and exit gracefully when you get a segmentation fault has already been suggested, I see no mention of the intricacies necessary to ensure the resulting backtrace points to the actual location of the fault (at least for some architectures - x86 & ARM).
虽然使用回溯()的execinfo.h功能,当你得到一个分段错误打印堆栈跟踪和正常退出也已经提出,我认为没有必要提及的复杂性,以确保所产生的回溯点的实际位置错误(至少对于某些架构 - x86 和 ARM)。
The first two entries in the stack frame chain when you get into the signal handler contain a return address inside the signal handler and one inside sigaction() in libc. The stack frame of the last function called before the signal (which is the location of the fault) is lost.
当您进入信号处理程序时,堆栈帧链中的前两个条目在信号处理程序中包含一个返回地址,在 libc 中的 sigaction() 中包含一个返回地址。信号之前调用的最后一个函数的栈帧(也就是故障的位置)丢失了。
Code
代码
#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);
}
Output
输出
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]
All the hazards of calling the backtrace() functions in a signal handler still exist and should not be overlooked, but I find the functionality I described here quite helpful in debugging crashes.
在信号处理程序中调用 backtrace() 函数的所有危险仍然存在,不应被忽视,但我发现我在此处描述的功能对调试崩溃非常有帮助。
It is important to note that the example I provided is developed/tested on Linux for x86. I have also successfully implemented this on ARM using uc_mcontext.arm_pc
instead of uc_mcontext.eip
.
需要注意的是,我提供的示例是在 Linux 上为 x86 开发/测试的。我也成功地在 ARM 上使用uc_mcontext.arm_pc
而不是uc_mcontext.eip
.
Here's a link to the article where I learned the details for this implementation: http://www.linuxjournal.com/article/6391
这是我了解此实现详细信息的文章的链接:http: //www.linuxjournal.com/article/6391
回答by jschmier
Even though a correct answerhas been provided that describes how to use the GNU libc backtrace()
function1and I provided my own answerthat describes how to ensure a backtrace from a signal handler points to the actual location of the fault2, I don't see any mention of demanglingC++ symbols output from the backtrace.
尽管已经提供了一个正确的答案来描述如何使用 GNU libcbacktrace()
函数1并且我提供了我自己的答案来描述如何确保从信号处理程序的回溯指向故障的实际位置2,我没有看到任何提及从回溯输出的demanglingC++ 符号。
When obtaining backtraces from a C++ program, the output can be run through c++filt
1to demangle the symbols or by using abi::__cxa_demangle
1directly.
从 C++ 程序中获取回溯时,可以通过c++filt
1运行输出以对符号进行解码或直接使用1。abi::__cxa_demangle
- 1Linux & OS X
Note that
c++filt
and__cxa_demangle
are GCC specific - 2Linux
- 1Linux & OS X
请注意,
c++filt
和__cxa_demangle
是特定于 GCC 的 - 2Linux
The following C++ Linux example uses the same signal handler as my other answerand demonstrates how c++filt
can be used to demangle the symbols.
以下 C++ Linux 示例使用与我的其他答案相同的信号处理程序,并演示了如何c++filt
对符号进行解构。
Code:
代码:
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;
}
Output(./test
):
输出( ./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
):
去重输出( ./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]
The following builds on the signal handler from my original answerand can replace the signal handler in the above example to demonstrate how abi::__cxa_demangle
can be used to demangle the symbols. This signal handler produces the same demangled output as the above example.
以下内容基于我的原始答案中的信号处理程序,可以替换上面示例中的信号处理程序,以演示如何abi::__cxa_demangle
使用对符号进行解构。此信号处理程序产生与上述示例相同的解角输出。
Code:
代码:
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++ = '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;
';
*offset_begin++ = '#!/bin/bash
LOGFILE=
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
';
*offset_end++ = '$ g++ -g prog.cpp -o prog
';
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);
}
回答by Simon Steele
Might be worth looking at Google Breakpad, a cross-platform crash dump generator and tools to process the dumps.
可能值得一看Google Breakpad,这是一个跨平台的故障转储生成器和处理转储的工具。
回答by Brian Mitchell
You did not specify your operating system, so this is difficult to answer. If you are using a system based on gnu libc, you might be able to use the libc function backtrace()
.
你没有指定你的操作系统,所以这很难回答。如果您使用的是基于 gnu libc 的系统,您或许可以使用 libc 函数backtrace()
。
GCC also has two builtins that can assist you, but which may or may not be implemented fully on your architecture, and those are __builtin_frame_address
and __builtin_return_address
. Both of which want an immediate integer level (by immediate, I mean it can't be a variable). If __builtin_frame_address
for a given level is non-zero, it should be safe to grab the return address of the same level.
GCC 也有两个内置函数可以帮助您,但它们可能会或可能不会在您的架构上完全实现,它们是__builtin_frame_address
和__builtin_return_address
。两者都需要立即整数级别(立即数,我的意思是它不能是变量)。如果__builtin_frame_address
给定级别不为零,则获取同一级别的返回地址应该是安全的。
回答by arr_sea
Thank you to enthusiasticgeek for drawing my attention to the addr2line utility.
感谢热心人让我注意到 addr2line 实用程序。
I've written a quick and dirty script to process the output of the answer provided here: (much thanks to jschmier!) using the addr2line utility.
我已经编写了一个快速而肮脏的脚本来处理这里提供的答案的输出:(非常感谢 jschmier!)使用 addr2line 实用程序。
The script accepts a single argument: The name of the file containing the output from jschmier's utility.
该脚本接受一个参数:包含 jschmier 实用程序输出的文件的名称。
The output should print something like the following for each level of the trace:
对于跟踪的每个级别,输出应打印如下内容:
$ gdb ./prog
... gdb startup output ...
(gdb) run
... program runs and crashes ...
(gdb) where
... gdb outputs your stack trace ...
Code:
代码:
##代码##回答by arr_sea
ulimit -c <value>
sets the core file size limit on unix. By default, the core file size limit is 0. You can see your ulimit
values with ulimit -a
.
ulimit -c <value>
在 unix 上设置核心文件大小限制。默认情况下,核心文件大小限制为 0。您可以ulimit
使用ulimit -a
.
also, if you run your program from within gdb, it will halt your program on "segmentation violations" (SIGSEGV
, generally when you accessed a piece of memory that you hadn't allocated) or you can set breakpoints.
此外,如果您从 gdb 中运行您的程序,它会因“分段违规”而停止您的程序(SIGSEGV
通常是当您访问一块尚未分配的内存时),或者您可以设置断点。
ddd and nemiver are front-ends for gdb which make working with it much easier for the novice.
ddd 和 nemiver 是 gdb 的前端,这使得新手更容易使用它。
回答by Gregory
Ive been looking at this problem for a while.
我一直在研究这个问题一段时间。
And buried deep in the Google Performance Tools README
并深埋在 Google Performance Tools README 中
http://code.google.com/p/google-perftools/source/browse/trunk/README
http://code.google.com/p/google-perftools/source/browse/trunk/README
talks about libunwind
谈论 libunwind
http://www.nongnu.org/libunwind/
http://www.nongnu.org/libunwind/
Would love to hear opinions of this library.
很想听听这个图书馆的意见。
The problem with -rdynamic is that it can increase the size of the binary relatively significantly in some cases
-rdynamic 的问题是在某些情况下它可以相对显着地增加二进制文件的大小
回答by Benson
It's important to note that once you generate a core file you'll need to use the gdb tool to look at it. For gdb to make sense of your core file, you must tell gcc to instrument the binary with debugging symbols: to do this, you compile with the -g flag:
需要注意的是,一旦你生成了一个核心文件,你就需要使用 gdb 工具来查看它。为了让 gdb 理解你的核心文件,你必须告诉 gcc 用调试符号检测二进制文件:为此,你用 -g 标志编译:
##代码##Then, you can either set "ulimit -c unlimited" to let it dump a core, or just run your program inside gdb. I like the second approach more:
然后,您可以设置“ulimit -c unlimited”以让它转储核心,或者只是在 gdb 中运行您的程序。我更喜欢第二种方法:
##代码##I hope this helps.
我希望这有帮助。