diff --git a/cli/stacktrace.cpp b/cli/stacktrace.cpp index 86521a28a6d..dbcbed448bb 100644 --- a/cli/stacktrace.cpp +++ b/cli/stacktrace.cpp @@ -31,9 +31,17 @@ void print_stacktrace(FILE* output, int start_idx, bool demangling, int maxdepth, bool omit_above_own) { // 32 vs. 64bit -#define ADDRESSDISPLAYLENGTH ((sizeof(long)==8)?12:8) + static constexpr auto ADDRESSDISPLAYLENGTH = (sizeof(long) == 8) ? 12 : 8; + void *callstackArray[32]= {nullptr}; // the less resources the better... const int currentdepth = backtrace(callstackArray, static_cast(getArrayLength(callstackArray))); + if (currentdepth == 0) { + fputs("Callstack could not be obtained (backtrace)\n", output); + return; + } + if (currentdepth == getArrayLength(callstackArray)) { + fputs("Callstack might be truncated\n", output); + } // set offset to 1 to omit the printing function itself int offset=start_idx+1; // some entries on top are within our own exception handling code or libc if (maxdepth<0) @@ -43,60 +51,92 @@ void print_stacktrace(FILE* output, int start_idx, bool demangling, int maxdepth char **symbolStringList = backtrace_symbols(callstackArray, currentdepth); if (!symbolStringList) { - fputs("Callstack could not be obtained\n", output); + fputs("Callstack could not be obtained (backtrace_symbols)\n", output); return; } fputs("Callstack:\n", output); bool own_code = false; char demangle_buffer[2048]= {0}; + bool no_address = false; for (int i = offset; i < maxdepth; ++i) { const char * const symbolString = symbolStringList[i]; + // TODO: implement parsing for __APPLE__ + // 0 test-signalhandler 0x0000000100dbf42c _Z16print_stacktraceP7__sFILEibib + 124 + + /* + * examples: + * ./test-signalhandler(_Z16print_stacktraceP8_IO_FILEibib+0xa1) [0x55cb65e41464] + * ./test-signalhandler(+0xf9d9) [0x55cb65e3c9d9] + */ + // skip all leading libc symbols so the first symbol is our code if (omit_above_own && !own_code) { if (strstr(symbolString, "/libc.so.6") != nullptr) continue; own_code = true; - offset = i; // make sure the numbering is continous if we omit frames + offset = i; // make sure the numbering is continuous if we omit frames } - char * realnameString = nullptr; - const char * const firstBracketName = strchr(symbolString, '('); - const char * const firstBracketAddress = strchr(symbolString, '['); - const char * const secondBracketAddress = strchr(firstBracketAddress, ']'); - const char * const beginAddress = firstBracketAddress+3; - const int addressLen = int(secondBracketAddress-beginAddress); - const int padLen = (ADDRESSDISPLAYLENGTH-addressLen); - if (demangling && firstBracketName) { - const char * const plus = strchr(firstBracketName, '+'); - if (plus && (plus>(firstBracketName+1))) { - char input_buffer[1024]= {0}; - strncpy(input_buffer, firstBracketName+1, plus-firstBracketName-1); - size_t length = getArrayLength(demangle_buffer); - int status=0; - // We're violating the specification - passing stack address instead of malloc'ed heap. - // Benefit is that no further heap is required, while there is sufficient stack... - realnameString = abi::__cxa_demangle(input_buffer, demangle_buffer, &length, &status); // non-NULL on success + const char * realnameString = nullptr; + if (demangling) { + const char * const firstBracketName = strchr(symbolString, '('); + if (firstBracketName) { + const char * const plus = strchr(firstBracketName, '+'); + if (plus && (plus>(firstBracketName+1))) { + char input_buffer[1024]= {0}; + strncpy(input_buffer, firstBracketName+1, plus-firstBracketName-1); + size_t length = getArrayLength(demangle_buffer); + int status=0; + // We're violating the specification - passing stack address instead of malloc'ed heap. + // Benefit is that no further heap is required, while there is sufficient stack... + realnameString = abi::__cxa_demangle(input_buffer, demangle_buffer, &length, &status); // non-NULL on success + } } } + + const char * const firstBracketAddress = strchr(symbolString, '['); + if (!firstBracketAddress) { + no_address = true; + break; + } + const char * const secondBracketAddress = strchr(firstBracketAddress, ']'); + if (!secondBracketAddress) { + no_address = true; + break; + } + const int ordinal=i-offset; fprintf(output, "#%-2d 0x", ordinal); + const int padLen = [&]() { + const char * const beginAddress = firstBracketAddress+3; + const int addressLen = int(secondBracketAddress-beginAddress); + return (ADDRESSDISPLAYLENGTH-addressLen); + }(); if (padLen>0) fprintf(output, "%0*d", - padLen, 0); + padLen, + 0); if (realnameString) { fprintf(output, "%.*s in %s\n", - static_cast(secondBracketAddress - firstBracketAddress - 3), firstBracketAddress+3, + static_cast(secondBracketAddress - firstBracketAddress - 3), + firstBracketAddress+3, realnameString); } else { fprintf(output, "%.*s in %.*s\n", - static_cast(secondBracketAddress - firstBracketAddress - 3), firstBracketAddress+3, - static_cast(firstBracketAddress - symbolString), symbolString); + static_cast(secondBracketAddress - firstBracketAddress - 3), + firstBracketAddress+3, + static_cast(firstBracketAddress - symbolString), + symbolString); } } // NOLINTNEXTLINE(bugprone-multi-level-implicit-pointer-conversion) - code matches the documented usage free(symbolStringList); -#undef ADDRESSDISPLAYLENGTH + + if (no_address) { + fputs("Callstack could not be obtained (no address)\n", output); + return; + } } #endif // USE_UNIX_BACKTRACE_SUPPORT diff --git a/lib/config.h b/lib/config.h index b9d34770be7..232fcb007fb 100644 --- a/lib/config.h +++ b/lib/config.h @@ -211,8 +211,7 @@ static const std::string emptyString; #define USE_WINDOWS_SEH #endif -// TODO: __GLIBC__ is dependent on the features.h include and not a built-in compiler define, so it might be problematic to depend on it -#if !defined(NO_UNIX_BACKTRACE_SUPPORT) && defined(__GNUC__) && defined(__GLIBC__) && !defined(__CYGWIN__) && !defined(__MINGW32__) && !defined(__NetBSD__) && !defined(__SVR4) && !defined(__QNX__) +#if !defined(NO_UNIX_BACKTRACE_SUPPORT) && defined(__GNUC__) && !defined(__APPLE__) && !defined(__CYGWIN__) && !defined(__MINGW32__) && !defined(__NetBSD__) && !defined(__SVR4) && !defined(__QNX__) #define USE_UNIX_BACKTRACE_SUPPORT #endif