forked from danmar/cppcheck
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstacktrace.cpp
More file actions
142 lines (128 loc) · 5.45 KB
/
stacktrace.cpp
File metadata and controls
142 lines (128 loc) · 5.45 KB
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