Skip to content

Commit

Permalink
src: unify native symbol inspection code
Browse files Browse the repository at this point in the history
Use a single file, and a single interface, for inspecting
symbols in the current process for debugging.

PR-URL: #21238
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
  • Loading branch information
addaleax authored and targos committed Jun 13, 2018
1 parent 5d3dfed commit aa468ab
Show file tree
Hide file tree
Showing 5 changed files with 199 additions and 94 deletions.
6 changes: 1 addition & 5 deletions node.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -495,9 +496,6 @@
'defines': [ 'HAVE_INSPECTOR=0' ]
}],
[ 'OS=="win"', {
'sources': [
'src/backtrace_win32.cc',
],
'conditions': [
[ 'node_intermediate_lib_type!="static_library"', {
'sources': [
Expand All @@ -506,8 +504,6 @@
}],
],
'libraries': [ '-lpsapi.lib' ]
}, { # POSIX
'sources': [ 'src/backtrace_posix.cc' ],
}],
[ 'node_use_etw=="true"', {
'defines': [ 'HAVE_ETW=1' ],
Expand Down
49 changes: 0 additions & 49 deletions src/backtrace_posix.cc

This file was deleted.

40 changes: 0 additions & 40 deletions src/backtrace_win32.cc

This file was deleted.

180 changes: 180 additions & 0 deletions src/debug_utils.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
#include "debug_utils.h"
#include "node_internals.h"

#ifdef __POSIX__
#if defined(__linux__)
#include <features.h>
#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 <cxxabi.h>
#include <dlfcn.h>
#include <execinfo.h>
#include <unistd.h>
#include <sys/mman.h>
#include <stdio.h>
#endif

#else // __POSIX__

#include <windows.h>
#include <dbghelp.h>

#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<void*>(
reinterpret_cast<uintptr_t>(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>
NativeSymbolDebuggingContext::New() {
return std::unique_ptr<NativeSymbolDebuggingContext>(
new PosixSymbolDebuggingContext());
}

#else // HAVE_EXECINFO_H

std::unique_ptr<NativeSymbolDebuggingContext>
NativeSymbolDebuggingContext::New() {
return std::unique_ptr<NativeSymbolDebuggingContext>(
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<SYMBOL_INFO*>(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<DWORD64>(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<NativeSymbolDebuggingContext>(
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
18 changes: 18 additions & 0 deletions src/debug_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,24 @@ inline void FORCE_INLINE Debug(AsyncWrap* async_wrap,
Debug(async_wrap, format.c_str(), std::forward<Args>(args)...);
}

// Debug helper for inspecting the currently running `node` executable.
class NativeSymbolDebuggingContext {
public:
static std::unique_ptr<NativeSymbolDebuggingContext> 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

Expand Down

0 comments on commit aa468ab

Please sign in to comment.