| /* Declarations for debug printing functions. | |
| Copyright (C) 2014-2021 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. */ | |
| 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. | |
| 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. The format | |
| string is rendered during construction and is re-used as is for the | |
| message on exit. */ | |
| scoped_debug_start_end (bool &debug_enabled, const char *module, | |
| const char *func, const char *start_prefix, | |
| const char *end_prefix, const char *fmt, ...) | |
| ATTRIBUTE_NULL_PRINTF (7, 8) | |
| : m_debug_enabled (debug_enabled), | |
| m_module (module), | |
| m_func (func), | |
| m_end_prefix (end_prefix), | |
| m_with_format (fmt != nullptr) | |
| { | |
| if (m_debug_enabled) | |
| { | |
| if (fmt != nullptr) | |
| { | |
| va_list args; | |
| va_start (args, fmt); | |
| m_msg = string_vprintf (fmt, args); | |
| va_end (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 () | |
| { | |
| if (m_must_decrement_print_depth) | |
| { | |
| gdb_assert (debug_print_depth > 0); | |
| --debug_print_depth; | |
| } | |
| if (m_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: | |
| bool &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; | |
| }; | |
| /* Helper to define a module-specific start/end debug macro. */ | |
| #define scoped_debug_start_end(debug_enabled, module, fmt, ...) \ | |
| scoped_debug_start_end CONCAT(scoped_debug_start_end, __LINE__) \ | |
| (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) \ | |
| scoped_debug_start_end CONCAT(scoped_debug_start_end, __LINE__) \ | |
| (debug_enabled, module, __func__, "enter", "exit", nullptr) | |
| #endif /* COMMON_COMMON_DEBUG_H */ |