diff --git a/ChangeLog b/ChangeLog index d60bd5de3..b46076145 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2019-11-15 Frederik Seiffert + + * configure.ac: check for unwind.h + * configure: regenerate + * Source/NSException.m: Added support for backtrace symbolication + using libunwind, which will be used when backtrace() is unavailable. + 2019-11-14 Fred Kiefer * Headers/Foundation/NSXPCConnection.h, diff --git a/Headers/GNUstepBase/config.h.in b/Headers/GNUstepBase/config.h.in index f56f4f4e7..4c1e26f44 100644 --- a/Headers/GNUstepBase/config.h.in +++ b/Headers/GNUstepBase/config.h.in @@ -737,6 +737,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H +/* Define to 1 if you have the header file. */ +#undef HAVE_UNWIND_H + /* Define to 1 if you have the `usleep' function. */ #undef HAVE_USLEEP diff --git a/Source/NSException.m b/Source/NSException.m index 537dbdf49..1b18b3170 100644 --- a/Source/NSException.m +++ b/Source/NSException.m @@ -565,6 +565,35 @@ GSListModules() #endif /* USE_BFD */ +#if defined(HAVE_UNWIND_H) && !defined(HAVE_BACKTRACE) + +#include +#include + +struct GSBacktraceState +{ + void **current; + void **end; +}; + +static _Unwind_Reason_Code +GSUnwindCallback(struct _Unwind_Context* context, void* arg) +{ + struct GSBacktraceState *state = (struct GSBacktraceState*)arg; + uintptr_t pc = _Unwind_GetIP(context); + if (pc) { + if (state->current == state->end) { + return _URC_END_OF_STACK; + } else { + *state->current++ = (void*)pc; + } + } + return 0; //_URC_OK/_URC_NO_REASON +} + +#endif /* HAVE_UNWIND_H && !HAVE_BACKTRACE */ + + #if defined(_WIN32) && !defined(USE_BFD) typedef USHORT (WINAPI *CaptureStackBackTraceType)(ULONG,ULONG,PVOID*,PULONG); typedef BOOL (WINAPI *SymInitializeType)(HANDLE,char*,BOOL); @@ -846,7 +875,7 @@ unsigned GSPrivateReturnAddresses(NSUInteger **returns) { unsigned numReturns; -#if HAVE_BACKTRACE +#if defined(HAVE_BACKTRACE) void *addr[MAXFRAMES*sizeof(void*)]; numReturns = backtrace(addr, MAXFRAMES); @@ -855,6 +884,18 @@ GSPrivateReturnAddresses(NSUInteger **returns) *returns = malloc(numReturns * sizeof(void*)); memcpy(*returns, addr, numReturns * sizeof(void*)); } +#elif defined(HAVE_UNWIND_H) + void *addr[MAXFRAMES]; + + struct GSBacktraceState state = {addr, addr + MAXFRAMES}; + _Unwind_Backtrace(GSUnwindCallback, &state); + + numReturns = state.current - addr; + if (numReturns > 0) + { + *returns = malloc(numReturns * sizeof(void*)); + memcpy(*returns, addr, numReturns * sizeof(void*)); + } #elif defined(_WIN32) && !defined(USE_BFD) NSUInteger addr[MAXFRAMES]; @@ -1225,6 +1266,36 @@ GSPrivateReturnAddresses(NSUInteger **returns) } symbols = [[NSArray alloc] initWithObjects: symbolArray count: count]; free(strs); +#elif defined(HAVE_UNWIND_H) + void **ptrs = (void**)&returns[FrameOffset]; + NSString **symbolArray; + + symbolArray = alloca(count * sizeof(NSString*)); + for (i = 0; i < count; i++) + { + const void *addr = ptrs[i]; + Dl_info info; + if (dladdr(addr, &info)) { + const char *libname = "unknown"; + if (info.dli_fname) { + // strip library path + char *delim = strrchr(info.dli_fname, '/'); + libname = delim ? delim + 1 : info.dli_fname; + } + if (info.dli_sname) { + symbolArray[i] = [NSString stringWithFormat: + @"%lu: %p %s %s + %d", (unsigned long)i, addr, libname, + info.dli_sname, (int)(addr - info.dli_saddr)]; + } else { + symbolArray[i] = [NSString stringWithFormat: + @"%lu: %p %s unknown", (unsigned long)i, addr, libname]; + } + } else { + symbolArray[i] = [NSString stringWithFormat: + @"%lu: %p unknown", (unsigned long)i, addr]; + } + } + symbols = [[NSArray alloc] initWithObjects: symbolArray count: count]; #else NSMutableArray *a; @@ -1233,8 +1304,8 @@ GSPrivateReturnAddresses(NSUInteger **returns) { NSString *s; - s = [[NSString alloc] initWithFormat: @"%@: symbol not available", - [a objectAtIndex: i]]; + s = [[NSString alloc] initWithFormat: @"%p: symbol not available", + [[a objectAtIndex: i] pointerValue]]; [a replaceObjectAtIndex: i withObject: s]; RELEASE(s); } diff --git a/configure b/configure index c4151ca3d..7c5cba978 100755 --- a/configure +++ b/configure @@ -9079,6 +9079,19 @@ fi done +for ac_header in unwind.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "unwind.h" "ac_cv_header_unwind_h" "$ac_includes_default" +if test "x$ac_cv_header_unwind_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_UNWIND_H 1 +_ACEOF + +fi + +done + + #-------------------------------------------------------------------- # These headers/functions needed by NSLog.m #-------------------------------------------------------------------- diff --git a/configure.ac b/configure.ac index 07496e653..1df64dedf 100644 --- a/configure.ac +++ b/configure.ac @@ -2321,6 +2321,8 @@ fi AC_CHECK_FUNCS(__builtin_extract_return_address) +AC_CHECK_HEADERS(unwind.h) + #-------------------------------------------------------------------- # These headers/functions needed by NSLog.m #--------------------------------------------------------------------