Mac OSX上未捕获异常时的回溯

Backtracing when uncaught exception on Mac OSX

本文关键字:回溯 捕获异常 OSX Mac      更新时间:2023-10-16

我正在Mac OSX Lion上进行一些C++编程,希望在崩溃或异常时打印出堆栈跟踪。在下面的讨论中,我尝试了MacPort的gcc47和苹果的llvm-gcc42。

我开始使用glog,因为它可以打印出漂亮的堆栈痕迹。如果我通过访问空指针让程序崩溃,那么打印以下堆栈跟踪看起来很好:

*** Aborted at 1333289352 (unix time) try "date -d @1333289352" if you are using GNU date ***
PC: @        0x1091a9137 C::h()
*** SIGSEGV (@0x0) received by PID 29623 (TID 0x7fff722d4960) stack trace: ***
    @     0x7fff8cabdcfa _sigtramp
    @        0x1091a9138 C::h()
    @        0x1091a9112 C::g()
    @        0x1091a90ef C::f()
    @        0x1091a903a main
Segmentation fault: 11

然而,如果我抛出异常导致程序崩溃,那么打印出来的堆栈跟踪就不太有用了:

terminate called after throwing an instance of 'std::runtime_error'
  what():  Haha
*** Aborted at 1333289406 (unix time) try "date -d @1333289406" if you are using GNU date ***
PC: @     0x7fff8450f82a __kill
*** SIGABRT (@0x7fff8450f82a) received by PID 52106 (TID 0x7fff722d4960) stack trace: ***
    @     0x7fff8cabdcfa _sigtramp
Abort trap: 6

我在一个CentOS系统上尝试了同样的方法,它打印出了合理的堆栈跟踪和未捕获的异常,所以这应该不是glog的问题。

所以我的问题是:有没有办法让glog打印出未捕获异常的堆栈跟踪?

简而言之:试着安装libunvent并重建googleglog,看看这是否能解决您的问题。这种依赖关系似乎是在撰写本文时由OSX SDK提供的。

stacktrace.cc(后来移到utilities.h):

// There are three different ways we can try to get the stack trace:
//
// 1) Our hand-coded stack-unwinder.  This depends on a certain stack
//    layout, which is used by gcc (and those systems using a
//    gcc-compatible ABI) on x86 systems, at least since gcc 2.95.
//    It uses the frame pointer to do its work.
//
// 2) The libunwind library.  This is still in development, and as a
//    separate library adds a new dependency, abut doesn't need a frame
//    pointer.  It also doesn't call malloc.
//
// 3) The gdb unwinder -- also the one used by the c++ exception code.
//    It's obviously well-tested, but has a fatal flaw: it can call
//    malloc() from the unwinder.  This is a problem because we're
//    trying to use the unwinder to instrument malloc().

在后一个文件中:

#if defined(HAVE_LIB_UNWIND)
# define STACKTRACE_H "stacktrace_libunwind-inl.h"
#elif !defined(NO_FRAME_POINTER)
# if defined(__i386__) && __GNUC__ >= 2
#  define STACKTRACE_H "stacktrace_x86-inl.h"
# elif defined(__x86_64__) && __GNUC__ >= 2
#  define STACKTRACE_H "stacktrace_x86_64-inl.h"
# elif (defined(__ppc__) || defined(__PPC__)) && __GNUC__ >= 2
#  define STACKTRACE_H "stacktrace_powerpc-inl.h"
# endif
#endif
#if !defined(STACKTRACE_H) && defined(HAVE_EXECINFO_H)
# define STACKTRACE_H "stacktrace_generic-inl.h"
#endif
#if defined(STACKTRACE_H)
# define HAVE_STACKTRACE
#endif

使用libunfold进行重建应该可以使其优先于堆栈跟踪。如果这不能解决问题,那么应该通知这两个工具背后的程序员。

从OS X 10.6开始,NSException类有一个-callStackSymbols和一个-callStackReturnAddresses方法,该方法应允许您检索抛出异常时的堆栈轨迹。如果您想对非异常错误使用相同的机制,请参阅Apple文档中的"控制程序对异常的响应"。我还没有在C++异常中尝试过,但文档声称,至少在64位运行时,Objective-C和C++异常是可互操作的,所以这至少值得一试。