1287516Sdim/* Declarations for debug printing functions.
2287516Sdim
3287516Sdim   Copyright (C) 2014-2023 Free Software Foundation, Inc.
4287516Sdim
5287516Sdim   This file is part of GDB.
6287516Sdim
7287516Sdim   This program is free software; you can redistribute it and/or modify
8287516Sdim   it under the terms of the GNU General Public License as published by
9287516Sdim   the Free Software Foundation; either version 3 of the License, or
10287516Sdim   (at your option) any later version.
11287516Sdim
12287516Sdim   This program is distributed in the hope that it will be useful,
13287516Sdim   but WITHOUT ANY WARRANTY; without even the implied warranty of
14287516Sdim   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15287516Sdim   GNU General Public License for more details.
16287516Sdim
17287516Sdim   You should have received a copy of the GNU General Public License
18287516Sdim   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19287516Sdim
20287516Sdim#ifndef COMMON_COMMON_DEBUG_H
21287516Sdim#define COMMON_COMMON_DEBUG_H
22287516Sdim
23287516Sdim#include "gdbsupport/gdb_optional.h"
24#include "gdbsupport/preprocessor.h"
25
26#include <stdarg.h>
27
28/* Set to true to enable debugging of hardware breakpoint/
29   watchpoint support code.  */
30
31extern bool show_debug_regs;
32
33/* Print a formatted message to the appropriate channel for
34   debugging output for the client.  */
35
36extern void debug_printf (const char *format, ...)
37     ATTRIBUTE_PRINTF (1, 2);
38
39/* Print a formatted message to the appropriate channel for
40   debugging output for the client.  This function must be
41   provided by the client.  */
42
43extern void debug_vprintf (const char *format, va_list ap)
44     ATTRIBUTE_PRINTF (1, 0);
45
46/* Print a debug statement prefixed with the module and function name, and
47   with a newline at the end.  */
48
49extern void ATTRIBUTE_PRINTF (3, 4) debug_prefixed_printf
50  (const char *module, const char *func, const char *format, ...);
51
52/* Print a debug statement prefixed with the module and function name, and
53   with a newline at the end.  */
54
55extern void ATTRIBUTE_PRINTF (3, 0) debug_prefixed_vprintf
56  (const char *module, const char *func, const char *format, va_list args);
57
58/* Helper to define "_debug_print" macros.
59
60   DEBUG_ENABLED_COND is an expression that evaluates to true if the debugging
61   statement is enabled and should be printed.
62
63   The other arguments, as well as the name of the current function, are
64   forwarded to debug_prefixed_printf.  */
65
66#define debug_prefixed_printf_cond(debug_enabled_cond, module, fmt, ...) \
67  do \
68    { \
69      if (debug_enabled_cond) \
70	debug_prefixed_printf (module, __func__, fmt, ##__VA_ARGS__); \
71    } \
72  while (0)
73
74#define debug_prefixed_printf_cond_nofunc(debug_enabled_cond, module, fmt, ...) \
75  do \
76    { \
77      if (debug_enabled_cond) \
78	debug_prefixed_printf (module, nullptr, fmt, ##__VA_ARGS__); \
79    } \
80  while (0)
81
82/* Nesting depth of scoped_debug_start_end objects.  */
83
84extern int debug_print_depth;
85
86/* Print a message on construction and destruction, to denote the start and end
87   of an operation.  Increment DEBUG_PRINT_DEPTH on construction and decrement
88   it on destruction, such that nested debug statements will be printed with
89   an indent and appear "inside" this one.  */
90
91template<typename PT>
92struct scoped_debug_start_end
93{
94  /* DEBUG_ENABLED is a reference to a variable that indicates whether debugging
95     is enabled, so if the debug statements should be printed.  Is is read
96     separately at construction and destruction, such that the start statement
97     could be printed but not the end statement, or vice-versa.
98
99     DEBUG_ENABLED should either be of type 'bool &' or should be a type
100     that can be invoked.
101
102     MODULE and FUNC are forwarded to debug_prefixed_printf.
103
104     START_PREFIX and END_PREFIX are the statements to print on construction and
105     destruction, respectively.
106
107     If the FMT format string is non-nullptr, then a `: ` is appended to the
108     messages, followed by the rendering of that format string with ARGS.
109     The format string is rendered during construction and is re-used as is
110     for the message on exit.  */
111
112  scoped_debug_start_end (PT &debug_enabled, const char *module,
113			  const char *func, const char *start_prefix,
114			  const char *end_prefix, const char *fmt,
115			  va_list args)
116    ATTRIBUTE_NULL_PRINTF (7, 0)
117    : m_debug_enabled (debug_enabled),
118      m_module (module),
119      m_func (func),
120      m_end_prefix (end_prefix),
121      m_with_format (fmt != nullptr)
122  {
123    if (is_debug_enabled ())
124      {
125	if (fmt != nullptr)
126	  {
127	    m_msg = string_vprintf (fmt, args);
128	    debug_prefixed_printf (m_module, m_func, "%s: %s",
129				   start_prefix, m_msg->c_str ());
130	  }
131	else
132	  debug_prefixed_printf (m_module, m_func, "%s", start_prefix);
133
134	++debug_print_depth;
135	m_must_decrement_print_depth = true;
136      }
137  }
138
139  DISABLE_COPY_AND_ASSIGN (scoped_debug_start_end);
140
141  scoped_debug_start_end (scoped_debug_start_end &&other) = default;
142
143  ~scoped_debug_start_end ()
144  {
145    if (m_must_decrement_print_depth)
146      {
147	gdb_assert (debug_print_depth > 0);
148	--debug_print_depth;
149      }
150
151    if (is_debug_enabled ())
152      {
153	if (m_with_format)
154	  {
155	    if (m_msg.has_value ())
156	      debug_prefixed_printf (m_module, m_func, "%s: %s",
157				     m_end_prefix, m_msg->c_str ());
158	    else
159	      {
160		/* A format string was passed to the constructor, but debug
161		   control variable wasn't set at the time, so we don't have the
162		   rendering of the format string.  */
163		debug_prefixed_printf (m_module, m_func, "%s: <%s debugging was not enabled on entry>",
164				       m_end_prefix, m_module);
165	      }
166	  }
167	else
168	  debug_prefixed_printf (m_module, m_func, "%s", m_end_prefix);
169      }
170  }
171
172private:
173
174  /* This function is specialized based on the type PT.  Returns true if
175     M_DEBUG_ENABLED indicates this debug setting is enabled, otherwise,
176     return false.  */
177  bool is_debug_enabled () const;
178
179  /* Reference to the debug setting, or a callback that can read the debug
180     setting.  Access the value of this by calling IS_DEBUG_ENABLED.  */
181  PT &m_debug_enabled;
182
183  const char *m_module;
184  const char *m_func;
185  const char *m_end_prefix;
186
187  /* The result of formatting the format string in the constructor.  */
188  gdb::optional<std::string> m_msg;
189
190  /* True is a non-nullptr format was passed to the constructor.  */
191  bool m_with_format;
192
193  /* This is used to handle the case where debugging is enabled during
194     construction but not during destruction, or vice-versa.  We want to make
195     sure there are as many increments are there are decrements.  */
196  bool m_must_decrement_print_depth = false;
197};
198
199/* Implementation of is_debug_enabled when PT is an invokable type.  */
200
201template<typename PT>
202inline bool
203scoped_debug_start_end<PT>::is_debug_enabled () const
204{
205  return m_debug_enabled ();
206}
207
208/* Implementation of is_debug_enabled when PT is 'bool &'.  */
209
210template<>
211inline bool
212scoped_debug_start_end<bool &>::is_debug_enabled () const
213{
214  return m_debug_enabled;
215}
216
217/* Wrapper around the scoped_debug_start_end constructor to allow the
218   caller to create an object using 'auto' type, the actual type will be
219   based on the type of the PRED argument.  All arguments are forwarded to
220   the scoped_debug_start_end constructor.  */
221
222template<typename PT>
223static inline scoped_debug_start_end<PT &> ATTRIBUTE_NULL_PRINTF (6, 7)
224make_scoped_debug_start_end (PT &&pred, const char *module, const char *func,
225			     const char *start_prefix,
226			     const char *end_prefix, const char *fmt, ...)
227{
228  va_list args;
229  va_start (args, fmt);
230  auto res = scoped_debug_start_end<PT &> (pred, module, func, start_prefix,
231					   end_prefix, fmt, args);
232  va_end (args);
233
234  return res;
235}
236
237/* Helper to define a module-specific start/end debug macro.  */
238
239#define scoped_debug_start_end(debug_enabled, module, fmt, ...)		\
240  auto CONCAT(scoped_debug_start_end, __LINE__)				\
241    = make_scoped_debug_start_end (debug_enabled, module, 	\
242				   __func__, "start", "end",	\
243				   fmt, ##__VA_ARGS__)
244
245/* Helper to define a module-specific enter/exit debug macro.  This is a special
246   case of `scoped_debug_start_end` where the start and end messages are "enter"
247   and "exit", to denote entry and exit of a function.  */
248
249#define scoped_debug_enter_exit(debug_enabled, module)	\
250  auto CONCAT(scoped_debug_start_end, __LINE__)				\
251    = make_scoped_debug_start_end (debug_enabled, module, 	\
252				   __func__, "enter", "exit",	\
253				   nullptr)
254
255#endif /* COMMON_COMMON_DEBUG_H */
256