Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 65 additions & 25 deletions cli/stacktrace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<int>(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)
Expand All @@ -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, '[');
Comment thread
danmar marked this conversation as resolved.
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<int>(secondBracketAddress - firstBracketAddress - 3), firstBracketAddress+3,
static_cast<int>(secondBracketAddress - firstBracketAddress - 3),
firstBracketAddress+3,
realnameString);
} else {
fprintf(output, "%.*s in %.*s\n",
static_cast<int>(secondBracketAddress - firstBracketAddress - 3), firstBracketAddress+3,
static_cast<int>(firstBracketAddress - symbolString), symbolString);
static_cast<int>(secondBracketAddress - firstBracketAddress - 3),
firstBracketAddress+3,
static_cast<int>(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
3 changes: 1 addition & 2 deletions lib/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down