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