Coverage Report

Created: 2026-05-16 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mysql-server/include/my_dbug.h
Line
Count
Source
1
/* Copyright (c) 2000, 2025, Oracle and/or its affiliates.
2
3
   This program is free software; you can redistribute it and/or modify
4
   it under the terms of the GNU General Public License, version 2.0,
5
   as published by the Free Software Foundation.
6
7
   This program is designed to work with certain software (including
8
   but not limited to OpenSSL) that is licensed under separate terms,
9
   as designated in a particular file or component or in included license
10
   documentation.  The authors of MySQL hereby grant you an additional
11
   permission to link the program and your derivative works with the
12
   separately licensed software that they have either included with
13
   the program or referenced in the documentation.
14
15
   This program is distributed in the hope that it will be useful,
16
   but WITHOUT ANY WARRANTY; without even the implied warranty of
17
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
   GNU General Public License, version 2.0, for more details.
19
20
   You should have received a copy of the GNU General Public License
21
   along with this program; if not, write to the Free Software
22
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
23
24
#ifndef MY_DBUG_INCLUDED
25
#define MY_DBUG_INCLUDED
26
27
/**
28
  @file include/my_dbug.h
29
*/
30
31
#ifdef MY_MSCRT_DEBUG
32
#include <crtdbg.h>
33
#endif
34
#include <stdlib.h>
35
36
#include "my_compiler.h"
37
38
#include <string.h>
39
40
#if !defined(NDEBUG)
41
#include <assert.h>  // IWYU pragma: keep
42
#include <stdio.h>
43
#endif
44
45
/**
46
  Calls our own implementation of abort, if specified, or std's abort().
47
 */
48
[[noreturn]] void my_abort();
49
/**
50
  Sets a new function to be called on my_abort().
51
52
  @param new_my_abort_func pointer to a new my_abort function. It can't be
53
  [[noreturn]] as pointers to methods can't have attributes.
54
 */
55
void set_my_abort(void (*new_my_abort_func)());
56
57
#if !defined(NDEBUG)
58
59
struct _db_stack_frame_ {
60
  const char *func;   /* function name of the previous stack frame       */
61
  int func_len;       /* how much to print from func */
62
  const char *file;   /* filename of the function of previous frame      */
63
  unsigned int level; /* this nesting level, highest bit enables tracing */
64
  struct _db_stack_frame_ *prev; /* pointer to the previous frame */
65
};
66
67
struct CODE_STATE;
68
69
extern int _db_keyword_(struct CODE_STATE *, const char *, int);
70
extern int _db_explain_(struct CODE_STATE *cs, char *buf, size_t len);
71
extern int _db_explain_init_(char *buf, size_t len);
72
extern int _db_is_pushed_(void);
73
extern void _db_process_(const char *name);
74
extern void _db_push_(const char *control);
75
extern void _db_pop_(void);
76
extern void _db_set_(const char *control);
77
extern void _db_set_init_(const char *control);
78
extern void _db_enter_(const char *_func_, int func_len, const char *_file_,
79
                       unsigned int _line_,
80
                       struct _db_stack_frame_ *_stack_frame_);
81
extern void _db_return_(unsigned int _line_,
82
                        struct _db_stack_frame_ *_stack_frame_);
83
extern void _db_pargs_(unsigned int _line_, const char *keyword);
84
extern int _db_enabled_();
85
extern void _db_doprnt_(const char *format, ...)
86
    MY_ATTRIBUTE((format(printf, 1, 2)));
87
extern void _db_dump_(unsigned int _line_, const char *keyword,
88
                      const unsigned char *memory, size_t length);
89
extern void _db_end_(void);
90
extern void _db_lock_file_(void);
91
extern void _db_unlock_file_(void);
92
extern FILE *_db_fp_(void);
93
extern void _db_flush_();
94
95
#ifdef __cplusplus
96
97
#if defined(__GNUC__)
98
// GCC, Clang, and compatible compilers.
99
#define DBUG_PRETTY_FUNCTION __PRETTY_FUNCTION__
100
#elif defined(__FUNCSIG__)
101
// For MSVC; skips the __cdecl. (__PRETTY_FUNCTION__ in GCC is not a
102
// preprocessor constant, but __FUNCSIG__ in MSVC is.)
103
#define DBUG_PRETTY_FUNCTION strchr(__FUNCSIG__, ' ') + 1
104
#else
105
// Standard C++; does not include the class name.
106
#define DBUG_PRETTY_FUNCTION __func__
107
#endif
108
109
/**
110
  A RAII helper to do DBUG_ENTER / DBUG_RETURN for you automatically. Use like
111
  this:
112
113
   int foo() {
114
     DBUG_TRACE;
115
     return 42;
116
   }
117
 */
118
class AutoDebugTrace {
119
 public:
120
  AutoDebugTrace(const char *function, const char *filename, int line) {
121
    // Remove the return type, if it's there.
122
    const char *begin = strchr(function, ' ');
123
    if (begin != nullptr) {
124
      function = begin + 1;
125
    }
126
127
    // Cut it off at the first parenthesis; the argument list is
128
    // often too long to be interesting.
129
    const char *end = strchr(function, '(');
130
131
    if (end == nullptr) {
132
      _db_enter_(function, static_cast<int>(strlen(function)), filename, line,
133
                 &m_stack_frame);
134
    } else {
135
      _db_enter_(function, static_cast<int>(end - function), filename, line,
136
                 &m_stack_frame);
137
    }
138
  }
139
140
  ~AutoDebugTrace() { _db_return_(0, &m_stack_frame); }
141
142
 private:
143
  _db_stack_frame_ m_stack_frame;
144
};
145
146
#define DBUG_TRACE \
147
  const AutoDebugTrace _db_trace(DBUG_PRETTY_FUNCTION, __FILE__, __LINE__)
148
149
#endif
150
151
#define DBUG_ENTER(a)                       \
152
  struct _db_stack_frame_ _db_stack_frame_; \
153
  _db_enter_(a, ::strlen(a), __FILE__, __LINE__, &_db_stack_frame_)
154
155
#define DBUG_RETURN(a1)                       \
156
  do {                                        \
157
    _db_return_(__LINE__, &_db_stack_frame_); \
158
    return (a1);                              \
159
  } while (0)
160
#define DBUG_VOID_RETURN                      \
161
  do {                                        \
162
    _db_return_(__LINE__, &_db_stack_frame_); \
163
    return;                                   \
164
  } while (0)
165
#define DBUG_EXECUTE(keyword, a1)              \
166
  do {                                         \
167
    if (_db_keyword_(nullptr, (keyword), 0)) { \
168
      a1                                       \
169
    }                                          \
170
  } while (0)
171
#define DBUG_EXECUTE_IF(keyword, a1)           \
172
  do {                                         \
173
    if (_db_keyword_(nullptr, (keyword), 1)) { \
174
      a1                                       \
175
    }                                          \
176
  } while (0)
177
#define DBUG_EVALUATE(keyword, a1, a2) \
178
  (_db_keyword_(nullptr, (keyword), 0) ? (a1) : (a2))
179
#define DBUG_EVALUATE_IF(keyword, a1, a2) \
180
  (_db_keyword_(nullptr, (keyword), 1) ? (a1) : (a2))
181
#define DBUG_PRINT(keyword, arglist) \
182
  do {                               \
183
    _db_pargs_(__LINE__, keyword);   \
184
    if (_db_enabled_()) {            \
185
      _db_doprnt_ arglist;           \
186
    }                                \
187
  } while (0)
188
189
#define DBUG_PUSH(a1) _db_push_(a1)
190
#define DBUG_POP() _db_pop_()
191
#define DBUG_SET(a1) _db_set_(a1)
192
#define DBUG_SET_INITIAL(a1) _db_set_init_(a1)
193
#define DBUG_PROCESS(a1) _db_process_(a1)
194
#define DBUG_FILE _db_fp_()
195
#define DBUG_DUMP(keyword, a1, a2) _db_dump_(__LINE__, keyword, a1, a2)
196
#define DBUG_END() _db_end_()
197
#define DBUG_LOCK_FILE _db_lock_file_()
198
#define DBUG_UNLOCK_FILE _db_unlock_file_()
199
#define DBUG_EXPLAIN(buf, len) _db_explain_(nullptr, (buf), (len))
200
#define DBUG_EXPLAIN_INITIAL(buf, len) _db_explain_init_((buf), (len))
201
#ifndef _WIN32
202
#define DBUG_ABORT() (_db_flush_(), my_abort())
203
#define DBUG_EXIT() (_db_flush_(), exit(2))
204
#else
205
#include <crtdbg.h>
206
207
#define DBUG_ABORT()                                                     \
208
  (_db_flush_(), (void)_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE), \
209
   (void)_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR), my_abort())
210
#define DBUG_EXIT()                                                      \
211
  (_db_flush_(), (void)_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE), \
212
   (void)_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR), _exit(2))
213
#endif
214
215
/*
216
  Make the program fail, without creating a core file.
217
  abort() will send SIGABRT which (most likely) generates core.
218
  Use SIGKILL instead, which cannot be caught.
219
  We also pause the current thread, until the signal is actually delivered.
220
  An alternative would be to use _exit(EXIT_FAILURE),
221
  but then valgrind would report lots of memory leaks.
222
 */
223
#ifdef _WIN32
224
#define DBUG_SUICIDE() DBUG_EXIT()
225
#else
226
[[noreturn]] extern void _db_suicide_();
227
extern void _db_flush_gcov_();
228
#define DBUG_SUICIDE() (_db_flush_(), _db_suicide_())
229
#endif
230
231
#else /* No debugger */
232
233
#ifdef __cplusplus
234
#define DBUG_TRACE \
235
383k
  do {             \
236
383k
  } while (false)
237
#endif
238
#define DBUG_ENTER(a1)
239
#define DBUG_RETURN(a1) \
240
  do {                  \
241
    return (a1);        \
242
  } while (0)
243
#define DBUG_VOID_RETURN \
244
  do {                   \
245
    return;              \
246
  } while (0)
247
#define DBUG_EXECUTE(keyword, a1) \
248
  do {                            \
249
  } while (0)
250
#define DBUG_EXECUTE_IF(keyword, a1) \
251
542k
  do {                               \
252
542k
  } while (0)
253
#define DBUG_EVALUATE(keyword, a1, a2) (a2)
254
#define DBUG_EVALUATE_IF(keyword, a1, a2) (a2)
255
#define DBUG_PRINT(keyword, arglist) \
256
204k
  do {                               \
257
204k
  } while (0)
258
#define DBUG_PUSH(a1) \
259
  do {                \
260
  } while (0)
261
#define DBUG_SET(a1) \
262
  do {               \
263
  } while (0)
264
#define DBUG_SET_INITIAL(a1) \
265
  do {                       \
266
  } while (0)
267
#define DBUG_POP() \
268
  do {             \
269
  } while (0)
270
#define DBUG_PROCESS(a1) \
271
1
  do {                   \
272
1
  } while (0)
273
#define DBUG_DUMP(keyword, a1, a2) \
274
  do {                             \
275
  } while (0)
276
#define DBUG_END() \
277
0
  do {             \
278
0
  } while (0)
279
#define DBUG_LOCK_FILE \
280
  do {                 \
281
  } while (0)
282
0
#define DBUG_FILE (stderr)
283
#define DBUG_UNLOCK_FILE \
284
  do {                   \
285
  } while (0)
286
#define DBUG_EXPLAIN(buf, len)
287
#define DBUG_EXPLAIN_INITIAL(buf, len)
288
#define DBUG_ABORT() \
289
  do {               \
290
  } while (0)
291
#define DBUG_SUICIDE() \
292
  do {                 \
293
  } while (0)
294
295
#endif
296
297
#ifdef __cplusplus
298
#if !defined(NDEBUG)
299
#include <sstream>
300
#include <string>
301
302
/*
303
  A C++ interface to the DBUG_PRINT macro.  The DBUG_LOG macro takes two
304
  arguments.  The first argument is the keyword, as that of the
305
  DBUG_PRINT.  The 2nd argument 'v' will be passed to a C++ output stream.
306
  This enables the use of C++ style output stream operator.  In the code, it
307
  will be used as follows:
308
309
  DBUG_LOG("blob", "space: " << space_id);
310
311
  Note: DBUG_PRINT() has a limitation of 1024 bytes for a single
312
  print out.  So, this limitation is there for DBUG_LOG macro also.
313
*/
314
315
#define DBUG_LOG(keyword, v)                           \
316
  do {                                                 \
317
    _db_pargs_(__LINE__, keyword);                     \
318
    if (_db_enabled_()) {                              \
319
      std::ostringstream sout;                         \
320
      sout << v;                                       \
321
      DBUG_PRINT(keyword, ("%s", sout.str().c_str())); \
322
    }                                                  \
323
  } while (0)
324
325
/**
326
  Shortcut for printing a variable name and its value in DBUG_LOG output.
327
328
  Use like:
329
330
  DBUG_LOG("info", DBUG_VAR(i) << " " << DBUG_VAR(thd->query));
331
332
  Example output for the above might be:
333
334
  i=[4711] thd->query=[INSERT INTO t VALUES (1)]
335
*/
336
#define DBUG_VAR(v) #v << "=[" << (v) << "]"
337
338
#else /* NDEBUG */
339
#define DBUG_LOG(keyword, v) \
340
  do {                       \
341
  } while (0)
342
#define DBUG_VAR(v) ""
343
#endif /* NDEBUG */
344
345
/**
346
   A type-safe interface to DBUG_EXECUTE_IF, where the debug action to
347
   activate when the keyword is provided is given as a callable object
348
   (typically a lambda).
349
350
   @note The body of the callable will be checked by the compiler even
351
         in optimized mode.
352
353
   @param keyword String literal which will enable this debug action.
354
   @param clos    Callable object taking no arguments which will be
355
                  called in debug mode if the keyword is enabled.
356
 */
357
template <class DBGCLOS>
358
inline void dbug(const char *keyword [[maybe_unused]],
359
0
                 DBGCLOS &&clos [[maybe_unused]]) {
360
0
  DBUG_EXECUTE_IF(keyword, clos(););
361
0
}
Unexecuted instantiation: my_file.cc:void dbug<file_info::RegisterFilename(int, char const*, file_info::OpenType)::$_0>(char const*, file_info::RegisterFilename(int, char const*, file_info::OpenType)::$_0&&)
Unexecuted instantiation: my_file.cc:void dbug<file_info::UnregisterFilename(int)::$_0>(char const*, file_info::UnregisterFilename(int)::$_0&&)
Unexecuted instantiation: my_file.cc:void dbug<file_info::UnregisterFilename(int)::$_1>(char const*, file_info::UnregisterFilename(int)::$_1&&)
Unexecuted instantiation: my_file.cc:void dbug<file_info::UnregisterFilename(int)::$_2>(char const*, file_info::UnregisterFilename(int)::$_2&&)
362
363
#endif /* __cplusplus */
364
#endif /* MY_DBUG_INCLUDED */