Skip to content

Commit aa468ab

Browse files
addaleaxtargos
authored andcommitted
src: unify native symbol inspection code
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 <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Gus Caplan <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Benjamin Gruenbaum <[email protected]> Reviewed-By: Colin Ihrig <[email protected]>
1 parent 5d3dfed commit aa468ab

5 files changed

+199
-94
lines changed

node.gyp

+1-5
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,7 @@
316316
'src/cares_wrap.cc',
317317
'src/connection_wrap.cc',
318318
'src/connect_wrap.cc',
319+
'src/debug_utils.cc',
319320
'src/env.cc',
320321
'src/exceptions.cc',
321322
'src/fs_event_wrap.cc',
@@ -495,9 +496,6 @@
495496
'defines': [ 'HAVE_INSPECTOR=0' ]
496497
}],
497498
[ 'OS=="win"', {
498-
'sources': [
499-
'src/backtrace_win32.cc',
500-
],
501499
'conditions': [
502500
[ 'node_intermediate_lib_type!="static_library"', {
503501
'sources': [
@@ -506,8 +504,6 @@
506504
}],
507505
],
508506
'libraries': [ '-lpsapi.lib' ]
509-
}, { # POSIX
510-
'sources': [ 'src/backtrace_posix.cc' ],
511507
}],
512508
[ 'node_use_etw=="true"', {
513509
'defines': [ 'HAVE_ETW=1' ],

src/backtrace_posix.cc

-49
This file was deleted.

src/backtrace_win32.cc

-40
This file was deleted.

src/debug_utils.cc

+180
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
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

src/debug_utils.h

+18
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,24 @@ inline void FORCE_INLINE Debug(AsyncWrap* async_wrap,
8484
Debug(async_wrap, format.c_str(), std::forward<Args>(args)...);
8585
}
8686

87+
// Debug helper for inspecting the currently running `node` executable.
88+
class NativeSymbolDebuggingContext {
89+
public:
90+
static std::unique_ptr<NativeSymbolDebuggingContext> New();
91+
92+
class SymbolInfo {
93+
public:
94+
std::string name;
95+
std::string filename;
96+
97+
std::string Display() const;
98+
};
99+
100+
virtual ~NativeSymbolDebuggingContext() {}
101+
virtual SymbolInfo LookupSymbol(void* address) { return { "", "" }; }
102+
virtual bool IsMapped(void* address) { return false; }
103+
virtual int GetStackTrace(void** frames, int count) { return 0; }
104+
};
87105

88106
} // namespace node
89107

0 commit comments

Comments
 (0)