1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
|
/*
* Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2025 Cppcheck team.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "stacktrace.h"
#ifdef USE_UNIX_BACKTRACE_SUPPORT
#include "utils.h"
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <cxxabi.h>
#include <execinfo.h>
void print_stacktrace(FILE* output, int start_idx, bool demangling, int maxdepth, bool omit_above_own)
{
// 32 vs. 64bit
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)
maxdepth=currentdepth-offset;
else
maxdepth = std::min(maxdepth, currentdepth);
char **symbolStringList = backtrace_symbols(callstackArray, currentdepth);
if (!symbolStringList) {
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 continuous if we omit frames
}
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);
if (realnameString) {
fprintf(output, "%.*s in %s\n",
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);
}
}
// NOLINTNEXTLINE(bugprone-multi-level-implicit-pointer-conversion) - code matches the documented usage
free(symbolStringList);
if (no_address) {
fputs("Callstack could not be obtained (no address)\n", output);
return;
}
}
#endif // USE_UNIX_BACKTRACE_SUPPORT
|