0

I am doing some C++ programming on Mac OSX Lion, and want to print out stack trace when crashing or exception. In the following discussion, I tried both MacPort's gcc47 and apple's llvm-gcc42.

I came to use glog because it prints pretty stack trace. It looks fine the prints the following stack trace if I let the program crash by accessing a null pointer:

*** 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

However, if I crashed the program by throwing an exception, the stack trace printed out is not quite useful:

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

I tried the samething on a CentOS system and it prints out reasonable stack trace with uncaught exceptions, so it should not be a problem of glog.

So my question is: is there a way to let glog print out the stack trace for uncaught exceptions?

Kan Li
  • 8,557
  • 8
  • 53
  • 93
  • This is not an answer to making glog work, but you might consider DTrace, which may also give what you want. There is no need to compile something into a program, or compile for debug. It can be used on existing programs. some references: [Oracle/Sun DTrace](http://docs.oracle.com/cd/E19253-01/817-6223/chp-actsub-ustack/index.html) and [MacTech DTrace](http://www.mactech.com/articles/mactech/Vol.23/23.11/ExploringLeopardwithDTrace/index.html) there are several pages of 'DTrace one liners' on the web which might give you want you want (using ustack). It is extremely useful. – gbulmer Apr 01 '12 at 13:57
  • For completeness, the OP appears to have filed this as a bug with google-glog [here](http://code.google.com/p/google-glog/issues/detail?id=120). Hopefully, someone from Google will address question directly. – MrGomez Apr 06 '12 at 07:03
  • @MrGomez, it was me who pasted on the google-glog issue. – Kan Li Apr 06 '12 at 17:38
  • @icando Yep! By "the OP," I mean "the original poster [on this question thread]." It just seemed helpful to link the two together, because if we find a solution here, they should also be informed of it. :) – MrGomez Apr 06 '12 at 18:18

2 Answers2

0

In short: try installing libunwind and rebuilding google-glog to see if this resolves your issue. This dependency appears to be given by the OSX SDK at the time of this writing.

From stacktrace.cc (later moved to 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().

And in the latter file:

#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

Rebuilding with libunwind available should allow it to take precedence over your stack traces. If this doesn't resolve the issue, the programmers behind both tools should be informed.

MrGomez
  • 23,788
  • 45
  • 72
  • I tried that, but seems like building the open source libunwind is difficult right now on MacOSX, because the open source version only works on elf, not the Mach-O. I might have to modify a lot of code in libunwind if I want to make it build on MacOSX. On the other hand, MacOSX does provide an libunwind at /usr/lib/system/libunwind.dylib, but I have no idea how it can be used by google-glog, because a small test program says ``ld: cannot link directly with /usr/lib/system/libunwind.dylib. Link against the umbrella framework 'System.framework' instead. for architecture x86_64'' – Kan Li Apr 06 '12 at 17:46
  • see this post, for reference: http://lists.gnu.org/archive/html/libunwind-devel/2010-03/msg00000.html – Kan Li Apr 06 '12 at 17:49
  • @icando You're correct, vanilla libunwind explodes violently when you attempt to compile it into an x86_64 Mach-O. However, I note Apple provides [this source for libunwind](http://www.opensource.apple.com/source/libunwind/) ([download link](http://www.opensource.apple.com/tarballs/libunwind/libunwind-30.tar.gz)), which appears to have Mach-O support and [fix bugs in GCC](http://www.opensource.apple.com/source/libunwind/libunwind-30/include/unwind.h). I'm going to give it a spin here to see if it works on my iMac. If it does, I'll update my answer. – MrGomez Apr 06 '12 at 19:01
  • @icando I was able to successfully get glog built against `stacktrace_libunwind-inl.h` on my system. However, I'm running 10.6.8, so this is against `/Developer/SDKs/MacOSX10.6.sdk/usr/include/libunwind.h`. I'll update my answer, for now. – MrGomez Apr 06 '12 at 19:55
  • it doesn't work for me. What's your output of a program that has an uncaught exception? I wonder if I missed something. Basically I just compiled libunwind source you gave with g++ 4.7 and generated a libunwind.dylib, and then build glog against it. It builds successfully but the output of uncaught exception still doesn't contain the correct stack trace. – Kan Li Apr 14 '12 at 20:19
  • @icando You're correct -- even with libunwind, I can't get it to step out of the exception frame and print more verbose information when I use `google::InstallFailureSignalHandler` and crash my program with an unhandled exception. How embarrassing. If this is indeed a regression, yes, Google should fix it. – MrGomez Apr 14 '12 at 23:39
0

As of OS X 10.6, the NSException class has a -callStackSymbols and a -callStackReturnAddresses method which should let you retrieve the stack track as it was at the time the exception was thrown. If you want to use that same mechanism for non-exception errors, take a look at Controlling a Program’s Response to Exceptions in the Apple documentation. I haven't tried this with C++ exceptions, but the docs claim that at least in the 64-bit runtime, Objective-C and C++ exceptions are interoperable, so it's at least worth a shot.

Brian Webster
  • 11,915
  • 4
  • 44
  • 58