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