Index: configure.ac ================================================================== --- configure.ac +++ configure.ac @@ -749,19 +749,31 @@ AS_IF([test x"$have_processes" = x"yes"], [ AC_SUBST(OFPROCESS_M, "OFProcess.m") AC_DEFINE(OF_HAVE_PROCESSES, 1, [Whether we have processes]) ]) -AC_MSG_CHECKING(for __builtin_return_address) -AC_TRY_LINK([], [ - __builtin_return_address(0); -], [ - AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_BUILTIN_RETURN_ADDRESS, 1, - [Whether we have __builtin_return_address]) -], [ - AC_MSG_RESULT(no) +AC_DEFUN([CHECK_BUILTIN_RETURN_ADDRESS], [ + AC_MSG_CHECKING(for __builtin_return_address) + AC_TRY_LINK([], [ + __builtin_return_address(1); + ], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_BUILTIN_RETURN_ADDRESS, 1, + [Whether we have __builtin_return_address]) + ], [ + AC_MSG_RESULT(no) + ]) +]) +AC_CHECK_HEADER(execinfo.h, [ + AC_DEFINE(HAVE_EXECINFO_H, 1, [Whether we have execinfo.h]) + AC_CHECK_FUNC(backtrace, [ + AC_DEFINE(HAVE_BACKTRACE, 1, [Whether we have backtrace()]) + ], [ + CHECK_BUILTIN_RETURN_ADDRESS + ]) +], [ + CHECK_BUILTIN_RETURN_ADDRESS ]) AS_IF([test x"$objc_runtime" = x"Apple runtime"], [ AC_CHECK_HEADER(Foundation/NSObject.h, [ AC_SUBST(FOUNDATION_COMPAT_M, "foundation-compat.m") Index: src/exceptions/OFException.h ================================================================== --- src/exceptions/OFException.h +++ src/exceptions/OFException.h @@ -27,11 +27,12 @@ * the OFAllocFailedException. */ @interface OFException: OFObject { Class _inClass; - void *_returnAddresses[32]; + void *_backtrace[32]; + int _backtraceSize; } #ifdef OF_HAVE_PROPERTIES @property (readonly) Class inClass; #endif Index: src/exceptions/OFException.m ================================================================== --- src/exceptions/OFException.m +++ src/exceptions/OFException.m @@ -16,10 +16,13 @@ #include "config.h" #include +#ifdef HAVE_EXECINFO_H +# include +#endif #ifdef HAVE_DLFCN_H # include #endif #import "OFException.h" @@ -49,20 +52,21 @@ - initWithClass: (Class)class { self = [super init]; _inClass = class; -#ifdef HAVE_BUILTIN_RETURN_ADDRESS +#if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) + _backtraceSize = backtrace(_backtrace, 32); +#elif defined(HAVE_BUILTIN_RETURN_ADDRESS) && defined(__ppc__) /* * We can't use a loop here, as __builtin_return_address() and * __builtin_frame_address() only allow a constant as parameter. */ -# define GET_FRAME(i) \ - if (__builtin_frame_address(i + 1) == NULL) \ - goto backtrace_done; \ - if ((_returnAddresses[i] = ( \ - __builtin_return_address(i))) == NULL) \ +# define GET_FRAME(i) \ + if (__builtin_frame_address(i + 1) == NULL) \ + goto backtrace_done; \ + if ((_backtrace[i] = (__builtin_return_address(i))) == NULL) \ goto backtrace_done; GET_FRAME(0) GET_FRAME(1) GET_FRAME(2) GET_FRAME(3) @@ -113,18 +117,45 @@ object_getClass(self), _inClass]; } - (OFArray*)backtrace { -#ifdef HAVE_BUILTIN_RETURN_ADDRESS +#if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) + OFMutableArray *backtrace = [OFMutableArray array]; + void *pool = objc_autoreleasePoolPush(); + char **symbols; + + if (_backtraceSize < 0) + return nil; + + symbols = backtrace_symbols(_backtrace, _backtraceSize); + @try { + int i; + + for (i = 0; i < _backtraceSize; i++) { + OFString *symbol = [OFString + stringWithCString: symbols[i] + encoding: OF_STRING_ENCODING_NATIVE]; + [backtrace addObject: symbol]; + } + } @finally { + free(symbols); + } + + objc_autoreleasePoolPop(pool); + + [backtrace makeImmutable]; + + return backtrace; +#elif defined(HAVE_BUILTIN_RETURN_ADDRESS) && defined(__ppc__) OFMutableArray *backtrace = [OFMutableArray array]; void *pool = objc_autoreleasePoolPush(); uint_fast8_t i; - for (i = 0; i < 32 && _returnAddresses[i] != NULL; i++) { + for (i = 0; i < 32 && _backtrace[i] != NULL; i++) { void *addr = - __builtin_extract_return_addr(_returnAddresses[i]); + __builtin_extract_return_addr(_backtrace[i]); # ifdef HAVE_DLFCN_H Dl_info info; if (dladdr(addr, &info)) { ptrdiff_t offset = (char*)addr - (char*)info.dli_saddr;