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