• 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 #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   V(PERMISSION_MODEL)
54 
55 enum class DebugCategory : unsigned int {
56 #define V(name) name,
57   DEBUG_CATEGORY_NAMES(V)
58 #undef V
59 };
60 
61 #define V(name) +1
62 constexpr unsigned int kDebugCategoryCount = DEBUG_CATEGORY_NAMES(V);
63 #undef V
64 
65 class NODE_EXTERN_PRIVATE EnabledDebugList {
66  public:
enabled(DebugCategory category)67   bool FORCE_INLINE enabled(DebugCategory category) const {
68     DCHECK_LT(static_cast<unsigned int>(category), kDebugCategoryCount);
69     return enabled_[static_cast<unsigned int>(category)];
70   }
71 
72   // Uses NODE_DEBUG_NATIVE to initialize the categories. The env_vars variable
73   // is parsed if it is not a nullptr, otherwise the system environment
74   // variables are parsed.
75   void Parse(std::shared_ptr<KVStore> env_vars = nullptr,
76              v8::Isolate* isolate = nullptr);
77 
78  private:
79   // Enable all categories matching cats.
80   void Parse(const std::string& cats);
set_enabled(DebugCategory category)81   void set_enabled(DebugCategory category) {
82     DCHECK_LT(static_cast<unsigned int>(category), kDebugCategoryCount);
83     enabled_[static_cast<int>(category)] = true;
84   }
85 
86   bool enabled_[kDebugCategoryCount] = {false};
87 };
88 
89 template <typename... Args>
90 inline void FORCE_INLINE Debug(EnabledDebugList* list,
91                                DebugCategory cat,
92                                const char* format,
93                                Args&&... args);
94 
95 inline void FORCE_INLINE Debug(EnabledDebugList* list,
96                                DebugCategory cat,
97                                const char* message);
98 
99 template <typename... Args>
100 inline void FORCE_INLINE
101 Debug(Environment* env, DebugCategory cat, const char* format, Args&&... args);
102 
103 inline void FORCE_INLINE Debug(Environment* env,
104                                DebugCategory cat,
105                                const char* message);
106 
107 template <typename... Args>
108 inline void Debug(Environment* env,
109                   DebugCategory cat,
110                   const std::string& format,
111                   Args&&... args);
112 
113 // Used internally by the 'real' Debug(AsyncWrap*, ...) functions below, so that
114 // the FORCE_INLINE flag on them doesn't apply to the contents of this function
115 // as well.
116 // We apply COLD_NOINLINE to tell the compiler that it's not worth optimizing
117 // this function for speed and it should rather focus on keeping it out of
118 // hot code paths. In particular, we want to keep the string concatenating code
119 // out of the function containing the original `Debug()` call.
120 template <typename... Args>
121 void COLD_NOINLINE UnconditionalAsyncWrapDebug(AsyncWrap* async_wrap,
122                                                const char* format,
123                                                Args&&... args);
124 
125 template <typename... Args>
126 inline void FORCE_INLINE Debug(AsyncWrap* async_wrap,
127                                const char* format,
128                                Args&&... args);
129 
130 template <typename... Args>
131 inline void FORCE_INLINE Debug(AsyncWrap* async_wrap,
132                                const std::string& format,
133                                Args&&... args);
134 
135 // Debug helper for inspecting the currently running `node` executable.
136 class NativeSymbolDebuggingContext {
137  public:
138   static std::unique_ptr<NativeSymbolDebuggingContext> New();
139 
140   class SymbolInfo {
141    public:
142     std::string name;
143     std::string filename;
144     size_t line = 0;
145     size_t dis = 0;
146 
147     std::string Display() const;
148   };
149 
150   NativeSymbolDebuggingContext() = default;
151   virtual ~NativeSymbolDebuggingContext() = default;
152 
LookupSymbol(void * address)153   virtual SymbolInfo LookupSymbol(void* address) { return {}; }
IsMapped(void * address)154   virtual bool IsMapped(void* address) { return false; }
GetStackTrace(void ** frames,int count)155   virtual int GetStackTrace(void** frames, int count) { return 0; }
156 
157   NativeSymbolDebuggingContext(const NativeSymbolDebuggingContext&) = delete;
158   NativeSymbolDebuggingContext(NativeSymbolDebuggingContext&&) = delete;
159   NativeSymbolDebuggingContext operator=(NativeSymbolDebuggingContext&)
160     = delete;
161   NativeSymbolDebuggingContext operator=(NativeSymbolDebuggingContext&&)
162     = delete;
163   static std::vector<std::string> GetLoadedLibraries();
164 };
165 
166 // Variant of `uv_loop_close` that tries to be as helpful as possible
167 // about giving information on currently existing handles, if there are any,
168 // but still aborts the process.
169 void CheckedUvLoopClose(uv_loop_t* loop);
170 void PrintLibuvHandleInformation(uv_loop_t* loop, FILE* stream);
171 
172 namespace per_process {
173 extern NODE_EXTERN_PRIVATE EnabledDebugList enabled_debug_list;
174 
175 template <typename... Args>
176 inline void FORCE_INLINE Debug(DebugCategory cat,
177                                const char* format,
178                                Args&&... args);
179 
180 inline void FORCE_INLINE Debug(DebugCategory cat, const char* message);
181 }  // namespace per_process
182 }  // namespace node
183 
184 #endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
185 
186 #endif  // SRC_DEBUG_UTILS_H_
187