Cppcheck
stacktrace.cpp
Go to the documentation of this file.
1 /*
2  * Cppcheck - A tool for static C/C++ code analysis
3  * Copyright (C) 2007-2024 Cppcheck team.
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "stacktrace.h"
20 
21 #ifdef USE_UNIX_BACKTRACE_SUPPORT
22 
23 #include "utils.h"
24 
25 #include <algorithm>
26 #include <cstdlib>
27 #include <cstring>
28 #include <cxxabi.h>
29 #include <execinfo.h>
30 
31 void print_stacktrace(FILE* output, int start_idx, bool demangling, int maxdepth, bool omit_above_own)
32 {
33  // 32 vs. 64bit
34 #define ADDRESSDISPLAYLENGTH ((sizeof(long)==8)?12:8)
35  void *callstackArray[32]= {nullptr}; // the less resources the better...
36  const int currentdepth = backtrace(callstackArray, (int)getArrayLength(callstackArray));
37  // set offset to 1 to omit the printing function itself
38  int offset=start_idx+1; // some entries on top are within our own exception handling code or libc
39  if (maxdepth<0)
40  maxdepth=currentdepth-offset;
41  else
42  maxdepth = std::min(maxdepth, currentdepth);
43 
44  char **symbolStringList = backtrace_symbols(callstackArray, currentdepth);
45  if (!symbolStringList) {
46  fputs("Callstack could not be obtained\n", output);
47  return;
48  }
49 
50  fputs("Callstack:\n", output);
51  bool own_code = false;
52  char demangle_buffer[2048]= {0};
53  for (int i = offset; i < maxdepth; ++i) {
54  const char * const symbolString = symbolStringList[i];
55  // skip all leading libc symbols so the first symbol is our code
56  if (omit_above_own && !own_code) {
57  if (strstr(symbolString, "/libc.so.6") != nullptr)
58  continue;
59  own_code = true;
60  offset = i; // make sure the numbering is continous if we omit frames
61  }
62  char * realnameString = nullptr;
63  const char * const firstBracketName = strchr(symbolString, '(');
64  const char * const firstBracketAddress = strchr(symbolString, '[');
65  const char * const secondBracketAddress = strchr(firstBracketAddress, ']');
66  const char * const beginAddress = firstBracketAddress+3;
67  const int addressLen = int(secondBracketAddress-beginAddress);
68  const int padLen = int(ADDRESSDISPLAYLENGTH-addressLen);
69  if (demangling && firstBracketName) {
70  const char * const plus = strchr(firstBracketName, '+');
71  if (plus && (plus>(firstBracketName+1))) {
72  char input_buffer[1024]= {0};
73  strncpy(input_buffer, firstBracketName+1, plus-firstBracketName-1);
74  size_t length = getArrayLength(demangle_buffer);
75  int status=0;
76  // We're violating the specification - passing stack address instead of malloc'ed heap.
77  // Benefit is that no further heap is required, while there is sufficient stack...
78  realnameString = abi::__cxa_demangle(input_buffer, demangle_buffer, &length, &status); // non-NULL on success
79  }
80  }
81  const int ordinal=i-offset;
82  fprintf(output, "#%-2d 0x",
83  ordinal);
84  if (padLen>0)
85  fprintf(output, "%0*d",
86  padLen, 0);
87  if (realnameString) {
88  fprintf(output, "%.*s in %s\n",
89  (int)(secondBracketAddress-firstBracketAddress-3), firstBracketAddress+3,
90  realnameString);
91  } else {
92  fprintf(output, "%.*s in %.*s\n",
93  (int)(secondBracketAddress-firstBracketAddress-3), firstBracketAddress+3,
94  (int)(firstBracketAddress-symbolString), symbolString);
95  }
96  }
97  // NOLINTNEXTLINE(bugprone-multi-level-implicit-pointer-conversion) - code matches the documented usage
98  free(symbolStringList);
99 #undef ADDRESSDISPLAYLENGTH
100 }
101 
102 #endif // USE_UNIX_BACKTRACE_SUPPORT
std::size_t getArrayLength(const T(&)[size])
Simple helper function:
Definition: utils.h:296