/root/doris/be/src/common/stack_trace.cpp
| Line | Count | Source | 
| 1 |  | // Licensed to the Apache Software Foundation (ASF) under one | 
| 2 |  | // or more contributor license agreements.  See the NOTICE file | 
| 3 |  | // distributed with this work for additional information | 
| 4 |  | // regarding copyright ownership.  The ASF licenses this file | 
| 5 |  | // to you under the Apache License, Version 2.0 (the | 
| 6 |  | // "License"); you may not use this file except in compliance | 
| 7 |  | // with the License.  You may obtain a copy of the License at | 
| 8 |  | // | 
| 9 |  | //   http://www.apache.org/licenses/LICENSE-2.0 | 
| 10 |  | // | 
| 11 |  | // Unless required by applicable law or agreed to in writing, | 
| 12 |  | // software distributed under the License is distributed on an | 
| 13 |  | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | 
| 14 |  | // KIND, either express or implied.  See the License for the | 
| 15 |  | // specific language governing permissions and limitations | 
| 16 |  | // under the License. | 
| 17 |  | // This file is copied from | 
| 18 |  | // https://github.com/ClickHouse/ClickHouse/blob/master/src/Common/StackTrace.cpp | 
| 19 |  | // and modified by Doris | 
| 20 |  |  | 
| 21 |  | #include "common/stack_trace.h" | 
| 22 |  |  | 
| 23 |  | #include <common/dwarf.h> | 
| 24 |  | #include <common/elf.h> | 
| 25 |  | #include <common/memory_sanitizer.h> | 
| 26 |  | #include <common/symbol_index.h> | 
| 27 |  | #include <fmt/format.h> | 
| 28 |  |  | 
| 29 |  | #include <atomic> | 
| 30 |  | #include <filesystem> | 
| 31 |  | #include <map> | 
| 32 |  | #include <mutex> | 
| 33 |  | #include <sstream> | 
| 34 |  | #include <unordered_map> | 
| 35 |  |  | 
| 36 |  | #include "config.h" | 
| 37 |  | #include "util/string_util.h" | 
| 38 |  | #include "vec/common/demangle.h" | 
| 39 |  | #include "vec/common/hex.h" | 
| 40 |  |  | 
| 41 |  | #if defined(USE_UNWIND) && USE_UNWIND && defined(__x86_64__) | 
| 42 |  | #include <libunwind.h> | 
| 43 |  | #else | 
| 44 |  | #include <execinfo.h> | 
| 45 |  | #endif | 
| 46 |  |  | 
| 47 |  | namespace { | 
| 48 |  | /// Currently this variable is set up once on server startup. | 
| 49 |  | /// But we use atomic just in case, so it is possible to be modified at runtime. | 
| 50 |  | std::atomic<bool> show_addresses = true; | 
| 51 |  |  | 
| 52 |  | // #if defined(__ELF__) && !defined(__FreeBSD__) | 
| 53 |  | // void writePointerHex(const void* ptr, std::stringstream& buf) { | 
| 54 |  | //     buf.write("0x", 2); | 
| 55 |  | //     char hex_str[2 * sizeof(ptr)]; | 
| 56 |  | //     doris::vectorized::write_hex_uint_lowercase(reinterpret_cast<uintptr_t>(ptr), hex_str); | 
| 57 |  | //     buf.write(hex_str, 2 * sizeof(ptr)); | 
| 58 |  | // } | 
| 59 |  | // #endif | 
| 60 |  |  | 
| 61 | 0 | bool shouldShowAddress(const void* addr) { | 
| 62 |  |     /// If the address is less than 4096, most likely it is a nullptr dereference with offset, | 
| 63 |  |     /// and showing this offset is secure nevertheless. | 
| 64 |  |     /// NOTE: 4096 is the page size on x86 and it can be different on other systems, | 
| 65 |  |     /// but for the purpose of this branch, it does not matter. | 
| 66 | 0 |     if (reinterpret_cast<uintptr_t>(addr) < 4096) { | 
| 67 | 0 |         return true; | 
| 68 | 0 |     } | 
| 69 |  |  | 
| 70 | 0 |     return show_addresses.load(std::memory_order_relaxed); | 
| 71 | 0 | } | 
| 72 |  | } // namespace | 
| 73 |  |  | 
| 74 | 0 | void StackTrace::setShowAddresses(bool show) { | 
| 75 | 0 |     show_addresses.store(show, std::memory_order_relaxed); | 
| 76 | 0 | } | 
| 77 |  |  | 
| 78 | 0 | std::string SigsegvErrorString(const siginfo_t& info, [[maybe_unused]] const ucontext_t& context) { | 
| 79 | 0 |     using namespace std::string_literals; | 
| 80 | 0 |     std::string address = | 
| 81 | 0 |             info.si_addr == nullptr | 
| 82 | 0 |                     ? "NULL pointer"s | 
| 83 | 0 |                     : (shouldShowAddress(info.si_addr) ? fmt::format("{}", info.si_addr) : ""s); | 
| 84 |  | 
 | 
| 85 | 0 |     const std::string_view access = | 
| 86 | 0 | #if defined(__x86_64__) && !defined(__FreeBSD__) && !defined(__APPLE__) && !defined(__arm__) && \ | 
| 87 | 0 |         !defined(__powerpc__) | 
| 88 | 0 |             (context.uc_mcontext.gregs[REG_ERR] & 0x02) ? "write" : "read"; | 
| 89 |  | #else | 
| 90 |  |             ""; | 
| 91 |  | #endif | 
| 92 |  | 
 | 
| 93 | 0 |     std::string_view message; | 
| 94 |  | 
 | 
| 95 | 0 |     switch (info.si_code) { | 
| 96 | 0 |     case SEGV_ACCERR: | 
| 97 | 0 |         message = "Attempted access has violated the permissions assigned to the memory area"; | 
| 98 | 0 |         break; | 
| 99 | 0 |     case SEGV_MAPERR: | 
| 100 | 0 |         message = "Address not mapped to object"; | 
| 101 | 0 |         break; | 
| 102 | 0 |     default: | 
| 103 | 0 |         message = "Unknown si_code"; | 
| 104 | 0 |         break; | 
| 105 | 0 |     } | 
| 106 |  |  | 
| 107 | 0 |     return fmt::format("Address: {}. Access: {}. {}.", std::move(address), access, message); | 
| 108 | 0 | } | 
| 109 |  |  | 
| 110 | 0 | constexpr std::string_view SigbusErrorString(int si_code) { | 
| 111 | 0 |     switch (si_code) { | 
| 112 | 0 |     case BUS_ADRALN: | 
| 113 | 0 |         return "Invalid address alignment."; | 
| 114 | 0 |     case BUS_ADRERR: | 
| 115 | 0 |         return "Non-existent physical address."; | 
| 116 | 0 |     case BUS_OBJERR: | 
| 117 | 0 |         return "Object specific hardware error."; | 
| 118 |  |  | 
| 119 |  |         // Linux specific | 
| 120 | 0 | #if defined(BUS_MCEERR_AR) | 
| 121 | 0 |     case BUS_MCEERR_AR: | 
| 122 | 0 |         return "Hardware memory error: action required."; | 
| 123 | 0 | #endif | 
| 124 | 0 | #if defined(BUS_MCEERR_AO) | 
| 125 | 0 |     case BUS_MCEERR_AO: | 
| 126 | 0 |         return "Hardware memory error: action optional."; | 
| 127 | 0 | #endif | 
| 128 | 0 |     default: | 
| 129 | 0 |         return "Unknown si_code."; | 
| 130 | 0 |     } | 
| 131 | 0 | } | 
| 132 |  |  | 
| 133 | 0 | constexpr std::string_view SigfpeErrorString(int si_code) { | 
| 134 | 0 |     switch (si_code) { | 
| 135 | 0 |     case FPE_INTDIV: | 
| 136 | 0 |         return "Integer divide by zero."; | 
| 137 | 0 |     case FPE_INTOVF: | 
| 138 | 0 |         return "Integer overflow."; | 
| 139 | 0 |     case FPE_FLTDIV: | 
| 140 | 0 |         return "Floating point divide by zero."; | 
| 141 | 0 |     case FPE_FLTOVF: | 
| 142 | 0 |         return "Floating point overflow."; | 
| 143 | 0 |     case FPE_FLTUND: | 
| 144 | 0 |         return "Floating point underflow."; | 
| 145 | 0 |     case FPE_FLTRES: | 
| 146 | 0 |         return "Floating point inexact result."; | 
| 147 | 0 |     case FPE_FLTINV: | 
| 148 | 0 |         return "Floating point invalid operation."; | 
| 149 | 0 |     case FPE_FLTSUB: | 
| 150 | 0 |         return "Subscript out of range."; | 
| 151 | 0 |     default: | 
| 152 | 0 |         return "Unknown si_code."; | 
| 153 | 0 |     } | 
| 154 | 0 | } | 
| 155 |  |  | 
| 156 | 0 | constexpr std::string_view SigillErrorString(int si_code) { | 
| 157 | 0 |     switch (si_code) { | 
| 158 | 0 |     case ILL_ILLOPC: | 
| 159 | 0 |         return "Illegal opcode."; | 
| 160 | 0 |     case ILL_ILLOPN: | 
| 161 | 0 |         return "Illegal operand."; | 
| 162 | 0 |     case ILL_ILLADR: | 
| 163 | 0 |         return "Illegal addressing mode."; | 
| 164 | 0 |     case ILL_ILLTRP: | 
| 165 | 0 |         return "Illegal trap."; | 
| 166 | 0 |     case ILL_PRVOPC: | 
| 167 | 0 |         return "Privileged opcode."; | 
| 168 | 0 |     case ILL_PRVREG: | 
| 169 | 0 |         return "Privileged register."; | 
| 170 | 0 |     case ILL_COPROC: | 
| 171 | 0 |         return "Coprocessor error."; | 
| 172 | 0 |     case ILL_BADSTK: | 
| 173 | 0 |         return "Internal stack error."; | 
| 174 | 0 |     default: | 
| 175 | 0 |         return "Unknown si_code."; | 
| 176 | 0 |     } | 
| 177 | 0 | } | 
| 178 |  |  | 
| 179 |  | std::string signalToErrorMessage(int sig, const siginfo_t& info, | 
| 180 | 0 |                                  [[maybe_unused]] const ucontext_t& context) { | 
| 181 | 0 |     switch (sig) { | 
| 182 | 0 |     case SIGSEGV: | 
| 183 | 0 |         return SigsegvErrorString(info, context); | 
| 184 | 0 |     case SIGBUS: | 
| 185 | 0 |         return std::string {SigbusErrorString(info.si_code)}; | 
| 186 | 0 |     case SIGILL: | 
| 187 | 0 |         return std::string {SigillErrorString(info.si_code)}; | 
| 188 | 0 |     case SIGFPE: | 
| 189 | 0 |         return std::string {SigfpeErrorString(info.si_code)}; | 
| 190 | 0 |     case SIGTSTP: | 
| 191 | 0 |         return "This is a signal used for debugging purposes by the user."; | 
| 192 | 0 |     default: | 
| 193 | 0 |         return ""; | 
| 194 | 0 |     } | 
| 195 | 0 | } | 
| 196 |  |  | 
| 197 | 0 | static void* getCallerAddress(const ucontext_t& context) { | 
| 198 | 0 | #if defined(__x86_64__) | 
| 199 |  |     /// Get the address at the time the signal was raised from the RIP (x86-64) | 
| 200 |  | #if defined(__FreeBSD__) | 
| 201 |  |     return reinterpret_cast<void*>(context.uc_mcontext.mc_rip); | 
| 202 |  | #elif defined(__APPLE__) | 
| 203 |  |     return reinterpret_cast<void*>(context.uc_mcontext->__ss.__rip); | 
| 204 |  | #else | 
| 205 | 0 |     return reinterpret_cast<void*>(context.uc_mcontext.gregs[REG_RIP]); | 
| 206 | 0 | #endif | 
| 207 |  | #elif defined(__APPLE__) && defined(__aarch64__) | 
| 208 |  |     return reinterpret_cast<void*>(context.uc_mcontext->__ss.__pc); | 
| 209 |  | #elif defined(__FreeBSD__) && defined(__aarch64__) | 
| 210 |  |     return reinterpret_cast<void*>(context.uc_mcontext.mc_gpregs.gp_elr); | 
| 211 |  | #elif defined(__aarch64__) | 
| 212 |  |     return reinterpret_cast<void*>(context.uc_mcontext.pc); | 
| 213 |  | #elif defined(__powerpc64__) && defined(__linux__) | 
| 214 |  |     return reinterpret_cast<void*>(context.uc_mcontext.gp_regs[PT_NIP]); | 
| 215 |  | #elif defined(__powerpc64__) && defined(__FreeBSD__) | 
| 216 |  |     return reinterpret_cast<void*>(context.uc_mcontext.mc_srr0); | 
| 217 |  | #elif defined(__riscv) | 
| 218 |  |     return reinterpret_cast<void*>(context.uc_mcontext.__gregs[REG_PC]); | 
| 219 |  | #elif defined(__s390x__) | 
| 220 |  |     return reinterpret_cast<void*>(context.uc_mcontext.psw.addr); | 
| 221 |  | #else | 
| 222 |  |     return nullptr; | 
| 223 |  | #endif | 
| 224 | 0 | } | 
| 225 |  |  | 
| 226 |  | // FIXME: looks like this is used only for Sentry but duplicates the whole algo, maybe replace? | 
| 227 |  | void StackTrace::symbolize(const StackTrace::FramePointers& frame_pointers, | 
| 228 |  |                            [[maybe_unused]] size_t offset, size_t size, | 
| 229 | 0 |                            StackTrace::Frames& frames) { | 
| 230 | 0 | #if defined(__ELF__) && !defined(__FreeBSD__) | 
| 231 | 0 |     auto symbol_index_ptr = doris::SymbolIndex::instance(); | 
| 232 | 0 |     const doris::SymbolIndex& symbol_index = *symbol_index_ptr; | 
| 233 | 0 |     std::unordered_map<std::string, doris::Dwarf> dwarfs; | 
| 234 |  | 
 | 
| 235 | 0 |     for (size_t i = 0; i < offset; ++i) { | 
| 236 | 0 |         frames[i].virtual_addr = frame_pointers[i]; | 
| 237 | 0 |     } | 
| 238 |  | 
 | 
| 239 | 0 |     for (size_t i = offset; i < size; ++i) { | 
| 240 | 0 |         StackTrace::Frame& current_frame = frames[i]; | 
| 241 | 0 |         current_frame.virtual_addr = frame_pointers[i]; | 
| 242 | 0 |         const auto* object = symbol_index.findObject(current_frame.virtual_addr); | 
| 243 | 0 |         uintptr_t virtual_offset = object ? uintptr_t(object->address_begin) : 0; | 
| 244 | 0 |         current_frame.physical_addr = | 
| 245 | 0 |                 reinterpret_cast<void*>(uintptr_t(current_frame.virtual_addr) - virtual_offset); | 
| 246 |  | 
 | 
| 247 | 0 |         if (object) { | 
| 248 | 0 |             current_frame.object = object->name; | 
| 249 | 0 |             if (std::error_code ec; | 
| 250 | 0 |                 std::filesystem::exists(current_frame.object.value(), ec) && !ec) { | 
| 251 | 0 |                 auto dwarf_it = dwarfs.try_emplace(object->name, object->elf).first; | 
| 252 |  | 
 | 
| 253 | 0 |                 doris::Dwarf::LocationInfo location; | 
| 254 | 0 |                 std::vector<doris::Dwarf::SymbolizedFrame> inline_frames; | 
| 255 | 0 |                 if (dwarf_it->second.findAddress(uintptr_t(current_frame.physical_addr), location, | 
| 256 | 0 |                                                  doris::Dwarf::LocationInfoMode::FAST, | 
| 257 | 0 |                                                  inline_frames)) { | 
| 258 | 0 |                     current_frame.file = location.file.toString(); | 
| 259 | 0 |                     current_frame.line = location.line; | 
| 260 | 0 |                 } | 
| 261 | 0 |             } | 
| 262 | 0 |         } else { | 
| 263 | 0 |             current_frame.object = "?"; | 
| 264 | 0 |         } | 
| 265 |  | 
 | 
| 266 | 0 |         if (const auto* symbol = symbol_index.findSymbol(current_frame.virtual_addr)) { | 
| 267 | 0 |             current_frame.symbol = demangle(symbol->name); | 
| 268 | 0 |         } else { | 
| 269 | 0 |             current_frame.symbol = "?"; | 
| 270 | 0 |         } | 
| 271 | 0 |     } | 
| 272 |  | #else | 
| 273 |  |     for (size_t i = 0; i < size; ++i) frames[i].virtual_addr = frame_pointers[i]; | 
| 274 |  | #endif | 
| 275 | 0 | } | 
| 276 |  |  | 
| 277 | 0 | StackTrace::StackTrace(const ucontext_t& signal_context) { | 
| 278 | 0 |     tryCapture(); | 
| 279 |  |  | 
| 280 |  |     /// This variable from signal handler is not instrumented by Memory Sanitizer. | 
| 281 | 0 |     __msan_unpoison(&signal_context, sizeof(signal_context)); | 
| 282 |  | 
 | 
| 283 | 0 |     void* caller_address = getCallerAddress(signal_context); | 
| 284 |  | 
 | 
| 285 | 0 |     if (size == 0 && caller_address) { | 
| 286 | 0 |         frame_pointers[0] = caller_address; | 
| 287 | 0 |         size = 1; | 
| 288 | 0 |     } else { | 
| 289 |  |         /// Skip excessive stack frames that we have created while finding stack trace. | 
| 290 | 0 |         for (size_t i = 0; i < size; ++i) { | 
| 291 | 0 |             if (frame_pointers[i] == caller_address) { | 
| 292 | 0 |                 offset = i; | 
| 293 | 0 |                 break; | 
| 294 | 0 |             } | 
| 295 | 0 |         } | 
| 296 | 0 |     } | 
| 297 | 0 | } | 
| 298 |  |  | 
| 299 | 1.59k | void StackTrace::tryCapture() { | 
| 300 |  |     // When unw_backtrace is not available, fall back on the standard | 
| 301 |  |     // `backtrace` function from execinfo.h. | 
| 302 | 1.59k | #if defined(USE_UNWIND) && USE_UNWIND && defined(__x86_64__) // TODO | 
| 303 | 1.59k |     size = unw_backtrace(frame_pointers.data(), capacity); | 
| 304 |  | #else | 
| 305 |  |     size = backtrace(frame_pointers.data(), capacity); | 
| 306 |  | #endif | 
| 307 | 1.59k |     __msan_unpoison(frame_pointers.data(), size * sizeof(frame_pointers[0])); | 
| 308 | 1.59k | } | 
| 309 |  |  | 
| 310 |  | /// ClickHouse uses bundled libc++ so type names will be the same on every system thus it's safe to hardcode them | 
| 311 |  | constexpr std::pair<std::string_view, std::string_view> replacements[] = { | 
| 312 |  |         {"::__1", ""}, | 
| 313 |  |         {"std::basic_string<char, std::char_traits<char>, std::allocator<char>>", "std::string"}}; | 
| 314 |  |  | 
| 315 | 4.92k | std::string collapseNames(std::string&& haystack) { | 
| 316 |  |     // TODO: surely there is a written version already for better in place search&replace | 
| 317 | 9.85k |     for (auto [needle, to] : replacements) { | 
| 318 | 9.85k |         size_t pos = 0; | 
| 319 | 9.85k |         while ((pos = haystack.find(needle, pos)) != std::string::npos) { | 
| 320 | 0 |             haystack.replace(pos, needle.length(), to); | 
| 321 | 0 |             pos += to.length(); | 
| 322 | 0 |         } | 
| 323 | 9.85k |     } | 
| 324 |  |  | 
| 325 | 4.92k |     return haystack; | 
| 326 | 4.92k | } | 
| 327 |  |  | 
| 328 |  | struct StackTraceRefTriple { | 
| 329 |  |     const StackTrace::FramePointers& pointers; | 
| 330 |  |     size_t offset; | 
| 331 |  |     size_t size; | 
| 332 |  | }; | 
| 333 |  |  | 
| 334 |  | struct StackTraceTriple { | 
| 335 |  |     StackTrace::FramePointers pointers; | 
| 336 |  |     size_t offset; | 
| 337 |  |     size_t size; | 
| 338 |  | }; | 
| 339 |  |  | 
| 340 |  | template <class T> | 
| 341 |  | concept MaybeRef = std::is_same_v<T, StackTraceTriple> || std::is_same_v<T, StackTraceRefTriple>; | 
| 342 |  |  | 
| 343 | 16.6k | constexpr bool operator<(const MaybeRef auto& left, const MaybeRef auto& right) { | 
| 344 | 16.6k |     return std::tuple {left.pointers, left.size, left.offset} < | 
| 345 | 16.6k |            std::tuple {right.pointers, right.size, right.offset}; | 
| 346 | 16.6k | } _ZltITk8MaybeRef16StackTraceTripleTk8MaybeRef19StackTraceRefTripleEbRKT_RKT0_| Line | Count | Source |  | 343 | 12.2k | constexpr bool operator<(const MaybeRef auto& left, const MaybeRef auto& right) { |  | 344 | 12.2k |     return std::tuple {left.pointers, left.size, left.offset} < |  | 345 | 12.2k |            std::tuple {right.pointers, right.size, right.offset}; |  | 346 | 12.2k | } | 
_ZltITk8MaybeRef19StackTraceRefTripleTk8MaybeRef16StackTraceTripleEbRKT_RKT0_| Line | Count | Source |  | 343 | 1.58k | constexpr bool operator<(const MaybeRef auto& left, const MaybeRef auto& right) { |  | 344 | 1.58k |     return std::tuple {left.pointers, left.size, left.offset} < |  | 345 | 1.58k |            std::tuple {right.pointers, right.size, right.offset}; |  | 346 | 1.58k | } | 
_ZltITk8MaybeRef16StackTraceTripleTk8MaybeRefS0_EbRKT_RKT0_| Line | Count | Source |  | 343 | 2.84k | constexpr bool operator<(const MaybeRef auto& left, const MaybeRef auto& right) { |  | 344 | 2.84k |     return std::tuple {left.pointers, left.size, left.offset} < |  | 345 | 2.84k |            std::tuple {right.pointers, right.size, right.offset}; |  | 346 | 2.84k | } | 
 | 
| 347 |  |  | 
| 348 |  | static void toStringEveryLineImpl([[maybe_unused]] const std::string dwarf_location_info_mode, | 
| 349 |  |                                   const StackTraceRefTriple& stack_trace, | 
| 350 | 248 |                                   std::function<void(std::string_view)> callback) { | 
| 351 | 248 |     if (stack_trace.size == 0) { | 
| 352 | 0 |         return callback("<Empty trace>"); | 
| 353 | 0 |     } | 
| 354 | 248 | #if defined(__ELF__) && !defined(__FreeBSD__) | 
| 355 |  |  | 
| 356 | 248 |     using enum doris::Dwarf::LocationInfoMode; | 
| 357 | 248 |     doris::Dwarf::LocationInfoMode mode; | 
| 358 | 248 |     auto dwarf_location_info_mode_lower = doris::to_lower(dwarf_location_info_mode); | 
| 359 | 248 |     if (dwarf_location_info_mode_lower == "disabled") { | 
| 360 | 229 |         mode = DISABLED; | 
| 361 | 229 |     } else if (dwarf_location_info_mode_lower == "fast") { | 
| 362 | 19 |         mode = FAST; | 
| 363 | 19 |     } else if (dwarf_location_info_mode_lower == "full") { | 
| 364 | 0 |         mode = FULL; | 
| 365 | 0 |     } else if (dwarf_location_info_mode_lower == "full_with_inline") { | 
| 366 | 0 |         mode = FULL_WITH_INLINE; | 
| 367 | 0 |     } else { | 
| 368 | 0 |         LOG(INFO) << "invalid LocationInfoMode: " << dwarf_location_info_mode; | 
| 369 | 0 |         mode = DISABLED; | 
| 370 | 0 |     } | 
| 371 | 248 |     auto symbol_index_ptr = doris::SymbolIndex::instance(); | 
| 372 | 248 |     const doris::SymbolIndex& symbol_index = *symbol_index_ptr; | 
| 373 | 248 |     std::unordered_map<std::string, doris::Dwarf> dwarfs; | 
| 374 | 5.17k |     for (size_t i = stack_trace.offset; i < stack_trace.size; ++i) { | 
| 375 | 4.92k |         std::vector<doris::Dwarf::SymbolizedFrame> inline_frames; | 
| 376 | 4.92k |         const void* virtual_addr = stack_trace.pointers[i]; | 
| 377 | 4.92k |         const auto* object = symbol_index.findObject(virtual_addr); | 
| 378 | 4.92k |         uintptr_t virtual_offset = object ? uintptr_t(object->address_begin) : 0; | 
| 379 | 4.92k |         const void* physical_addr = | 
| 380 | 4.92k |                 reinterpret_cast<const void*>(uintptr_t(virtual_addr) - virtual_offset); | 
| 381 |  |  | 
| 382 | 4.92k |         std::stringstream out; | 
| 383 | 4.92k |         out << "\t" << i << "# "; | 
| 384 | 4.92k |         if (i < 10) { // for alignment | 
| 385 | 2.48k |             out << " "; | 
| 386 | 2.48k |         } | 
| 387 |  |  | 
| 388 | 4.92k |         if (const auto* const symbol = symbol_index.findSymbol(virtual_addr)) { | 
| 389 | 4.92k |             out << collapseNames(demangle(symbol->name)); | 
| 390 | 4.92k |         } else { | 
| 391 | 0 |             out << "?"; | 
| 392 | 0 |         } | 
| 393 |  |  | 
| 394 | 4.92k |         if (std::error_code ec; object && std::filesystem::exists(object->name, ec) && !ec) { | 
| 395 | 4.92k |             auto dwarf_it = dwarfs.try_emplace(object->name, object->elf).first; | 
| 396 |  |  | 
| 397 | 4.92k |             doris::Dwarf::LocationInfo location; | 
| 398 |  |  | 
| 399 | 4.92k |             if (dwarf_it->second.findAddress(uintptr_t(physical_addr), location, mode, | 
| 400 | 4.92k |                                              inline_frames)) { | 
| 401 | 145 |                 out << " at " << location.file.toString() << ":" << location.line; | 
| 402 | 145 |             } | 
| 403 | 4.92k |         } | 
| 404 |  |  | 
| 405 |  |         // Do not display the stack address and file name, it is not important. | 
| 406 |  |         // if (shouldShowAddress(physical_addr)) { | 
| 407 |  |         //     out << " @ "; | 
| 408 |  |         //     writePointerHex(physical_addr, out); | 
| 409 |  |         // } | 
| 410 |  |  | 
| 411 |  |         // out << "  in " << (object ? object->name : "?"); | 
| 412 |  |  | 
| 413 | 4.92k |         callback(out.str()); | 
| 414 |  |  | 
| 415 | 4.92k |         for (size_t j = 0; j < inline_frames.size(); ++j) { | 
| 416 | 0 |             const auto& frame = inline_frames[j]; | 
| 417 | 0 |             callback(fmt::format("\t{}.{}. inlined from {}: {}:{}", i, j + 1, | 
| 418 | 0 |                                  collapseNames(demangle(frame.name)), | 
| 419 | 0 |                                  frame.location.file.toString(), frame.location.line)); | 
| 420 | 0 |         } | 
| 421 | 4.92k |     } | 
| 422 |  | #else | 
| 423 |  |     for (size_t i = stack_trace.offset; i < stack_trace.size; ++i) | 
| 424 |  |         if (const void* const addr = stack_trace.pointers[i]; shouldShowAddress(addr)) | 
| 425 |  |             callback(fmt::format("{}. {}", i, addr)); | 
| 426 |  | #endif | 
| 427 | 248 | } | 
| 428 |  |  | 
| 429 | 0 | void StackTrace::toStringEveryLine(std::function<void(std::string_view)> callback) const { | 
| 430 | 0 |     toStringEveryLineImpl("FULL_WITH_INLINE", {frame_pointers, offset, size}, std::move(callback)); | 
| 431 | 0 | } | 
| 432 |  |  | 
| 433 |  | using StackTraceCache = std::map<StackTraceTriple, std::string, std::less<>>; | 
| 434 |  |  | 
| 435 | 1.59k | static StackTraceCache& cacheInstance() { | 
| 436 | 1.59k |     static StackTraceCache cache; | 
| 437 | 1.59k |     return cache; | 
| 438 | 1.59k | } | 
| 439 |  |  | 
| 440 |  | static std::mutex stacktrace_cache_mutex; | 
| 441 |  |  | 
| 442 |  | std::string toStringCached(const StackTrace::FramePointers& pointers, size_t offset, size_t size, | 
| 443 | 1.59k |                            const std::string& dwarf_location_info_mode) { | 
| 444 |  |     /// Calculation of stack trace text is extremely slow. | 
| 445 |  |     /// We use simple cache because otherwise the server could be overloaded by trash queries. | 
| 446 |  |     /// Note that this cache can grow unconditionally, but practically it should be small. | 
| 447 | 1.59k |     std::lock_guard lock {stacktrace_cache_mutex}; | 
| 448 |  |  | 
| 449 | 1.59k |     StackTraceCache& cache = cacheInstance(); | 
| 450 | 1.59k |     const StackTraceRefTriple key {pointers, offset, size}; | 
| 451 |  |  | 
| 452 | 1.59k |     if (auto it = cache.find(key); it != cache.end()) { | 
| 453 | 1.34k |         return it->second; | 
| 454 | 1.34k |     } else { | 
| 455 | 248 |         std::stringstream out; | 
| 456 | 248 |         toStringEveryLineImpl(dwarf_location_info_mode, key, | 
| 457 | 4.92k |                               [&](std::string_view str) { out << str << '\n'; }); | 
| 458 |  |  | 
| 459 | 248 |         return cache.emplace(StackTraceTriple {pointers, offset, size}, out.str()).first->second; | 
| 460 | 248 |     } | 
| 461 | 1.59k | } | 
| 462 |  |  | 
| 463 |  | std::string StackTrace::toString(int start_pointers_index, | 
| 464 | 1.59k |                                  const std::string& dwarf_location_info_mode) const { | 
| 465 |  |     // Default delete the first three frame pointers, which are inside the stack_trace.cpp. | 
| 466 | 1.59k |     start_pointers_index += 3; | 
| 467 | 1.59k |     StackTrace::FramePointers frame_pointers_raw {}; | 
| 468 | 1.59k |     std::copy(frame_pointers.begin() + start_pointers_index, frame_pointers.end(), | 
| 469 | 1.59k |               frame_pointers_raw.begin()); | 
| 470 | 1.59k |     return toStringCached(frame_pointers_raw, offset, size - start_pointers_index, | 
| 471 | 1.59k |                           dwarf_location_info_mode); | 
| 472 | 1.59k | } | 
| 473 |  |  | 
| 474 |  | std::string StackTrace::toString(void** frame_pointers_raw, size_t offset, size_t size, | 
| 475 | 0 |                                  const std::string& dwarf_location_info_mode) { | 
| 476 | 0 |     __msan_unpoison(frame_pointers_raw, size * sizeof(*frame_pointers_raw)); | 
| 477 |  | 
 | 
| 478 | 0 |     StackTrace::FramePointers frame_pointers {}; | 
| 479 | 0 |     std::copy_n(frame_pointers_raw, size, frame_pointers.begin()); | 
| 480 |  | 
 | 
| 481 | 0 |     return toStringCached(frame_pointers, offset, size, dwarf_location_info_mode); | 
| 482 | 0 | } | 
| 483 |  |  | 
| 484 | 0 | void StackTrace::createCache() { | 
| 485 | 0 |     std::lock_guard lock {stacktrace_cache_mutex}; | 
| 486 | 0 |     cacheInstance(); | 
| 487 | 0 | } | 
| 488 |  |  | 
| 489 | 0 | void StackTrace::dropCache() { | 
| 490 | 0 |     std::lock_guard lock {stacktrace_cache_mutex}; | 
| 491 | 0 |     cacheInstance().clear(); | 
| 492 | 0 | } |