|  | 
|  | 1 | +#include "debug_utils.h" | 
|  | 2 | +#include "node_internals.h" | 
|  | 3 | + | 
|  | 4 | +#ifdef __POSIX__ | 
|  | 5 | +#if defined(__linux__) | 
|  | 6 | +#include <features.h> | 
|  | 7 | +#endif | 
|  | 8 | + | 
|  | 9 | +#if defined(__linux__) && !defined(__GLIBC__) || \ | 
|  | 10 | +    defined(__UCLIBC__) || \ | 
|  | 11 | +    defined(_AIX) | 
|  | 12 | +#define HAVE_EXECINFO_H 0 | 
|  | 13 | +#else | 
|  | 14 | +#define HAVE_EXECINFO_H 1 | 
|  | 15 | +#endif | 
|  | 16 | + | 
|  | 17 | +#if HAVE_EXECINFO_H | 
|  | 18 | +#include <cxxabi.h> | 
|  | 19 | +#include <dlfcn.h> | 
|  | 20 | +#include <execinfo.h> | 
|  | 21 | +#include <unistd.h> | 
|  | 22 | +#include <sys/mman.h> | 
|  | 23 | +#include <stdio.h> | 
|  | 24 | +#endif | 
|  | 25 | + | 
|  | 26 | +#else  // __POSIX__ | 
|  | 27 | + | 
|  | 28 | +#include <windows.h> | 
|  | 29 | +#include <dbghelp.h> | 
|  | 30 | + | 
|  | 31 | +#endif  // __POSIX__ | 
|  | 32 | + | 
|  | 33 | +namespace node { | 
|  | 34 | + | 
|  | 35 | +#ifdef __POSIX__ | 
|  | 36 | +#if HAVE_EXECINFO_H | 
|  | 37 | +class PosixSymbolDebuggingContext final : public NativeSymbolDebuggingContext { | 
|  | 38 | + public: | 
|  | 39 | +  PosixSymbolDebuggingContext() : pagesize_(getpagesize()) { } | 
|  | 40 | + | 
|  | 41 | +  SymbolInfo LookupSymbol(void* address) override { | 
|  | 42 | +    Dl_info info; | 
|  | 43 | +    const bool have_info = dladdr(address, &info); | 
|  | 44 | +    SymbolInfo ret; | 
|  | 45 | +    if (!have_info) | 
|  | 46 | +      return ret; | 
|  | 47 | + | 
|  | 48 | +    if (info.dli_sname != nullptr) { | 
|  | 49 | +      if (char* demangled = abi::__cxa_demangle(info.dli_sname, 0, 0, 0)) { | 
|  | 50 | +        ret.name = demangled; | 
|  | 51 | +        free(demangled); | 
|  | 52 | +      } else { | 
|  | 53 | +        ret.name = info.dli_sname; | 
|  | 54 | +      } | 
|  | 55 | +    } | 
|  | 56 | + | 
|  | 57 | +    if (info.dli_fname != nullptr) { | 
|  | 58 | +      ret.filename = info.dli_fname; | 
|  | 59 | +    } | 
|  | 60 | + | 
|  | 61 | +    return ret; | 
|  | 62 | +  } | 
|  | 63 | + | 
|  | 64 | +  bool IsMapped(void* address) override { | 
|  | 65 | +    void* page_aligned = reinterpret_cast<void*>( | 
|  | 66 | +        reinterpret_cast<uintptr_t>(address) & ~(pagesize_ - 1)); | 
|  | 67 | +    return msync(page_aligned, pagesize_, MS_ASYNC) == 0; | 
|  | 68 | +  } | 
|  | 69 | + | 
|  | 70 | +  int GetStackTrace(void** frames, int count) override { | 
|  | 71 | +    return backtrace(frames, count); | 
|  | 72 | +  } | 
|  | 73 | + | 
|  | 74 | + private: | 
|  | 75 | +  uintptr_t pagesize_; | 
|  | 76 | +}; | 
|  | 77 | + | 
|  | 78 | +std::unique_ptr<NativeSymbolDebuggingContext> | 
|  | 79 | +NativeSymbolDebuggingContext::New() { | 
|  | 80 | +  return std::unique_ptr<NativeSymbolDebuggingContext>( | 
|  | 81 | +      new PosixSymbolDebuggingContext()); | 
|  | 82 | +} | 
|  | 83 | + | 
|  | 84 | +#else  // HAVE_EXECINFO_H | 
|  | 85 | + | 
|  | 86 | +std::unique_ptr<NativeSymbolDebuggingContext> | 
|  | 87 | +NativeSymbolDebuggingContext::New() { | 
|  | 88 | +  return std::unique_ptr<NativeSymbolDebuggingContext>( | 
|  | 89 | +      new NativeSymbolDebuggingContext()); | 
|  | 90 | +} | 
|  | 91 | + | 
|  | 92 | +#endif  // HAVE_EXECINFO_H | 
|  | 93 | + | 
|  | 94 | +#else  // __POSIX__ | 
|  | 95 | + | 
|  | 96 | +class Win32SymbolDebuggingContext final : public NativeSymbolDebuggingContext { | 
|  | 97 | + public: | 
|  | 98 | +  Win32SymbolDebuggingContext() { | 
|  | 99 | +    current_process_ = GetCurrentProcess(); | 
|  | 100 | +    USE(SymInitialize(process, nullptr, true)); | 
|  | 101 | +  } | 
|  | 102 | + | 
|  | 103 | +  ~Win32SymbolDebuggingContext() { | 
|  | 104 | +    USE(SymCleanup(process)); | 
|  | 105 | +  } | 
|  | 106 | + | 
|  | 107 | +  SymbolInfo LookupSymbol(void* address) override { | 
|  | 108 | +    // Ref: https://msdn.microsoft.com/en-en/library/windows/desktop/ms680578(v=vs.85).aspx | 
|  | 109 | +    char info_buf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME]; | 
|  | 110 | +    SYMBOL_INFO* info = reinterpret_cast<SYMBOL_INFO*>(info_buf); | 
|  | 111 | +    char demangled[MAX_SYM_NAME]; | 
|  | 112 | + | 
|  | 113 | +    info->MaxNameLen = MAX_SYM_NAME; | 
|  | 114 | +    info->SizeOfStruct = sizeof(SYMBOL_INFO); | 
|  | 115 | + | 
|  | 116 | +    SymbolInfo ret; | 
|  | 117 | +    const bool have_info = SymFromAddr(process, | 
|  | 118 | +                                       reinterpret_cast<DWORD64>(address), | 
|  | 119 | +                                       nullptr, | 
|  | 120 | +                                       info); | 
|  | 121 | +    if (have_info && strlen(info->Name) == 0) { | 
|  | 122 | +      if (UnDecorateSymbolName(info->Name, | 
|  | 123 | +                               demangled_, | 
|  | 124 | +                               sizeof(demangled_), | 
|  | 125 | +                               UNDNAME_COMPLETE)) { | 
|  | 126 | +        ret.name = demangled_; | 
|  | 127 | +      } else { | 
|  | 128 | +        ret.name = info->Name; | 
|  | 129 | +      } | 
|  | 130 | +    } | 
|  | 131 | + | 
|  | 132 | +    return ret; | 
|  | 133 | +  } | 
|  | 134 | + | 
|  | 135 | +  bool IsMapped(void* address) override { | 
|  | 136 | +    MEMORY_BASIC_INFORMATION info; | 
|  | 137 | + | 
|  | 138 | +    if (VirtualQuery(address, &info, sizeof(info)) != info) | 
|  | 139 | +      return false; | 
|  | 140 | + | 
|  | 141 | +    return info.State == MEM_COMMIT && info.Protect != 0; | 
|  | 142 | +  } | 
|  | 143 | + | 
|  | 144 | +  int GetStackTrace(void** frames, int count) override { | 
|  | 145 | +    return CaptureStackBackTrace(0, count, frames, nullptr); | 
|  | 146 | +  } | 
|  | 147 | + | 
|  | 148 | + private: | 
|  | 149 | +  HANDLE current_process_; | 
|  | 150 | +}; | 
|  | 151 | + | 
|  | 152 | +NativeSymbolDebuggingContext::New() { | 
|  | 153 | +  return std::unique_ptr<NativeSymbolDebuggingContext>( | 
|  | 154 | +      new Win32SymbolDebuggingContext()); | 
|  | 155 | +} | 
|  | 156 | + | 
|  | 157 | +#endif  // __POSIX__ | 
|  | 158 | + | 
|  | 159 | +std::string NativeSymbolDebuggingContext::SymbolInfo::Display() const { | 
|  | 160 | +  std::string ret = name; | 
|  | 161 | +  if (!filename.empty()) { | 
|  | 162 | +    ret += " ["; | 
|  | 163 | +    ret += filename; | 
|  | 164 | +    ret += ']'; | 
|  | 165 | +  } | 
|  | 166 | +  return ret; | 
|  | 167 | +} | 
|  | 168 | + | 
|  | 169 | +void DumpBacktrace(FILE* fp) { | 
|  | 170 | +  auto sym_ctx = NativeSymbolDebuggingContext::New(); | 
|  | 171 | +  void* frames[256]; | 
|  | 172 | +  const int size = sym_ctx->GetStackTrace(frames, arraysize(frames)); | 
|  | 173 | +  for (int i = 1; i < size; i += 1) { | 
|  | 174 | +    void* frame = frames[i]; | 
|  | 175 | +    fprintf(fp, "%2d: %p %s\n", | 
|  | 176 | +            i, frame, sym_ctx->LookupSymbol(frame).Display().c_str()); | 
|  | 177 | +  } | 
|  | 178 | +} | 
|  | 179 | + | 
|  | 180 | +}  // namespace node | 
0 commit comments