From: Tom Tromey Date: Sat, 6 Dec 2025 21:35:24 +0000 (-0600) Subject: Add a new logging_file implementation X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=aed0772e66e921c235165480276600a7c7dfc048;p=thirdparty%2Fbinutils-gdb.git Add a new logging_file implementation This adds a new logging_file subclass of ui_file. This new subclass handles the details of logging, by consulting the relevant globals. I think a dependency on globals is warranted here, because the logging settings themselves are global. The idea of this approach is that rather than modifying the output pipeline in response to logging commands, a logging_file will simply always be in the pipeline, and will then react to the appropriate settings. ("Appropriate" because there are tests that the logger doesn't immediately react to changes, so it captures settings at the moment logging starts.) The new code isn't actually used yet -- nothing in this patch constructs a logging_file. It's separate for easier review. Approved-By: Andrew Burgess --- diff --git a/gdb/cli/cli-logging.c b/gdb/cli/cli-logging.c index c00c6bf0488..6f2a6287700 100644 --- a/gdb/cli/cli-logging.c +++ b/gdb/cli/cli-logging.c @@ -20,6 +20,7 @@ #include "cli/cli-cmds.h" #include "ui-out.h" #include "interps.h" +#include "logging-file.h" #include "cli/cli-style.h" #include "cli/cli-decode.h" @@ -61,6 +62,9 @@ show_logging_overwrite (struct ui_file *file, int from_tty, gdb_printf (file, _("off: Logging appends to the log file.\n")); } +/* The current log file, or nullptr if none. */ +static ui_file_up log_file; + /* Value as configured by the user. */ static bool logging_redirect; static bool debug_redirect; @@ -96,6 +100,119 @@ show_logging_debug_redirect (struct ui_file *file, int from_tty, _("off: Debug output will go to both the screen and the log file.\n")); } +/* Values as used by the logging_file implementation. These are + separate and only set when logging is enabled, because historically + gdb required you to disable and re-enable logging to change these + settings. */ + +static bool logging_redirect_for_file; +static bool debug_redirect_for_file; + +/* See logging-file.h. */ + +template +bool +logging_file::ordinary_output () const +{ + if (log_file == nullptr) + return true; + if (logging_redirect_for_file) + return false; + if (debug_redirect_for_file) + return !m_for_stdlog; + return true; +} + +/* See logging-file.h. */ + +template +void +logging_file::flush () +{ + if (log_file != nullptr) + log_file->flush (); + /* Always flushing seems fine. */ + m_out->flush (); +} + +/* See logging-file.h. */ + +template +bool +logging_file::can_page () const +{ + /* If all output is redirected, do not page. */ + if (!ordinary_output ()) + return false; + /* In other cases, paging happens if the underlying stream can + page. */ + return m_out->can_page (); +} + +/* See logging-file.h. */ + +template +void +logging_file::write (const char *buf, long length_buf) +{ + if (log_file != nullptr) + log_file->write (buf, length_buf); + if (ordinary_output ()) + m_out->write (buf, length_buf); +} + +/* See logging-file.h. */ + +template +void +logging_file::write_async_safe (const char *buf, long length_buf) +{ + if (log_file != nullptr) + log_file->write_async_safe (buf, length_buf); + if (ordinary_output ()) + m_out->write_async_safe (buf, length_buf); +} + +/* See logging-file.h. */ + +template +void +logging_file::puts (const char *linebuffer) +{ + if (log_file != nullptr) + log_file->puts (linebuffer); + if (ordinary_output ()) + m_out->puts (linebuffer); +} + +/* See logging-file.h. */ + +template +void +logging_file::emit_style_escape (const ui_file_style &style) +{ + if (log_file != nullptr) + log_file->emit_style_escape (style); + if (ordinary_output ()) + m_out->emit_style_escape (style); +} + +/* See logging-file.h. */ + +template +void +logging_file::puts_unfiltered (const char *str) +{ + if (log_file != nullptr) + log_file->puts_unfiltered (str); + if (ordinary_output ()) + m_out->puts_unfiltered (str); +} + +/* The available instantiations of logging_file. */ +template class logging_file; +template class logging_file; + /* If we've pushed output files, close them and pop them. */ static void pop_output_files (void) @@ -141,6 +258,8 @@ handle_redirections (int from_tty) } saved_filename = logging_filename; + logging_redirect_for_file = logging_redirect; + debug_redirect_for_file = debug_redirect; /* Let the interpreter do anything it needs. */ current_interp_set_logging (std::move (log), logging_redirect, diff --git a/gdb/logging-file.h b/gdb/logging-file.h new file mode 100644 index 00000000000..5dfe1118494 --- /dev/null +++ b/gdb/logging-file.h @@ -0,0 +1,82 @@ +/* Copyright (C) 2025, 2026 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 . */ + +#ifndef GDB_LOGGING_FILE_H +#define GDB_LOGGING_FILE_H + +#include "ui-file.h" + +/* A ui_file implementation that optionally writes its output to a + second logging stream. Whether logging is actually done depends on + the user's logging settings. The precise underlying ui_file type + is a template parameter, so that either owning or non-owning + instances can be made. */ + +template +class logging_file : public ui_file +{ +public: + /* This wraps another stream. Whether or not output actually goes + to that stream depends on the redirection settings. FOR_STDLOG + should only be set for a stream intended by use as gdb_stdlog; + this is used to implement the "debug redirect" feature. */ + logging_file (T out, bool for_stdlog = false) + : m_out (std::move (out)), + m_for_stdlog (for_stdlog) + { + } + + void write (const char *buf, long length_buf) override; + void write_async_safe (const char *buf, long length_buf) override; + void puts (const char *) override; + void flush () override; + bool can_page () const override; + void emit_style_escape (const ui_file_style &style) override; + void puts_unfiltered (const char *str) override; + + bool isatty () override + { + /* Defer to the wrapped file. */ + return m_out->isatty (); + } + + bool term_out () override + { + /* Defer to the wrapped file. */ + return m_out->term_out (); + } + + bool can_emit_style_escape () override + { + /* Defer to the wrapped file. */ + return m_out->can_emit_style_escape (); + } + +private: + /* A helper function that returns true if output should go to + M_OUT. */ + bool ordinary_output () const; + + /* The underlying file. */ + T m_out; + + /* True if this stream is used for gdb_stdlog. This is used to + implement the debug redirect feature. */ + bool m_for_stdlog; +}; + +#endif /* GDB_LOGGING_FILE_H */