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