1 |
|
|
#ifndef SRC_DEBUG_UTILS_H_ |
2 |
|
|
#define SRC_DEBUG_UTILS_H_ |
3 |
|
|
|
4 |
|
|
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS |
5 |
|
|
|
6 |
|
|
#include "async_wrap.h" |
7 |
|
|
#include "util.h" |
8 |
|
|
|
9 |
|
|
#include <algorithm> |
10 |
|
|
#include <sstream> |
11 |
|
|
#include <string> |
12 |
|
|
|
13 |
|
|
// Use FORCE_INLINE on functions that have a debug-category-enabled check first |
14 |
|
|
// and then ideally only a single function call following it, to maintain |
15 |
|
|
// performance for the common case (no debugging used). |
16 |
|
|
#ifdef __GNUC__ |
17 |
|
|
#define FORCE_INLINE __attribute__((always_inline)) |
18 |
|
|
#define COLD_NOINLINE __attribute__((cold, noinline)) |
19 |
|
|
#else |
20 |
|
|
#define FORCE_INLINE |
21 |
|
|
#define COLD_NOINLINE |
22 |
|
|
#endif |
23 |
|
|
|
24 |
|
|
namespace node { |
25 |
|
|
class Environment; |
26 |
|
|
|
27 |
|
|
template <typename T> |
28 |
|
|
inline std::string ToString(const T& value); |
29 |
|
|
|
30 |
|
|
// C++-style variant of sprintf()/fprintf() that: |
31 |
|
|
// - Returns an std::string |
32 |
|
|
// - Handles \0 bytes correctly |
33 |
|
|
// - Supports %p and %s. %d, %i and %u are aliases for %s. |
34 |
|
|
// - Accepts any class that has a ToString() method for stringification. |
35 |
|
|
template <typename... Args> |
36 |
|
|
inline std::string SPrintF(const char* format, Args&&... args); |
37 |
|
|
template <typename... Args> |
38 |
|
|
inline void FPrintF(FILE* file, const char* format, Args&&... args); |
39 |
|
|
void NODE_EXTERN_PRIVATE FWrite(FILE* file, const std::string& str); |
40 |
|
|
|
41 |
|
|
// Listing the AsyncWrap provider types first enables us to cast directly |
42 |
|
|
// from a provider type to a debug category. |
43 |
|
|
#define DEBUG_CATEGORY_NAMES(V) \ |
44 |
|
|
NODE_ASYNC_PROVIDER_TYPES(V) \ |
45 |
|
|
V(DIAGNOSTICS) \ |
46 |
|
|
V(HUGEPAGES) \ |
47 |
|
|
V(INSPECTOR_SERVER) \ |
48 |
|
|
V(INSPECTOR_PROFILER) \ |
49 |
|
|
V(CODE_CACHE) \ |
50 |
|
|
V(NGTCP2_DEBUG) \ |
51 |
|
|
V(WASI) \ |
52 |
|
|
V(MKSNAPSHOT) |
53 |
|
|
|
54 |
|
|
enum class DebugCategory : unsigned int { |
55 |
|
|
#define V(name) name, |
56 |
|
|
DEBUG_CATEGORY_NAMES(V) |
57 |
|
|
#undef V |
58 |
|
|
}; |
59 |
|
|
|
60 |
|
|
#define V(name) +1 |
61 |
|
|
constexpr unsigned int kDebugCategoryCount = DEBUG_CATEGORY_NAMES(V); |
62 |
|
|
#undef V |
63 |
|
|
|
64 |
|
|
class NODE_EXTERN_PRIVATE EnabledDebugList { |
65 |
|
|
public: |
66 |
|
|
bool FORCE_INLINE enabled(DebugCategory category) const { |
67 |
|
|
DCHECK_LT(static_cast<unsigned int>(category), kDebugCategoryCount); |
68 |
|
2291416 |
return enabled_[static_cast<unsigned int>(category)]; |
69 |
|
|
} |
70 |
|
|
|
71 |
|
|
// Uses NODE_DEBUG_NATIVE to initialize the categories. The env_vars variable |
72 |
|
|
// is parsed if it is not a nullptr, otherwise the system environment |
73 |
|
|
// variables are parsed. |
74 |
|
|
void Parse(std::shared_ptr<KVStore> env_vars = nullptr, |
75 |
|
|
v8::Isolate* isolate = nullptr); |
76 |
|
|
|
77 |
|
|
private: |
78 |
|
|
// Enable all categories matching cats. |
79 |
|
|
void Parse(const std::string& cats); |
80 |
|
118 |
void set_enabled(DebugCategory category) { |
81 |
|
|
DCHECK_LT(static_cast<unsigned int>(category), kDebugCategoryCount); |
82 |
|
118 |
enabled_[static_cast<int>(category)] = true; |
83 |
|
118 |
} |
84 |
|
|
|
85 |
|
|
bool enabled_[kDebugCategoryCount] = {false}; |
86 |
|
|
}; |
87 |
|
|
|
88 |
|
|
template <typename... Args> |
89 |
|
|
inline void FORCE_INLINE Debug(EnabledDebugList* list, |
90 |
|
|
DebugCategory cat, |
91 |
|
|
const char* format, |
92 |
|
|
Args&&... args); |
93 |
|
|
|
94 |
|
|
inline void FORCE_INLINE Debug(EnabledDebugList* list, |
95 |
|
|
DebugCategory cat, |
96 |
|
|
const char* message); |
97 |
|
|
|
98 |
|
|
template <typename... Args> |
99 |
|
|
inline void FORCE_INLINE |
100 |
|
|
Debug(Environment* env, DebugCategory cat, const char* format, Args&&... args); |
101 |
|
|
|
102 |
|
|
inline void FORCE_INLINE Debug(Environment* env, |
103 |
|
|
DebugCategory cat, |
104 |
|
|
const char* message); |
105 |
|
|
|
106 |
|
|
template <typename... Args> |
107 |
|
|
inline void Debug(Environment* env, |
108 |
|
|
DebugCategory cat, |
109 |
|
|
const std::string& format, |
110 |
|
|
Args&&... args); |
111 |
|
|
|
112 |
|
|
// Used internally by the 'real' Debug(AsyncWrap*, ...) functions below, so that |
113 |
|
|
// the FORCE_INLINE flag on them doesn't apply to the contents of this function |
114 |
|
|
// as well. |
115 |
|
|
// We apply COLD_NOINLINE to tell the compiler that it's not worth optimizing |
116 |
|
|
// this function for speed and it should rather focus on keeping it out of |
117 |
|
|
// hot code paths. In particular, we want to keep the string concatenating code |
118 |
|
|
// out of the function containing the original `Debug()` call. |
119 |
|
|
template <typename... Args> |
120 |
|
|
void COLD_NOINLINE UnconditionalAsyncWrapDebug(AsyncWrap* async_wrap, |
121 |
|
|
const char* format, |
122 |
|
|
Args&&... args); |
123 |
|
|
|
124 |
|
|
template <typename... Args> |
125 |
|
|
inline void FORCE_INLINE Debug(AsyncWrap* async_wrap, |
126 |
|
|
const char* format, |
127 |
|
|
Args&&... args); |
128 |
|
|
|
129 |
|
|
template <typename... Args> |
130 |
|
|
inline void FORCE_INLINE Debug(AsyncWrap* async_wrap, |
131 |
|
|
const std::string& format, |
132 |
|
|
Args&&... args); |
133 |
|
|
|
134 |
|
|
// Debug helper for inspecting the currently running `node` executable. |
135 |
|
|
class NativeSymbolDebuggingContext { |
136 |
|
|
public: |
137 |
|
|
static std::unique_ptr<NativeSymbolDebuggingContext> New(); |
138 |
|
|
|
139 |
|
|
class SymbolInfo { |
140 |
|
|
public: |
141 |
|
|
std::string name; |
142 |
|
|
std::string filename; |
143 |
|
|
size_t line = 0; |
144 |
|
|
size_t dis = 0; |
145 |
|
|
|
146 |
|
|
std::string Display() const; |
147 |
|
|
}; |
148 |
|
|
|
149 |
|
39 |
NativeSymbolDebuggingContext() = default; |
150 |
|
78 |
virtual ~NativeSymbolDebuggingContext() = default; |
151 |
|
|
|
152 |
|
|
virtual SymbolInfo LookupSymbol(void* address) { return {}; } |
153 |
|
|
virtual bool IsMapped(void* address) { return false; } |
154 |
|
|
virtual int GetStackTrace(void** frames, int count) { return 0; } |
155 |
|
|
|
156 |
|
|
NativeSymbolDebuggingContext(const NativeSymbolDebuggingContext&) = delete; |
157 |
|
|
NativeSymbolDebuggingContext(NativeSymbolDebuggingContext&&) = delete; |
158 |
|
|
NativeSymbolDebuggingContext operator=(NativeSymbolDebuggingContext&) |
159 |
|
|
= delete; |
160 |
|
|
NativeSymbolDebuggingContext operator=(NativeSymbolDebuggingContext&&) |
161 |
|
|
= delete; |
162 |
|
|
static std::vector<std::string> GetLoadedLibraries(); |
163 |
|
|
}; |
164 |
|
|
|
165 |
|
|
// Variant of `uv_loop_close` that tries to be as helpful as possible |
166 |
|
|
// about giving information on currently existing handles, if there are any, |
167 |
|
|
// but still aborts the process. |
168 |
|
|
void CheckedUvLoopClose(uv_loop_t* loop); |
169 |
|
|
void PrintLibuvHandleInformation(uv_loop_t* loop, FILE* stream); |
170 |
|
|
|
171 |
|
|
namespace per_process { |
172 |
|
|
extern NODE_EXTERN_PRIVATE EnabledDebugList enabled_debug_list; |
173 |
|
|
|
174 |
|
|
template <typename... Args> |
175 |
|
|
inline void FORCE_INLINE Debug(DebugCategory cat, |
176 |
|
|
const char* format, |
177 |
|
|
Args&&... args); |
178 |
|
|
|
179 |
|
|
inline void FORCE_INLINE Debug(DebugCategory cat, const char* message); |
180 |
|
|
} // namespace per_process |
181 |
|
|
} // namespace node |
182 |
|
|
|
183 |
|
|
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS |
184 |
|
|
|
185 |
|
|
#endif // SRC_DEBUG_UTILS_H_ |