/* Declarations for debug printing functions.
- Copyright (C) 2014-2020 Free Software Foundation, Inc.
+ Copyright (C) 2014-2021 Free Software Foundation, Inc.
This file is part of GDB.
#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 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 */