GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: debug_utils.h Lines: 7 10 70.0 %
Date: 2022-08-21 04:19:51 Branches: 0 0 - %

Line Branch Exec Source
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
54
enum class DebugCategory {
55
#define V(name) name,
56
  DEBUG_CATEGORY_NAMES(V)
57
#undef V
58
      CATEGORY_COUNT
59
};
60
61
class NODE_EXTERN_PRIVATE EnabledDebugList {
62
 public:
63
2253621
  bool enabled(DebugCategory category) const {
64
    DCHECK_GE(static_cast<int>(category), 0);
65
    DCHECK_LT(static_cast<int>(category),
66
              static_cast<int>(DebugCategory::CATEGORY_COUNT));
67
2253621
    return enabled_[static_cast<int>(category)];
68
  }
69
70
  // Uses NODE_DEBUG_NATIVE to initialize the categories. The env_vars variable
71
  // is parsed if it is not a nullptr, otherwise the system environment
72
  // variables are parsed.
73
  void Parse(std::shared_ptr<KVStore> env_vars = nullptr,
74
             v8::Isolate* isolate = nullptr);
75
76
 private:
77
  // Set all categories matching cats to the value of enabled.
78
  void Parse(const std::string& cats, bool enabled);
79
115
  void set_enabled(DebugCategory category, bool enabled) {
80
    DCHECK_GE(static_cast<int>(category), 0);
81
    DCHECK_LT(static_cast<int>(category),
82
              static_cast<int>(DebugCategory::CATEGORY_COUNT));
83
115
    enabled_[static_cast<int>(category)] = true;
84
115
  }
85
86
  bool enabled_[static_cast<int>(DebugCategory::CATEGORY_COUNT)] = {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
29
  NativeSymbolDebuggingContext() = default;
151
58
  virtual ~NativeSymbolDebuggingContext() = default;
152
153
  virtual SymbolInfo LookupSymbol(void* address) { return {}; }
154
  virtual bool IsMapped(void* address) { return false; }
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_