Coverage Report

Created: 2026-01-31 08:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/duckdb/src/common/stacktrace.cpp
Line
Count
Source
1
#include "duckdb/common/stacktrace.hpp"
2
#include "duckdb/common/string_util.hpp"
3
#include "duckdb/common/to_string.hpp"
4
5
#if defined(__GLIBC__) || defined(__APPLE__)
6
#include <execinfo.h>
7
#include <cxxabi.h>
8
#endif
9
10
namespace duckdb {
11
12
#if defined(__GLIBC__) || defined(__APPLE__)
13
0
static string UnmangleSymbol(string symbol) {
14
  // find the mangled name
15
0
  idx_t mangle_start = symbol.size();
16
0
  idx_t mangle_end = 0;
17
0
  for (idx_t i = 0; i < symbol.size(); ++i) {
18
0
    if (symbol[i] == '_') {
19
0
      mangle_start = i;
20
0
      break;
21
0
    }
22
0
  }
23
0
  for (idx_t i = mangle_start; i < symbol.size(); i++) {
24
0
    if (StringUtil::CharacterIsSpace(symbol[i]) || symbol[i] == ')' || symbol[i] == '+') {
25
0
      mangle_end = i;
26
0
      break;
27
0
    }
28
0
  }
29
0
  if (mangle_start >= mangle_end) {
30
0
    return symbol;
31
0
  }
32
0
  string mangled_symbol = symbol.substr(mangle_start, mangle_end - mangle_start);
33
34
0
  int status;
35
0
  auto demangle_result = abi::__cxa_demangle(mangled_symbol.c_str(), nullptr, nullptr, &status);
36
0
  if (status != 0 || !demangle_result) {
37
0
    return symbol;
38
0
  }
39
0
  string result;
40
0
  result += symbol.substr(0, mangle_start);
41
0
  result += demangle_result;
42
0
  result += symbol.substr(mangle_end);
43
0
  free(demangle_result);
44
0
  return result;
45
0
}
46
47
0
static string CleanupStackTrace(string symbol) {
48
#ifdef __APPLE__
49
  // structure of frame pointers is [depth] [library] [pointer] [symbol]
50
  // we are only interested in [depth] and [symbol]
51
52
  // find the depth
53
  idx_t start;
54
  for (start = 0; start < symbol.size(); start++) {
55
    if (!StringUtil::CharacterIsDigit(symbol[start])) {
56
      break;
57
    }
58
  }
59
60
  // now scan forward until we find the frame pointer
61
  idx_t frame_end = symbol.size();
62
  for (idx_t i = start; i + 1 < symbol.size(); ++i) {
63
    if (symbol[i] == '0' && symbol[i + 1] == 'x') {
64
      idx_t k;
65
      for (k = i + 2; k < symbol.size(); ++k) {
66
        if (!StringUtil::CharacterIsHex(symbol[k])) {
67
          break;
68
        }
69
      }
70
      frame_end = k;
71
      break;
72
    }
73
  }
74
  static constexpr idx_t STACK_TRACE_INDENTATION = 8;
75
  if (frame_end == symbol.size() || start >= STACK_TRACE_INDENTATION) {
76
    // frame pointer not found - just preserve the original frame
77
    return symbol;
78
  }
79
  idx_t space_count = STACK_TRACE_INDENTATION - start;
80
  return symbol.substr(0, start) + string(space_count, ' ') + symbol.substr(frame_end, symbol.size() - frame_end);
81
#else
82
0
  return symbol;
83
0
#endif
84
0
}
85
86
0
string StackTrace::GetStacktracePointers(idx_t max_depth) {
87
0
  string result;
88
0
  auto callstack = unique_ptr<void *[]>(new void *[max_depth]);
89
0
  int frames = backtrace(callstack.get(), NumericCast<int32_t>(max_depth));
90
  // skip two frames (these are always StackTrace::...)
91
0
  for (idx_t i = 2; i < NumericCast<idx_t>(frames); i++) {
92
0
    if (!result.empty()) {
93
0
      result += ";";
94
0
    }
95
0
    result += to_string(CastPointerToValue(callstack[i]));
96
0
  }
97
0
  return result;
98
0
}
99
100
0
string StackTrace::ResolveStacktraceSymbols(const string &pointers) {
101
0
  auto splits = StringUtil::Split(pointers, ";");
102
0
  idx_t frame_count = splits.size();
103
0
  auto callstack = unique_ptr<void *[]>(new void *[frame_count]);
104
0
  for (idx_t i = 0; i < frame_count; i++) {
105
0
    callstack[i] = cast_uint64_to_pointer(StringUtil::ToUnsigned(splits[i]));
106
0
  }
107
0
  string result;
108
0
  char **strs = backtrace_symbols(callstack.get(), NumericCast<int>(frame_count));
109
0
  for (idx_t i = 0; i < frame_count; i++) {
110
0
    result += CleanupStackTrace(UnmangleSymbol(strs[i]));
111
0
    result += "\n";
112
0
  }
113
0
  free(reinterpret_cast<void *>(strs));
114
0
  return "\n" + result;
115
0
}
116
117
#else
118
string StackTrace::GetStacktracePointers(idx_t max_depth) {
119
  return string();
120
}
121
122
string StackTrace::ResolveStacktraceSymbols(const string &pointers) {
123
  return string();
124
}
125
#endif
126
127
} // namespace duckdb