|  | /* Declarations for debug printing functions. | 
|  |  | 
|  | Copyright (C) 2014-2023 Free Software Foundation, Inc. | 
|  |  | 
|  | This file is part of GDB. | 
|  |  | 
|  | This program is free software; you can redistribute it and/or modify | 
|  | it under the terms of the GNU General Public License as published by | 
|  | the Free Software Foundation; either version 3 of the License, or | 
|  | (at your option) any later version. | 
|  |  | 
|  | This program is distributed in the hope that it will be useful, | 
|  | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | GNU General Public License for more details. | 
|  |  | 
|  | You should have received a copy of the GNU General Public License | 
|  | along with this program.  If not, see <http://www.gnu.org/licenses/>.  */ | 
|  |  | 
|  | #ifndef COMMON_COMMON_DEBUG_H | 
|  | #define COMMON_COMMON_DEBUG_H | 
|  |  | 
|  | #include "gdbsupport/gdb_optional.h" | 
|  | #include "gdbsupport/preprocessor.h" | 
|  |  | 
|  | #include <stdarg.h> | 
|  |  | 
|  | /* Set to true to enable debugging of hardware breakpoint/ | 
|  | watchpoint support code.  */ | 
|  |  | 
|  | extern bool show_debug_regs; | 
|  |  | 
|  | /* Print a formatted message to the appropriate channel for | 
|  | debugging output for the client.  */ | 
|  |  | 
|  | extern void debug_printf (const char *format, ...) | 
|  | ATTRIBUTE_PRINTF (1, 2); | 
|  |  | 
|  | /* Print a formatted message to the appropriate channel for | 
|  | debugging output for the client.  This function must be | 
|  | provided by the client.  */ | 
|  |  | 
|  | extern void debug_vprintf (const char *format, va_list ap) | 
|  | ATTRIBUTE_PRINTF (1, 0); | 
|  |  | 
|  | /* Print a debug statement prefixed with the module and function name, and | 
|  | with a newline at the end.  */ | 
|  |  | 
|  | extern void ATTRIBUTE_PRINTF (3, 4) debug_prefixed_printf | 
|  | (const char *module, const char *func, const char *format, ...); | 
|  |  | 
|  | /* Print a debug statement prefixed with the module and function name, and | 
|  | with a newline at the end.  */ | 
|  |  | 
|  | extern void ATTRIBUTE_PRINTF (3, 0) debug_prefixed_vprintf | 
|  | (const char *module, const char *func, const char *format, va_list args); | 
|  |  | 
|  | /* Helper to define "_debug_print" macros. | 
|  |  | 
|  | DEBUG_ENABLED_COND is an expression that evaluates to true if the debugging | 
|  | statement is enabled and should be printed. | 
|  |  | 
|  | The other arguments, as well as the name of the current function, are | 
|  | forwarded to debug_prefixed_printf.  */ | 
|  |  | 
|  | #define debug_prefixed_printf_cond(debug_enabled_cond, module, fmt, ...) \ | 
|  | do \ | 
|  | { \ | 
|  | if (debug_enabled_cond) \ | 
|  | debug_prefixed_printf (module, __func__, fmt, ##__VA_ARGS__); \ | 
|  | } \ | 
|  | while (0) | 
|  |  | 
|  | #define debug_prefixed_printf_cond_nofunc(debug_enabled_cond, module, fmt, ...) \ | 
|  | do \ | 
|  | { \ | 
|  | if (debug_enabled_cond) \ | 
|  | debug_prefixed_printf (module, nullptr, fmt, ##__VA_ARGS__); \ | 
|  | } \ | 
|  | while (0) | 
|  |  | 
|  | /* Nesting depth of scoped_debug_start_end objects.  */ | 
|  |  | 
|  | extern int debug_print_depth; | 
|  |  | 
|  | /* Print a message on construction and destruction, to denote the start and end | 
|  | of an operation.  Increment DEBUG_PRINT_DEPTH on construction and decrement | 
|  | it on destruction, such that nested debug statements will be printed with | 
|  | an indent and appear "inside" this one.  */ | 
|  |  | 
|  | template<typename PT> | 
|  | struct scoped_debug_start_end | 
|  | { | 
|  | /* DEBUG_ENABLED is a reference to a variable that indicates whether debugging | 
|  | is enabled, so if the debug statements should be printed.  Is is read | 
|  | separately at construction and destruction, such that the start statement | 
|  | could be printed but not the end statement, or vice-versa. | 
|  |  | 
|  | DEBUG_ENABLED should either be of type 'bool &' or should be a type | 
|  | that can be invoked. | 
|  |  | 
|  | MODULE and FUNC are forwarded to debug_prefixed_printf. | 
|  |  | 
|  | START_PREFIX and END_PREFIX are the statements to print on construction and | 
|  | destruction, respectively. | 
|  |  | 
|  | If the FMT format string is non-nullptr, then a `: ` is appended to the | 
|  | messages, followed by the rendering of that format string with ARGS. | 
|  | The format string is rendered during construction and is re-used as is | 
|  | for the message on exit.  */ | 
|  |  | 
|  | scoped_debug_start_end (PT &debug_enabled, const char *module, | 
|  | const char *func, const char *start_prefix, | 
|  | const char *end_prefix, const char *fmt, | 
|  | va_list args) | 
|  | ATTRIBUTE_NULL_PRINTF (7, 0) | 
|  | : m_debug_enabled (debug_enabled), | 
|  | m_module (module), | 
|  | m_func (func), | 
|  | m_end_prefix (end_prefix), | 
|  | m_with_format (fmt != nullptr) | 
|  | { | 
|  | if (is_debug_enabled ()) | 
|  | { | 
|  | if (fmt != nullptr) | 
|  | { | 
|  | m_msg = string_vprintf (fmt, args); | 
|  | debug_prefixed_printf (m_module, m_func, "%s: %s", | 
|  | start_prefix, m_msg->c_str ()); | 
|  | } | 
|  | else | 
|  | debug_prefixed_printf (m_module, m_func, "%s", start_prefix); | 
|  |  | 
|  | ++debug_print_depth; | 
|  | m_must_decrement_print_depth = true; | 
|  | } | 
|  | } | 
|  |  | 
|  | DISABLE_COPY_AND_ASSIGN (scoped_debug_start_end); | 
|  |  | 
|  | scoped_debug_start_end (scoped_debug_start_end &&other) | 
|  | : m_debug_enabled (other.m_debug_enabled), | 
|  | m_module (other.m_module), | 
|  | m_func (other.m_func), | 
|  | m_end_prefix (other.m_end_prefix), | 
|  | m_msg (other.m_msg), | 
|  | m_with_format (other.m_with_format), | 
|  | m_must_decrement_print_depth (other.m_must_decrement_print_depth), | 
|  | m_disabled (other.m_disabled) | 
|  | { | 
|  | /* Avoid the moved-from object doing the side-effects in its destructor.  */ | 
|  | other.m_disabled = true; | 
|  | } | 
|  |  | 
|  | ~scoped_debug_start_end () | 
|  | { | 
|  | if (m_disabled) | 
|  | return; | 
|  |  | 
|  | if (m_must_decrement_print_depth) | 
|  | { | 
|  | gdb_assert (debug_print_depth > 0); | 
|  | --debug_print_depth; | 
|  | } | 
|  |  | 
|  | if (is_debug_enabled ()) | 
|  | { | 
|  | if (m_with_format) | 
|  | { | 
|  | if (m_msg.has_value ()) | 
|  | debug_prefixed_printf (m_module, m_func, "%s: %s", | 
|  | m_end_prefix, m_msg->c_str ()); | 
|  | else | 
|  | { | 
|  | /* A format string was passed to the constructor, but debug | 
|  | control variable wasn't set at the time, so we don't have the | 
|  | rendering of the format string.  */ | 
|  | debug_prefixed_printf (m_module, m_func, "%s: <%s debugging was not enabled on entry>", | 
|  | m_end_prefix, m_module); | 
|  | } | 
|  | } | 
|  | else | 
|  | debug_prefixed_printf (m_module, m_func, "%s", m_end_prefix); | 
|  | } | 
|  | } | 
|  |  | 
|  | private: | 
|  |  | 
|  | /* This function is specialized based on the type PT.  Returns true if | 
|  | M_DEBUG_ENABLED indicates this debug setting is enabled, otherwise, | 
|  | return false.  */ | 
|  | bool is_debug_enabled () const; | 
|  |  | 
|  | /* Reference to the debug setting, or a callback that can read the debug | 
|  | setting.  Access the value of this by calling IS_DEBUG_ENABLED.  */ | 
|  | PT &m_debug_enabled; | 
|  |  | 
|  | const char *m_module; | 
|  | const char *m_func; | 
|  | const char *m_end_prefix; | 
|  |  | 
|  | /* The result of formatting the format string in the constructor.  */ | 
|  | gdb::optional<std::string> m_msg; | 
|  |  | 
|  | /* True is a non-nullptr format was passed to the constructor.  */ | 
|  | bool m_with_format; | 
|  |  | 
|  | /* This is used to handle the case where debugging is enabled during | 
|  | construction but not during destruction, or vice-versa.  We want to make | 
|  | sure there are as many increments are there are decrements.  */ | 
|  | bool m_must_decrement_print_depth = false; | 
|  |  | 
|  | /* True if this object was moved from, and the destructor behavior must be | 
|  | inhibited.  */ | 
|  | bool m_disabled = false; | 
|  | }; | 
|  |  | 
|  | /* Implementation of is_debug_enabled when PT is an invokable type.  */ | 
|  |  | 
|  | template<typename PT> | 
|  | inline bool | 
|  | scoped_debug_start_end<PT>::is_debug_enabled () const | 
|  | { | 
|  | return m_debug_enabled (); | 
|  | } | 
|  |  | 
|  | /* Implementation of is_debug_enabled when PT is 'bool &'.  */ | 
|  |  | 
|  | template<> | 
|  | inline bool | 
|  | scoped_debug_start_end<bool &>::is_debug_enabled () const | 
|  | { | 
|  | return m_debug_enabled; | 
|  | } | 
|  |  | 
|  | /* Wrapper around the scoped_debug_start_end constructor to allow the | 
|  | caller to create an object using 'auto' type, the actual type will be | 
|  | based on the type of the PRED argument.  All arguments are forwarded to | 
|  | the scoped_debug_start_end constructor.  */ | 
|  |  | 
|  | template<typename PT> | 
|  | static inline scoped_debug_start_end<PT &> ATTRIBUTE_NULL_PRINTF (6, 7) | 
|  | make_scoped_debug_start_end (PT &&pred, const char *module, const char *func, | 
|  | const char *start_prefix, | 
|  | const char *end_prefix, const char *fmt, ...) | 
|  | { | 
|  | va_list args; | 
|  | va_start (args, fmt); | 
|  | auto res = scoped_debug_start_end<PT &> (pred, module, func, start_prefix, | 
|  | end_prefix, fmt, args); | 
|  | va_end (args); | 
|  |  | 
|  | return res; | 
|  | } | 
|  |  | 
|  | /* Helper to define a module-specific start/end debug macro.  */ | 
|  |  | 
|  | #define scoped_debug_start_end(debug_enabled, module, fmt, ...)		\ | 
|  | auto CONCAT(scoped_debug_start_end, __LINE__)				\ | 
|  | = make_scoped_debug_start_end (debug_enabled, module, 	\ | 
|  | __func__, "start", "end",	\ | 
|  | fmt, ##__VA_ARGS__) | 
|  |  | 
|  | /* Helper to define a module-specific enter/exit debug macro.  This is a special | 
|  | case of `scoped_debug_start_end` where the start and end messages are "enter" | 
|  | and "exit", to denote entry and exit of a function.  */ | 
|  |  | 
|  | #define scoped_debug_enter_exit(debug_enabled, module)	\ | 
|  | auto CONCAT(scoped_debug_start_end, __LINE__)				\ | 
|  | = make_scoped_debug_start_end (debug_enabled, module, 	\ | 
|  | __func__, "enter", "exit",	\ | 
|  | nullptr) | 
|  |  | 
|  | #endif /* COMMON_COMMON_DEBUG_H */ |