Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
src: unify native symbol inspection code
Use a single file, and a single interface, for inspecting
symbols in the current process for debugging.
  • Loading branch information
addaleax committed Jun 11, 2018
commit af954800b32946341540d38e2ae7f6ac45069ecc
6 changes: 1 addition & 5 deletions node.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,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 @@ -496,9 +497,6 @@
'defines': [ 'HAVE_INSPECTOR=0' ]
}],
[ 'OS=="win"', {
'sources': [
'src/backtrace_win32.cc',
],
'conditions': [
[ 'node_intermediate_lib_type!="static_library"', {
'sources': [
Expand All @@ -507,8 +505,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