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