| /* 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 */ |