diff --git a/node.gyp b/node.gyp index 6a3a8c015e71c0..2f3c342a74e3c0 100644 --- a/node.gyp +++ b/node.gyp @@ -316,6 +316,7 @@ 'src/cares_wrap.cc', 'src/connection_wrap.cc', 'src/connect_wrap.cc', + 'src/debug_utils.cc', 'src/env.cc', 'src/exceptions.cc', 'src/fs_event_wrap.cc', @@ -495,9 +496,6 @@ 'defines': [ 'HAVE_INSPECTOR=0' ] }], [ 'OS=="win"', { - 'sources': [ - 'src/backtrace_win32.cc', - ], 'conditions': [ [ 'node_intermediate_lib_type!="static_library"', { 'sources': [ @@ -506,8 +504,6 @@ }], ], 'libraries': [ '-lpsapi.lib' ] - }, { # POSIX - 'sources': [ 'src/backtrace_posix.cc' ], }], [ 'node_use_etw=="true"', { 'defines': [ 'HAVE_ETW=1' ], diff --git a/src/backtrace_posix.cc b/src/backtrace_posix.cc deleted file mode 100644 index c7a6bea1938a7c..00000000000000 --- a/src/backtrace_posix.cc +++ /dev/null @@ -1,49 +0,0 @@ -#include "node_internals.h" - -#if defined(__linux__) -#include -#endif - -#if defined(__linux__) && !defined(__GLIBC__) || \ - defined(__UCLIBC__) || \ - defined(_AIX) -#define HAVE_EXECINFO_H 0 -#else -#define HAVE_EXECINFO_H 1 -#endif - -#if HAVE_EXECINFO_H -#include -#include -#include -#include -#endif - -namespace node { - -void DumpBacktrace(FILE* fp) { -#if HAVE_EXECINFO_H - void* frames[256]; - const int size = backtrace(frames, arraysize(frames)); - for (int i = 1; i < size; i += 1) { - void* frame = frames[i]; - fprintf(fp, "%2d: ", i); - Dl_info info; - const bool have_info = dladdr(frame, &info); - if (!have_info || info.dli_sname == nullptr) { - fprintf(fp, "%p", frame); - } else if (char* demangled = abi::__cxa_demangle(info.dli_sname, 0, 0, 0)) { - fprintf(fp, "%s", demangled); - free(demangled); - } else { - fprintf(fp, "%s", info.dli_sname); - } - if (have_info && info.dli_fname != nullptr) { - fprintf(fp, " [%s]", info.dli_fname); - } - fprintf(fp, "\n"); - } -#endif // HAVE_EXECINFO_H -} - -} // namespace node diff --git a/src/backtrace_win32.cc b/src/backtrace_win32.cc deleted file mode 100644 index ccc3af9455b18d..00000000000000 --- a/src/backtrace_win32.cc +++ /dev/null @@ -1,40 +0,0 @@ -#include "node_internals.h" -#include -#include - -namespace node { - -void DumpBacktrace(FILE* fp) { - void* frames[256]; - int size = CaptureStackBackTrace(0, arraysize(frames), frames, nullptr); - HANDLE process = GetCurrentProcess(); - (void)SymInitialize(process, nullptr, true); - - // Ref: https://msdn.microsoft.com/en-en/library/windows/desktop/ms680578(v=vs.85).aspx - char info_buf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME]; - SYMBOL_INFO* info = reinterpret_cast(info_buf); - char demangled[MAX_SYM_NAME]; - - for (int i = 1; i < size; i += 1) { - void* frame = frames[i]; - fprintf(fp, "%2d: ", i); - info->MaxNameLen = MAX_SYM_NAME; - info->SizeOfStruct = sizeof(SYMBOL_INFO); - const bool have_info = - SymFromAddr(process, reinterpret_cast(frame), nullptr, info); - if (!have_info || strlen(info->Name) == 0) { - fprintf(fp, "%p", frame); - } else if (UnDecorateSymbolName(info->Name, - demangled, - sizeof(demangled), - UNDNAME_COMPLETE)) { - fprintf(fp, "%s", demangled); - } else { - fprintf(fp, "%s", info->Name); - } - fprintf(fp, "\n"); - } - (void)SymCleanup(process); -} - -} // namespace node diff --git a/src/debug_utils.cc b/src/debug_utils.cc new file mode 100644 index 00000000000000..53212fcd05e3f1 --- /dev/null +++ b/src/debug_utils.cc @@ -0,0 +1,180 @@ +#include "debug_utils.h" +#include "node_internals.h" + +#ifdef __POSIX__ +#if defined(__linux__) +#include +#endif + +#if defined(__linux__) && !defined(__GLIBC__) || \ + defined(__UCLIBC__) || \ + defined(_AIX) +#define HAVE_EXECINFO_H 0 +#else +#define HAVE_EXECINFO_H 1 +#endif + +#if HAVE_EXECINFO_H +#include +#include +#include +#include +#include +#include +#endif + +#else // __POSIX__ + +#include +#include + +#endif // __POSIX__ + +namespace node { + +#ifdef __POSIX__ +#if HAVE_EXECINFO_H +class PosixSymbolDebuggingContext final : public NativeSymbolDebuggingContext { + public: + PosixSymbolDebuggingContext() : pagesize_(getpagesize()) { } + + SymbolInfo LookupSymbol(void* address) override { + Dl_info info; + const bool have_info = dladdr(address, &info); + SymbolInfo ret; + if (!have_info) + return ret; + + if (info.dli_sname != nullptr) { + if (char* demangled = abi::__cxa_demangle(info.dli_sname, 0, 0, 0)) { + ret.name = demangled; + free(demangled); + } else { + ret.name = info.dli_sname; + } + } + + if (info.dli_fname != nullptr) { + ret.filename = info.dli_fname; + } + + return ret; + } + + bool IsMapped(void* address) override { + void* page_aligned = reinterpret_cast( + reinterpret_cast(address) & ~(pagesize_ - 1)); + return msync(page_aligned, pagesize_, MS_ASYNC) == 0; + } + + int GetStackTrace(void** frames, int count) override { + return backtrace(frames, count); + } + + private: + uintptr_t pagesize_; +}; + +std::unique_ptr +NativeSymbolDebuggingContext::New() { + return std::unique_ptr( + new PosixSymbolDebuggingContext()); +} + +#else // HAVE_EXECINFO_H + +std::unique_ptr +NativeSymbolDebuggingContext::New() { + return std::unique_ptr( + new NativeSymbolDebuggingContext()); +} + +#endif // HAVE_EXECINFO_H + +#else // __POSIX__ + +class Win32SymbolDebuggingContext final : public NativeSymbolDebuggingContext { + public: + Win32SymbolDebuggingContext() { + current_process_ = GetCurrentProcess(); + USE(SymInitialize(process, nullptr, true)); + } + + ~Win32SymbolDebuggingContext() { + USE(SymCleanup(process)); + } + + SymbolInfo LookupSymbol(void* address) override { + // Ref: https://msdn.microsoft.com/en-en/library/windows/desktop/ms680578(v=vs.85).aspx + char info_buf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME]; + SYMBOL_INFO* info = reinterpret_cast(info_buf); + char demangled[MAX_SYM_NAME]; + + info->MaxNameLen = MAX_SYM_NAME; + info->SizeOfStruct = sizeof(SYMBOL_INFO); + + SymbolInfo ret; + const bool have_info = SymFromAddr(process, + reinterpret_cast(address), + nullptr, + info); + if (have_info && strlen(info->Name) == 0) { + if (UnDecorateSymbolName(info->Name, + demangled_, + sizeof(demangled_), + UNDNAME_COMPLETE)) { + ret.name = demangled_; + } else { + ret.name = info->Name; + } + } + + return ret; + } + + bool IsMapped(void* address) override { + MEMORY_BASIC_INFORMATION info; + + if (VirtualQuery(address, &info, sizeof(info)) != info) + return false; + + return info.State == MEM_COMMIT && info.Protect != 0; + } + + int GetStackTrace(void** frames, int count) override { + return CaptureStackBackTrace(0, count, frames, nullptr); + } + + private: + HANDLE current_process_; +}; + +NativeSymbolDebuggingContext::New() { + return std::unique_ptr( + new Win32SymbolDebuggingContext()); +} + +#endif // __POSIX__ + +std::string NativeSymbolDebuggingContext::SymbolInfo::Display() const { + std::string ret = name; + if (!filename.empty()) { + ret += " ["; + ret += filename; + ret += ']'; + } + return ret; +} + +void DumpBacktrace(FILE* fp) { + auto sym_ctx = NativeSymbolDebuggingContext::New(); + void* frames[256]; + const int size = sym_ctx->GetStackTrace(frames, arraysize(frames)); + for (int i = 1; i < size; i += 1) { + void* frame = frames[i]; + fprintf(fp, "%2d: %p %s\n", + i, frame, sym_ctx->LookupSymbol(frame).Display().c_str()); + } +} + +} // namespace node diff --git a/src/debug_utils.h b/src/debug_utils.h index f10342c79d35be..4d9ce253c0defb 100644 --- a/src/debug_utils.h +++ b/src/debug_utils.h @@ -84,6 +84,24 @@ inline void FORCE_INLINE Debug(AsyncWrap* async_wrap, Debug(async_wrap, format.c_str(), std::forward(args)...); } +// Debug helper for inspecting the currently running `node` executable. +class NativeSymbolDebuggingContext { + public: + static std::unique_ptr New(); + + class SymbolInfo { + public: + std::string name; + std::string filename; + + std::string Display() const; + }; + + virtual ~NativeSymbolDebuggingContext() {} + virtual SymbolInfo LookupSymbol(void* address) { return { "", "" }; } + virtual bool IsMapped(void* address) { return false; } + virtual int GetStackTrace(void** frames, int count) { return 0; } +}; } // namespace node