11cb0ef41Sopenharmony_ci#ifndef SRC_DEBUG_UTILS_H_
21cb0ef41Sopenharmony_ci#define SRC_DEBUG_UTILS_H_
31cb0ef41Sopenharmony_ci
41cb0ef41Sopenharmony_ci#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
51cb0ef41Sopenharmony_ci
61cb0ef41Sopenharmony_ci#include "async_wrap.h"
71cb0ef41Sopenharmony_ci#include "util.h"
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_ci#include <algorithm>
101cb0ef41Sopenharmony_ci#include <sstream>
111cb0ef41Sopenharmony_ci#include <string>
121cb0ef41Sopenharmony_ci
131cb0ef41Sopenharmony_ci// Use FORCE_INLINE on functions that have a debug-category-enabled check first
141cb0ef41Sopenharmony_ci// and then ideally only a single function call following it, to maintain
151cb0ef41Sopenharmony_ci// performance for the common case (no debugging used).
161cb0ef41Sopenharmony_ci#ifdef __GNUC__
171cb0ef41Sopenharmony_ci#define FORCE_INLINE __attribute__((always_inline))
181cb0ef41Sopenharmony_ci#define COLD_NOINLINE __attribute__((cold, noinline))
191cb0ef41Sopenharmony_ci#else
201cb0ef41Sopenharmony_ci#define FORCE_INLINE
211cb0ef41Sopenharmony_ci#define COLD_NOINLINE
221cb0ef41Sopenharmony_ci#endif
231cb0ef41Sopenharmony_ci
241cb0ef41Sopenharmony_cinamespace node {
251cb0ef41Sopenharmony_ciclass Environment;
261cb0ef41Sopenharmony_ci
271cb0ef41Sopenharmony_citemplate <typename T>
281cb0ef41Sopenharmony_ciinline std::string ToString(const T& value);
291cb0ef41Sopenharmony_ci
301cb0ef41Sopenharmony_ci// C++-style variant of sprintf()/fprintf() that:
311cb0ef41Sopenharmony_ci// - Returns an std::string
321cb0ef41Sopenharmony_ci// - Handles \0 bytes correctly
331cb0ef41Sopenharmony_ci// - Supports %p and %s. %d, %i and %u are aliases for %s.
341cb0ef41Sopenharmony_ci// - Accepts any class that has a ToString() method for stringification.
351cb0ef41Sopenharmony_citemplate <typename... Args>
361cb0ef41Sopenharmony_ciinline std::string SPrintF(const char* format, Args&&... args);
371cb0ef41Sopenharmony_citemplate <typename... Args>
381cb0ef41Sopenharmony_ciinline void FPrintF(FILE* file, const char* format, Args&&... args);
391cb0ef41Sopenharmony_civoid NODE_EXTERN_PRIVATE FWrite(FILE* file, const std::string& str);
401cb0ef41Sopenharmony_ci
411cb0ef41Sopenharmony_ci// Listing the AsyncWrap provider types first enables us to cast directly
421cb0ef41Sopenharmony_ci// from a provider type to a debug category.
431cb0ef41Sopenharmony_ci#define DEBUG_CATEGORY_NAMES(V)                                                \
441cb0ef41Sopenharmony_ci  NODE_ASYNC_PROVIDER_TYPES(V)                                                 \
451cb0ef41Sopenharmony_ci  V(DIAGNOSTICS)                                                               \
461cb0ef41Sopenharmony_ci  V(HUGEPAGES)                                                                 \
471cb0ef41Sopenharmony_ci  V(INSPECTOR_SERVER)                                                          \
481cb0ef41Sopenharmony_ci  V(INSPECTOR_PROFILER)                                                        \
491cb0ef41Sopenharmony_ci  V(CODE_CACHE)                                                                \
501cb0ef41Sopenharmony_ci  V(NGTCP2_DEBUG)                                                              \
511cb0ef41Sopenharmony_ci  V(WASI)                                                                      \
521cb0ef41Sopenharmony_ci  V(MKSNAPSHOT)                                                                \
531cb0ef41Sopenharmony_ci  V(PERMISSION_MODEL)
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_cienum class DebugCategory : unsigned int {
561cb0ef41Sopenharmony_ci#define V(name) name,
571cb0ef41Sopenharmony_ci  DEBUG_CATEGORY_NAMES(V)
581cb0ef41Sopenharmony_ci#undef V
591cb0ef41Sopenharmony_ci};
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_ci#define V(name) +1
621cb0ef41Sopenharmony_ciconstexpr unsigned int kDebugCategoryCount = DEBUG_CATEGORY_NAMES(V);
631cb0ef41Sopenharmony_ci#undef V
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_ciclass NODE_EXTERN_PRIVATE EnabledDebugList {
661cb0ef41Sopenharmony_ci public:
671cb0ef41Sopenharmony_ci  bool FORCE_INLINE enabled(DebugCategory category) const {
681cb0ef41Sopenharmony_ci    DCHECK_LT(static_cast<unsigned int>(category), kDebugCategoryCount);
691cb0ef41Sopenharmony_ci    return enabled_[static_cast<unsigned int>(category)];
701cb0ef41Sopenharmony_ci  }
711cb0ef41Sopenharmony_ci
721cb0ef41Sopenharmony_ci  // Uses NODE_DEBUG_NATIVE to initialize the categories. The env_vars variable
731cb0ef41Sopenharmony_ci  // is parsed if it is not a nullptr, otherwise the system environment
741cb0ef41Sopenharmony_ci  // variables are parsed.
751cb0ef41Sopenharmony_ci  void Parse(std::shared_ptr<KVStore> env_vars = nullptr,
761cb0ef41Sopenharmony_ci             v8::Isolate* isolate = nullptr);
771cb0ef41Sopenharmony_ci
781cb0ef41Sopenharmony_ci private:
791cb0ef41Sopenharmony_ci  // Enable all categories matching cats.
801cb0ef41Sopenharmony_ci  void Parse(const std::string& cats);
811cb0ef41Sopenharmony_ci  void set_enabled(DebugCategory category) {
821cb0ef41Sopenharmony_ci    DCHECK_LT(static_cast<unsigned int>(category), kDebugCategoryCount);
831cb0ef41Sopenharmony_ci    enabled_[static_cast<int>(category)] = true;
841cb0ef41Sopenharmony_ci  }
851cb0ef41Sopenharmony_ci
861cb0ef41Sopenharmony_ci  bool enabled_[kDebugCategoryCount] = {false};
871cb0ef41Sopenharmony_ci};
881cb0ef41Sopenharmony_ci
891cb0ef41Sopenharmony_citemplate <typename... Args>
901cb0ef41Sopenharmony_ciinline void FORCE_INLINE Debug(EnabledDebugList* list,
911cb0ef41Sopenharmony_ci                               DebugCategory cat,
921cb0ef41Sopenharmony_ci                               const char* format,
931cb0ef41Sopenharmony_ci                               Args&&... args);
941cb0ef41Sopenharmony_ci
951cb0ef41Sopenharmony_ciinline void FORCE_INLINE Debug(EnabledDebugList* list,
961cb0ef41Sopenharmony_ci                               DebugCategory cat,
971cb0ef41Sopenharmony_ci                               const char* message);
981cb0ef41Sopenharmony_ci
991cb0ef41Sopenharmony_citemplate <typename... Args>
1001cb0ef41Sopenharmony_ciinline void FORCE_INLINE
1011cb0ef41Sopenharmony_ciDebug(Environment* env, DebugCategory cat, const char* format, Args&&... args);
1021cb0ef41Sopenharmony_ci
1031cb0ef41Sopenharmony_ciinline void FORCE_INLINE Debug(Environment* env,
1041cb0ef41Sopenharmony_ci                               DebugCategory cat,
1051cb0ef41Sopenharmony_ci                               const char* message);
1061cb0ef41Sopenharmony_ci
1071cb0ef41Sopenharmony_citemplate <typename... Args>
1081cb0ef41Sopenharmony_ciinline void Debug(Environment* env,
1091cb0ef41Sopenharmony_ci                  DebugCategory cat,
1101cb0ef41Sopenharmony_ci                  const std::string& format,
1111cb0ef41Sopenharmony_ci                  Args&&... args);
1121cb0ef41Sopenharmony_ci
1131cb0ef41Sopenharmony_ci// Used internally by the 'real' Debug(AsyncWrap*, ...) functions below, so that
1141cb0ef41Sopenharmony_ci// the FORCE_INLINE flag on them doesn't apply to the contents of this function
1151cb0ef41Sopenharmony_ci// as well.
1161cb0ef41Sopenharmony_ci// We apply COLD_NOINLINE to tell the compiler that it's not worth optimizing
1171cb0ef41Sopenharmony_ci// this function for speed and it should rather focus on keeping it out of
1181cb0ef41Sopenharmony_ci// hot code paths. In particular, we want to keep the string concatenating code
1191cb0ef41Sopenharmony_ci// out of the function containing the original `Debug()` call.
1201cb0ef41Sopenharmony_citemplate <typename... Args>
1211cb0ef41Sopenharmony_civoid COLD_NOINLINE UnconditionalAsyncWrapDebug(AsyncWrap* async_wrap,
1221cb0ef41Sopenharmony_ci                                               const char* format,
1231cb0ef41Sopenharmony_ci                                               Args&&... args);
1241cb0ef41Sopenharmony_ci
1251cb0ef41Sopenharmony_citemplate <typename... Args>
1261cb0ef41Sopenharmony_ciinline void FORCE_INLINE Debug(AsyncWrap* async_wrap,
1271cb0ef41Sopenharmony_ci                               const char* format,
1281cb0ef41Sopenharmony_ci                               Args&&... args);
1291cb0ef41Sopenharmony_ci
1301cb0ef41Sopenharmony_citemplate <typename... Args>
1311cb0ef41Sopenharmony_ciinline void FORCE_INLINE Debug(AsyncWrap* async_wrap,
1321cb0ef41Sopenharmony_ci                               const std::string& format,
1331cb0ef41Sopenharmony_ci                               Args&&... args);
1341cb0ef41Sopenharmony_ci
1351cb0ef41Sopenharmony_ci// Debug helper for inspecting the currently running `node` executable.
1361cb0ef41Sopenharmony_ciclass NativeSymbolDebuggingContext {
1371cb0ef41Sopenharmony_ci public:
1381cb0ef41Sopenharmony_ci  static std::unique_ptr<NativeSymbolDebuggingContext> New();
1391cb0ef41Sopenharmony_ci
1401cb0ef41Sopenharmony_ci  class SymbolInfo {
1411cb0ef41Sopenharmony_ci   public:
1421cb0ef41Sopenharmony_ci    std::string name;
1431cb0ef41Sopenharmony_ci    std::string filename;
1441cb0ef41Sopenharmony_ci    size_t line = 0;
1451cb0ef41Sopenharmony_ci    size_t dis = 0;
1461cb0ef41Sopenharmony_ci
1471cb0ef41Sopenharmony_ci    std::string Display() const;
1481cb0ef41Sopenharmony_ci  };
1491cb0ef41Sopenharmony_ci
1501cb0ef41Sopenharmony_ci  NativeSymbolDebuggingContext() = default;
1511cb0ef41Sopenharmony_ci  virtual ~NativeSymbolDebuggingContext() = default;
1521cb0ef41Sopenharmony_ci
1531cb0ef41Sopenharmony_ci  virtual SymbolInfo LookupSymbol(void* address) { return {}; }
1541cb0ef41Sopenharmony_ci  virtual bool IsMapped(void* address) { return false; }
1551cb0ef41Sopenharmony_ci  virtual int GetStackTrace(void** frames, int count) { return 0; }
1561cb0ef41Sopenharmony_ci
1571cb0ef41Sopenharmony_ci  NativeSymbolDebuggingContext(const NativeSymbolDebuggingContext&) = delete;
1581cb0ef41Sopenharmony_ci  NativeSymbolDebuggingContext(NativeSymbolDebuggingContext&&) = delete;
1591cb0ef41Sopenharmony_ci  NativeSymbolDebuggingContext operator=(NativeSymbolDebuggingContext&)
1601cb0ef41Sopenharmony_ci    = delete;
1611cb0ef41Sopenharmony_ci  NativeSymbolDebuggingContext operator=(NativeSymbolDebuggingContext&&)
1621cb0ef41Sopenharmony_ci    = delete;
1631cb0ef41Sopenharmony_ci  static std::vector<std::string> GetLoadedLibraries();
1641cb0ef41Sopenharmony_ci};
1651cb0ef41Sopenharmony_ci
1661cb0ef41Sopenharmony_ci// Variant of `uv_loop_close` that tries to be as helpful as possible
1671cb0ef41Sopenharmony_ci// about giving information on currently existing handles, if there are any,
1681cb0ef41Sopenharmony_ci// but still aborts the process.
1691cb0ef41Sopenharmony_civoid CheckedUvLoopClose(uv_loop_t* loop);
1701cb0ef41Sopenharmony_civoid PrintLibuvHandleInformation(uv_loop_t* loop, FILE* stream);
1711cb0ef41Sopenharmony_ci
1721cb0ef41Sopenharmony_cinamespace per_process {
1731cb0ef41Sopenharmony_ciextern NODE_EXTERN_PRIVATE EnabledDebugList enabled_debug_list;
1741cb0ef41Sopenharmony_ci
1751cb0ef41Sopenharmony_citemplate <typename... Args>
1761cb0ef41Sopenharmony_ciinline void FORCE_INLINE Debug(DebugCategory cat,
1771cb0ef41Sopenharmony_ci                               const char* format,
1781cb0ef41Sopenharmony_ci                               Args&&... args);
1791cb0ef41Sopenharmony_ci
1801cb0ef41Sopenharmony_ciinline void FORCE_INLINE Debug(DebugCategory cat, const char* message);
1811cb0ef41Sopenharmony_ci}  // namespace per_process
1821cb0ef41Sopenharmony_ci}  // namespace node
1831cb0ef41Sopenharmony_ci
1841cb0ef41Sopenharmony_ci#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
1851cb0ef41Sopenharmony_ci
1861cb0ef41Sopenharmony_ci#endif  // SRC_DEBUG_UTILS_H_
187