xref: /netbsd-src/external/gpl3/gdb/dist/gdbsupport/common-debug.h (revision 5ba1f45f2a09259cc846f20c7c5501604d633c90)
18dffb485Schristos /* Declarations for debug printing functions.
28dffb485Schristos 
3*5ba1f45fSchristos    Copyright (C) 2014-2024 Free Software Foundation, Inc.
48dffb485Schristos 
58dffb485Schristos    This file is part of GDB.
68dffb485Schristos 
78dffb485Schristos    This program is free software; you can redistribute it and/or modify
88dffb485Schristos    it under the terms of the GNU General Public License as published by
98dffb485Schristos    the Free Software Foundation; either version 3 of the License, or
108dffb485Schristos    (at your option) any later version.
118dffb485Schristos 
128dffb485Schristos    This program is distributed in the hope that it will be useful,
138dffb485Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
148dffb485Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
158dffb485Schristos    GNU General Public License for more details.
168dffb485Schristos 
178dffb485Schristos    You should have received a copy of the GNU General Public License
188dffb485Schristos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
198dffb485Schristos 
208dffb485Schristos #ifndef COMMON_COMMON_DEBUG_H
218dffb485Schristos #define COMMON_COMMON_DEBUG_H
228dffb485Schristos 
23*5ba1f45fSchristos #include <optional>
244b169a6bSchristos #include "gdbsupport/preprocessor.h"
254b169a6bSchristos 
264b169a6bSchristos #include <stdarg.h>
274b169a6bSchristos 
288dffb485Schristos /* Set to true to enable debugging of hardware breakpoint/
298dffb485Schristos    watchpoint support code.  */
308dffb485Schristos 
318dffb485Schristos extern bool show_debug_regs;
328dffb485Schristos 
338dffb485Schristos /* Print a formatted message to the appropriate channel for
348dffb485Schristos    debugging output for the client.  */
358dffb485Schristos 
368dffb485Schristos extern void debug_printf (const char *format, ...)
378dffb485Schristos      ATTRIBUTE_PRINTF (1, 2);
388dffb485Schristos 
398dffb485Schristos /* Print a formatted message to the appropriate channel for
408dffb485Schristos    debugging output for the client.  This function must be
418dffb485Schristos    provided by the client.  */
428dffb485Schristos 
438dffb485Schristos extern void debug_vprintf (const char *format, va_list ap)
448dffb485Schristos      ATTRIBUTE_PRINTF (1, 0);
458dffb485Schristos 
464b169a6bSchristos /* Print a debug statement prefixed with the module and function name, and
474b169a6bSchristos    with a newline at the end.  */
484b169a6bSchristos 
494b169a6bSchristos extern void ATTRIBUTE_PRINTF (3, 4) debug_prefixed_printf
504b169a6bSchristos   (const char *module, const char *func, const char *format, ...);
514b169a6bSchristos 
524b169a6bSchristos /* Print a debug statement prefixed with the module and function name, and
534b169a6bSchristos    with a newline at the end.  */
544b169a6bSchristos 
554b169a6bSchristos extern void ATTRIBUTE_PRINTF (3, 0) debug_prefixed_vprintf
564b169a6bSchristos   (const char *module, const char *func, const char *format, va_list args);
574b169a6bSchristos 
584b169a6bSchristos /* Helper to define "_debug_print" macros.
594b169a6bSchristos 
604b169a6bSchristos    DEBUG_ENABLED_COND is an expression that evaluates to true if the debugging
614b169a6bSchristos    statement is enabled and should be printed.
624b169a6bSchristos 
634b169a6bSchristos    The other arguments, as well as the name of the current function, are
644b169a6bSchristos    forwarded to debug_prefixed_printf.  */
654b169a6bSchristos 
664b169a6bSchristos #define debug_prefixed_printf_cond(debug_enabled_cond, module, fmt, ...) \
674b169a6bSchristos   do \
684b169a6bSchristos     { \
694b169a6bSchristos       if (debug_enabled_cond) \
704b169a6bSchristos 	debug_prefixed_printf (module, __func__, fmt, ##__VA_ARGS__); \
714b169a6bSchristos     } \
724b169a6bSchristos   while (0)
734b169a6bSchristos 
744b169a6bSchristos #define debug_prefixed_printf_cond_nofunc(debug_enabled_cond, module, fmt, ...) \
754b169a6bSchristos   do \
764b169a6bSchristos     { \
774b169a6bSchristos       if (debug_enabled_cond) \
784b169a6bSchristos 	debug_prefixed_printf (module, nullptr, fmt, ##__VA_ARGS__); \
794b169a6bSchristos     } \
804b169a6bSchristos   while (0)
814b169a6bSchristos 
824b169a6bSchristos /* Nesting depth of scoped_debug_start_end objects.  */
834b169a6bSchristos 
844b169a6bSchristos extern int debug_print_depth;
854b169a6bSchristos 
864b169a6bSchristos /* Print a message on construction and destruction, to denote the start and end
874b169a6bSchristos    of an operation.  Increment DEBUG_PRINT_DEPTH on construction and decrement
884b169a6bSchristos    it on destruction, such that nested debug statements will be printed with
894b169a6bSchristos    an indent and appear "inside" this one.  */
904b169a6bSchristos 
914b169a6bSchristos template<typename PT>
924b169a6bSchristos struct scoped_debug_start_end
934b169a6bSchristos {
944b169a6bSchristos   /* DEBUG_ENABLED is a reference to a variable that indicates whether debugging
954b169a6bSchristos      is enabled, so if the debug statements should be printed.  Is is read
964b169a6bSchristos      separately at construction and destruction, such that the start statement
974b169a6bSchristos      could be printed but not the end statement, or vice-versa.
984b169a6bSchristos 
994b169a6bSchristos      DEBUG_ENABLED should either be of type 'bool &' or should be a type
1004b169a6bSchristos      that can be invoked.
1014b169a6bSchristos 
1024b169a6bSchristos      MODULE and FUNC are forwarded to debug_prefixed_printf.
1034b169a6bSchristos 
1044b169a6bSchristos      START_PREFIX and END_PREFIX are the statements to print on construction and
1054b169a6bSchristos      destruction, respectively.
1064b169a6bSchristos 
1074b169a6bSchristos      If the FMT format string is non-nullptr, then a `: ` is appended to the
1084b169a6bSchristos      messages, followed by the rendering of that format string with ARGS.
1094b169a6bSchristos      The format string is rendered during construction and is re-used as is
1104b169a6bSchristos      for the message on exit.  */
1114b169a6bSchristos 
1124b169a6bSchristos   scoped_debug_start_end (PT &debug_enabled, const char *module,
1134b169a6bSchristos 			  const char *func, const char *start_prefix,
1144b169a6bSchristos 			  const char *end_prefix, const char *fmt,
1154b169a6bSchristos 			  va_list args)
1164b169a6bSchristos     ATTRIBUTE_NULL_PRINTF (7, 0)
1174b169a6bSchristos     : m_debug_enabled (debug_enabled),
1184b169a6bSchristos       m_module (module),
1194b169a6bSchristos       m_func (func),
1204b169a6bSchristos       m_end_prefix (end_prefix),
1214b169a6bSchristos       m_with_format (fmt != nullptr)
1224b169a6bSchristos   {
1234b169a6bSchristos     if (is_debug_enabled ())
1244b169a6bSchristos       {
1254b169a6bSchristos 	if (fmt != nullptr)
1264b169a6bSchristos 	  {
1274b169a6bSchristos 	    m_msg = string_vprintf (fmt, args);
1284b169a6bSchristos 	    debug_prefixed_printf (m_module, m_func, "%s: %s",
1294b169a6bSchristos 				   start_prefix, m_msg->c_str ());
1304b169a6bSchristos 	  }
1314b169a6bSchristos 	else
1324b169a6bSchristos 	  debug_prefixed_printf (m_module, m_func, "%s", start_prefix);
1334b169a6bSchristos 
1344b169a6bSchristos 	++debug_print_depth;
1354b169a6bSchristos 	m_must_decrement_print_depth = true;
1364b169a6bSchristos       }
1374b169a6bSchristos   }
1384b169a6bSchristos 
1394b169a6bSchristos   DISABLE_COPY_AND_ASSIGN (scoped_debug_start_end);
1404b169a6bSchristos 
141*5ba1f45fSchristos   scoped_debug_start_end (scoped_debug_start_end &&other)
142*5ba1f45fSchristos     : m_debug_enabled (other.m_debug_enabled),
143*5ba1f45fSchristos       m_module (other.m_module),
144*5ba1f45fSchristos       m_func (other.m_func),
145*5ba1f45fSchristos       m_end_prefix (other.m_end_prefix),
146*5ba1f45fSchristos       m_msg (other.m_msg),
147*5ba1f45fSchristos       m_with_format (other.m_with_format),
148*5ba1f45fSchristos       m_must_decrement_print_depth (other.m_must_decrement_print_depth),
149*5ba1f45fSchristos       m_disabled (other.m_disabled)
150*5ba1f45fSchristos   {
151*5ba1f45fSchristos     /* Avoid the moved-from object doing the side-effects in its destructor.  */
152*5ba1f45fSchristos     other.m_disabled = true;
153*5ba1f45fSchristos   }
1544b169a6bSchristos 
1554b169a6bSchristos   ~scoped_debug_start_end ()
1564b169a6bSchristos   {
157*5ba1f45fSchristos     if (m_disabled)
158*5ba1f45fSchristos       return;
159*5ba1f45fSchristos 
1604b169a6bSchristos     if (m_must_decrement_print_depth)
1614b169a6bSchristos       {
1624b169a6bSchristos 	gdb_assert (debug_print_depth > 0);
1634b169a6bSchristos 	--debug_print_depth;
1644b169a6bSchristos       }
1654b169a6bSchristos 
1664b169a6bSchristos     if (is_debug_enabled ())
1674b169a6bSchristos       {
1684b169a6bSchristos 	if (m_with_format)
1694b169a6bSchristos 	  {
1704b169a6bSchristos 	    if (m_msg.has_value ())
1714b169a6bSchristos 	      debug_prefixed_printf (m_module, m_func, "%s: %s",
1724b169a6bSchristos 				     m_end_prefix, m_msg->c_str ());
1734b169a6bSchristos 	    else
1744b169a6bSchristos 	      {
1754b169a6bSchristos 		/* A format string was passed to the constructor, but debug
1764b169a6bSchristos 		   control variable wasn't set at the time, so we don't have the
1774b169a6bSchristos 		   rendering of the format string.  */
1784b169a6bSchristos 		debug_prefixed_printf (m_module, m_func, "%s: <%s debugging was not enabled on entry>",
1794b169a6bSchristos 				       m_end_prefix, m_module);
1804b169a6bSchristos 	      }
1814b169a6bSchristos 	  }
1824b169a6bSchristos 	else
1834b169a6bSchristos 	  debug_prefixed_printf (m_module, m_func, "%s", m_end_prefix);
1844b169a6bSchristos       }
1854b169a6bSchristos   }
1864b169a6bSchristos 
1874b169a6bSchristos private:
1884b169a6bSchristos 
1894b169a6bSchristos   /* This function is specialized based on the type PT.  Returns true if
1904b169a6bSchristos      M_DEBUG_ENABLED indicates this debug setting is enabled, otherwise,
1914b169a6bSchristos      return false.  */
1924b169a6bSchristos   bool is_debug_enabled () const;
1934b169a6bSchristos 
1944b169a6bSchristos   /* Reference to the debug setting, or a callback that can read the debug
1954b169a6bSchristos      setting.  Access the value of this by calling IS_DEBUG_ENABLED.  */
1964b169a6bSchristos   PT &m_debug_enabled;
1974b169a6bSchristos 
1984b169a6bSchristos   const char *m_module;
1994b169a6bSchristos   const char *m_func;
2004b169a6bSchristos   const char *m_end_prefix;
2014b169a6bSchristos 
2024b169a6bSchristos   /* The result of formatting the format string in the constructor.  */
203*5ba1f45fSchristos   std::optional<std::string> m_msg;
2044b169a6bSchristos 
2054b169a6bSchristos   /* True is a non-nullptr format was passed to the constructor.  */
2064b169a6bSchristos   bool m_with_format;
2074b169a6bSchristos 
2084b169a6bSchristos   /* This is used to handle the case where debugging is enabled during
2094b169a6bSchristos      construction but not during destruction, or vice-versa.  We want to make
2104b169a6bSchristos      sure there are as many increments are there are decrements.  */
2114b169a6bSchristos   bool m_must_decrement_print_depth = false;
212*5ba1f45fSchristos 
213*5ba1f45fSchristos   /* True if this object was moved from, and the destructor behavior must be
214*5ba1f45fSchristos      inhibited.  */
215*5ba1f45fSchristos   bool m_disabled = false;
2164b169a6bSchristos };
2174b169a6bSchristos 
2184b169a6bSchristos /* Implementation of is_debug_enabled when PT is an invokable type.  */
2194b169a6bSchristos 
2204b169a6bSchristos template<typename PT>
2214b169a6bSchristos inline bool
2224b169a6bSchristos scoped_debug_start_end<PT>::is_debug_enabled () const
2234b169a6bSchristos {
2244b169a6bSchristos   return m_debug_enabled ();
2254b169a6bSchristos }
2264b169a6bSchristos 
2274b169a6bSchristos /* Implementation of is_debug_enabled when PT is 'bool &'.  */
2284b169a6bSchristos 
2294b169a6bSchristos template<>
2304b169a6bSchristos inline bool
2314b169a6bSchristos scoped_debug_start_end<bool &>::is_debug_enabled () const
2324b169a6bSchristos {
2334b169a6bSchristos   return m_debug_enabled;
2344b169a6bSchristos }
2354b169a6bSchristos 
2364b169a6bSchristos /* Wrapper around the scoped_debug_start_end constructor to allow the
2374b169a6bSchristos    caller to create an object using 'auto' type, the actual type will be
2384b169a6bSchristos    based on the type of the PRED argument.  All arguments are forwarded to
2394b169a6bSchristos    the scoped_debug_start_end constructor.  */
2404b169a6bSchristos 
2414b169a6bSchristos template<typename PT>
2424b169a6bSchristos static inline scoped_debug_start_end<PT &> ATTRIBUTE_NULL_PRINTF (6, 7)
2434b169a6bSchristos make_scoped_debug_start_end (PT &&pred, const char *module, const char *func,
2444b169a6bSchristos 			     const char *start_prefix,
2454b169a6bSchristos 			     const char *end_prefix, const char *fmt, ...)
2464b169a6bSchristos {
2474b169a6bSchristos   va_list args;
2484b169a6bSchristos   va_start (args, fmt);
2494b169a6bSchristos   auto res = scoped_debug_start_end<PT &> (pred, module, func, start_prefix,
2504b169a6bSchristos 					   end_prefix, fmt, args);
2514b169a6bSchristos   va_end (args);
2524b169a6bSchristos 
2534b169a6bSchristos   return res;
2544b169a6bSchristos }
2554b169a6bSchristos 
2564b169a6bSchristos /* Helper to define a module-specific start/end debug macro.  */
2574b169a6bSchristos 
2584b169a6bSchristos #define scoped_debug_start_end(debug_enabled, module, fmt, ...)		\
2594b169a6bSchristos   auto CONCAT(scoped_debug_start_end, __LINE__)				\
2604b169a6bSchristos     = make_scoped_debug_start_end (debug_enabled, module, 	\
2614b169a6bSchristos 				   __func__, "start", "end",	\
2624b169a6bSchristos 				   fmt, ##__VA_ARGS__)
2634b169a6bSchristos 
2644b169a6bSchristos /* Helper to define a module-specific enter/exit debug macro.  This is a special
2654b169a6bSchristos    case of `scoped_debug_start_end` where the start and end messages are "enter"
2664b169a6bSchristos    and "exit", to denote entry and exit of a function.  */
2674b169a6bSchristos 
2684b169a6bSchristos #define scoped_debug_enter_exit(debug_enabled, module)	\
2694b169a6bSchristos   auto CONCAT(scoped_debug_start_end, __LINE__)				\
2704b169a6bSchristos     = make_scoped_debug_start_end (debug_enabled, module, 	\
2714b169a6bSchristos 				   __func__, "enter", "exit",	\
2724b169a6bSchristos 				   nullptr)
2734b169a6bSchristos 
2748dffb485Schristos #endif /* COMMON_COMMON_DEBUG_H */
275