Index: configure.ac ================================================================== --- configure.ac +++ configure.ac @@ -614,11 +614,11 @@ ]) AC_CHECK_HEADER(poll.h, [ AC_DEFINE(HAVE_POLL_H, 1, [Whether we have poll.h]) AC_SUBST(OFSTREAMOBSERVER_POLL_M, "OFStreamObserver_poll.m") ]) - AC_CHECK_HEADERS(sys/select.h, [ + AC_CHECK_HEADER(sys/select.h, [ AC_DEFINE(HAVE_SYS_SELECT_H, 1, [Whether we have sys/select.h]) AC_SUBST(OFSTREAMOBSERVER_SELECT_M, "OFStreamObserver_select.m") ]) case "$host_os" in mingw*) @@ -734,10 +734,12 @@ esac 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_CHECK_HEADERS(execinfo.h) AS_IF([test x"$objc_runtime" = x"Apple runtime"], [ AC_CHECK_HEADER(Foundation/NSObject.h, [ AC_SUBST(FOUNDATION_COMPAT_M, "foundation-compat.m") AC_SUBST(BRIDGE, "bridge") Index: src/exceptions/OFException.h ================================================================== --- src/exceptions/OFException.h +++ src/exceptions/OFException.h @@ -14,11 +14,15 @@ * file. */ #import "OFObject.h" +#define OF_EXCEPTION_MAX_BACKTRACE_SIZE 32 + @class OFString; +@class OFArray; +@class OFMutableArray; /*! * @brief The base class for all exceptions in ObjFW * * The OFException class is the base class for all exceptions in ObjFW, except @@ -25,10 +29,13 @@ * the OFAllocFailedException. */ @interface OFException: OFObject { Class _inClass; + OFMutableArray *_backtrace; + void *_backtraceBuffer[OF_EXCEPTION_MAX_BACKTRACE_SIZE]; + int _backtraceSize; } #ifdef OF_HAVE_PROPERTIES @property (readonly) Class inClass; #endif @@ -60,6 +67,14 @@ * @brief Returns a description of the exception. * * @return A description of the exception */ - (OFString*)description; + +/*! + * @brief Returns a backtrace of when the exception was created or nil if no + * backtrace is available. + * + * @return A backtrace of when the exception was created + */ +- (OFArray*)backtrace; @end Index: src/exceptions/OFException.m ================================================================== --- src/exceptions/OFException.m +++ src/exceptions/OFException.m @@ -15,13 +15,20 @@ */ #include "config.h" #include + +#ifdef HAVE_EXECINFO_H +# include +#endif #import "OFException.h" #import "OFString.h" +#import "OFArray.h" + +#import "autorelease.h" @implementation OFException + (instancetype)exceptionWithClass: (Class)class { return [[[self alloc] initWithClass: class] autorelease]; @@ -42,13 +49,24 @@ - initWithClass: (Class)class { self = [super init]; _inClass = class; +#ifdef HAVE_EXECINFO_H + _backtraceSize = backtrace(_backtraceBuffer, + OF_EXCEPTION_MAX_BACKTRACE_SIZE); +#endif return self; } + +- (void)dealloc +{ + [_backtrace release]; + + [super dealloc]; +} - (Class)inClass { return _inClass; } @@ -57,6 +75,46 @@ { return [OFString stringWithFormat: @"An exception of class %@ occurred in class %@!", object_getClass(self), _inClass]; } + +- (OFArray*)backtrace +{ +#ifdef HAVE_EXECINFO_H + char **symbols; + + if (_backtrace != nil) + return _backtrace; + + if (_backtraceSize < 1) + return nil; + + symbols = backtrace_symbols(_backtraceBuffer, _backtraceSize); + @try { + int i; + + _backtrace = [[OFMutableArray alloc] init]; + + for (i = 0; i < _backtraceSize; i++) { + void *pool = objc_autoreleasePoolPush(); + OFString *symbol; + + symbol = [OFString + stringWithCString: symbols[i] + encoding: OF_STRING_ENCODING_NATIVE]; + [_backtrace addObject: symbol]; + + objc_autoreleasePoolPop(pool); + } + } @finally { + free(symbols); + } + + [_backtrace makeImmutable]; + + return _backtrace; +#else + return nil; +#endif +} @end