|  | /* Command-line output logging for GDB, the GNU debugger. | 
|  |  | 
|  | Copyright (C) 2003-2022 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/>.  */ | 
|  |  | 
|  | #include "defs.h" | 
|  | #include "gdbcmd.h" | 
|  | #include "ui-out.h" | 
|  | #include "interps.h" | 
|  | #include "cli/cli-style.h" | 
|  | #include "cli/cli-decode.h" | 
|  |  | 
|  | static std::string saved_filename; | 
|  |  | 
|  | static std::string logging_filename = "gdb.txt"; | 
|  | static void | 
|  | show_logging_filename (struct ui_file *file, int from_tty, | 
|  | struct cmd_list_element *c, const char *value) | 
|  | { | 
|  | gdb_printf (file, _("The current logfile is \"%ps\".\n"), | 
|  | styled_string (file_name_style.style (), value)); | 
|  | } | 
|  |  | 
|  | static bool logging_overwrite; | 
|  |  | 
|  | static void | 
|  | maybe_warn_already_logging () | 
|  | { | 
|  | if (!saved_filename.empty ()) | 
|  | warning (_("Currently logging to %s.  Turn the logging off and on to " | 
|  | "make the new setting effective."), saved_filename.c_str ()); | 
|  | } | 
|  |  | 
|  | static void | 
|  | set_logging_overwrite (const char *args, | 
|  | int from_tty, struct cmd_list_element *c) | 
|  | { | 
|  | maybe_warn_already_logging (); | 
|  | } | 
|  |  | 
|  | static void | 
|  | show_logging_overwrite (struct ui_file *file, int from_tty, | 
|  | struct cmd_list_element *c, const char *value) | 
|  | { | 
|  | if (logging_overwrite) | 
|  | gdb_printf (file, _("on: Logging overwrites the log file.\n")); | 
|  | else | 
|  | gdb_printf (file, _("off: Logging appends to the log file.\n")); | 
|  | } | 
|  |  | 
|  | /* Value as configured by the user.  */ | 
|  | static bool logging_redirect; | 
|  | static bool debug_redirect; | 
|  |  | 
|  | static void | 
|  | set_logging_redirect (const char *args, | 
|  | int from_tty, struct cmd_list_element *c) | 
|  | { | 
|  | maybe_warn_already_logging (); | 
|  | } | 
|  |  | 
|  | static void | 
|  | show_logging_redirect (struct ui_file *file, int from_tty, | 
|  | struct cmd_list_element *c, const char *value) | 
|  | { | 
|  | if (logging_redirect) | 
|  | gdb_printf (file, _("on: Output will go only to the log file.\n")); | 
|  | else | 
|  | gdb_printf | 
|  | (file, | 
|  | _("off: Output will go to both the screen and the log file.\n")); | 
|  | } | 
|  |  | 
|  | static void | 
|  | show_logging_debug_redirect (struct ui_file *file, int from_tty, | 
|  | struct cmd_list_element *c, const char *value) | 
|  | { | 
|  | if (debug_redirect) | 
|  | gdb_printf (file, _("on: Debug output will go only to the log file.\n")); | 
|  | else | 
|  | gdb_printf | 
|  | (file, | 
|  | _("off: Debug output will go to both the screen and the log file.\n")); | 
|  | } | 
|  |  | 
|  | /* If we've pushed output files, close them and pop them.  */ | 
|  | static void | 
|  | pop_output_files (void) | 
|  | { | 
|  | current_interp_set_logging (NULL, false, false); | 
|  |  | 
|  | /* Stay consistent with handle_redirections.  */ | 
|  | if (!current_uiout->is_mi_like_p ()) | 
|  | current_uiout->redirect (NULL); | 
|  | } | 
|  |  | 
|  | /* This is a helper for the `set logging' command.  */ | 
|  | static void | 
|  | handle_redirections (int from_tty) | 
|  | { | 
|  | if (!saved_filename.empty ()) | 
|  | { | 
|  | gdb_printf ("Already logging to %s.\n", | 
|  | saved_filename.c_str ()); | 
|  | return; | 
|  | } | 
|  |  | 
|  | stdio_file_up log (new no_terminal_escape_file ()); | 
|  | if (!log->open (logging_filename.c_str (), logging_overwrite ? "w" : "a")) | 
|  | perror_with_name (_("set logging")); | 
|  |  | 
|  | /* Redirects everything to gdb_stdout while this is running.  */ | 
|  | if (from_tty) | 
|  | { | 
|  | if (!logging_redirect) | 
|  | gdb_printf ("Copying output to %s.\n", | 
|  | logging_filename.c_str ()); | 
|  | else | 
|  | gdb_printf ("Redirecting output to %s.\n", | 
|  | logging_filename.c_str ()); | 
|  |  | 
|  | if (!debug_redirect) | 
|  | gdb_printf ("Copying debug output to %s.\n", | 
|  | logging_filename.c_str ()); | 
|  | else | 
|  | gdb_printf ("Redirecting debug output to %s.\n", | 
|  | logging_filename.c_str ()); | 
|  | } | 
|  |  | 
|  | saved_filename = logging_filename; | 
|  |  | 
|  | /* Let the interpreter do anything it needs.  */ | 
|  | current_interp_set_logging (std::move (log), logging_redirect, | 
|  | debug_redirect); | 
|  |  | 
|  | /* Redirect the current ui-out object's output to the log.  Use | 
|  | gdb_stdout, not log, since the interpreter may have created a tee | 
|  | that wraps the log.  Don't do the redirect for MI, it confuses | 
|  | MI's ui-out scheme.  Note that we may get here with MI as current | 
|  | interpreter, but with the current ui_out as a CLI ui_out, with | 
|  | '-interpreter-exec console "set logging on"'.  */ | 
|  | if (!current_uiout->is_mi_like_p ()) | 
|  | current_uiout->redirect (gdb_stdout); | 
|  | } | 
|  |  | 
|  | static void | 
|  | set_logging_on (const char *args, int from_tty) | 
|  | { | 
|  | const char *rest = args; | 
|  |  | 
|  | if (rest && *rest) | 
|  | logging_filename = rest; | 
|  |  | 
|  | handle_redirections (from_tty); | 
|  | } | 
|  |  | 
|  | static void | 
|  | set_logging_off (const char *args, int from_tty) | 
|  | { | 
|  | if (saved_filename.empty ()) | 
|  | return; | 
|  |  | 
|  | pop_output_files (); | 
|  | if (from_tty) | 
|  | gdb_printf ("Done logging to %s.\n", | 
|  | saved_filename.c_str ()); | 
|  | saved_filename.clear (); | 
|  | } | 
|  |  | 
|  | static bool logging_enabled; | 
|  |  | 
|  | static void | 
|  | set_logging_enabled (const char *args, | 
|  | int from_tty, struct cmd_list_element *c) | 
|  | { | 
|  | if (logging_enabled) | 
|  | set_logging_on (args, from_tty); | 
|  | else | 
|  | set_logging_off (args, from_tty); | 
|  | } | 
|  |  | 
|  | static void | 
|  | show_logging_enabled (struct ui_file *file, int from_tty, | 
|  | struct cmd_list_element *c, const char *value) | 
|  | { | 
|  | if (logging_enabled) | 
|  | gdb_printf (file, _("on: Logging is enabled.\n")); | 
|  | else | 
|  | gdb_printf (file, _("off: Logging is disabled.\n")); | 
|  | } | 
|  |  | 
|  | void _initialize_cli_logging (); | 
|  | void | 
|  | _initialize_cli_logging () | 
|  | { | 
|  | static struct cmd_list_element *set_logging_cmdlist, *show_logging_cmdlist; | 
|  |  | 
|  | /* Set/show logging.  */ | 
|  | add_setshow_prefix_cmd ("logging", class_support, | 
|  | _("Set logging options."), | 
|  | _("Show logging options."), | 
|  | &set_logging_cmdlist, &show_logging_cmdlist, | 
|  | &setlist, &showlist); | 
|  |  | 
|  | /* Set/show logging overwrite.  */ | 
|  | add_setshow_boolean_cmd ("overwrite", class_support, &logging_overwrite, _("\ | 
|  | Set whether logging overwrites or appends to the log file."), _("\ | 
|  | Show whether logging overwrites or appends to the log file."), _("\ | 
|  | If set, logging overwrites the log file."), | 
|  | set_logging_overwrite, | 
|  | show_logging_overwrite, | 
|  | &set_logging_cmdlist, &show_logging_cmdlist); | 
|  |  | 
|  | /* Set/show logging redirect.  */ | 
|  | add_setshow_boolean_cmd ("redirect", class_support, &logging_redirect, _("\ | 
|  | Set the logging output mode."), _("\ | 
|  | Show the logging output mode."), _("\ | 
|  | If redirect is off, output will go to both the screen and the log file.\n\ | 
|  | If redirect is on, output will go only to the log file."), | 
|  | set_logging_redirect, | 
|  | show_logging_redirect, | 
|  | &set_logging_cmdlist, &show_logging_cmdlist); | 
|  |  | 
|  | /* Set/show logging debugredirect.  */ | 
|  | add_setshow_boolean_cmd ("debugredirect", class_support, | 
|  | &debug_redirect, _("\ | 
|  | Set the logging debug output mode."), _("\ | 
|  | Show the logging debug output mode."), _("\ | 
|  | If debug redirect is off, debug will go to both the screen and the log file.\n\ | 
|  | If debug redirect is on, debug will go only to the log file."), | 
|  | set_logging_redirect, | 
|  | show_logging_debug_redirect, | 
|  | &set_logging_cmdlist, &show_logging_cmdlist); | 
|  |  | 
|  | /* Set/show logging file.  */ | 
|  | add_setshow_filename_cmd ("file", class_support, &logging_filename, _("\ | 
|  | Set the current logfile."), _("\ | 
|  | Show the current logfile."), _("\ | 
|  | The logfile is used when directing GDB's output."), | 
|  | NULL, | 
|  | show_logging_filename, | 
|  | &set_logging_cmdlist, &show_logging_cmdlist); | 
|  |  | 
|  | /* Set/show logging enabled.  */ | 
|  | set_show_commands setshow_logging_enabled_cmds | 
|  | = add_setshow_boolean_cmd ("enabled", class_support, &logging_enabled, | 
|  | _("Enable logging."), | 
|  | _("Show whether logging is enabled."), | 
|  | _("When on, enable logging."), | 
|  | set_logging_enabled, | 
|  | show_logging_enabled, | 
|  | &set_logging_cmdlist, &show_logging_cmdlist); | 
|  |  | 
|  | /* Set logging on, deprecated alias.  */ | 
|  | cmd_list_element *set_logging_on_cmd | 
|  | = add_alias_cmd ("on", setshow_logging_enabled_cmds.set, class_support, | 
|  | false, &set_logging_cmdlist); | 
|  | deprecate_cmd (set_logging_on_cmd, "set logging enabled on"); | 
|  | set_logging_on_cmd->default_args = "on"; | 
|  |  | 
|  | /* Set logging off, deprecated alias.  */ | 
|  | cmd_list_element *set_logging_off_cmd | 
|  | = add_alias_cmd ("off", setshow_logging_enabled_cmds.set, class_support, | 
|  | false, &set_logging_cmdlist); | 
|  | deprecate_cmd (set_logging_off_cmd, "set logging enabled off"); | 
|  | set_logging_off_cmd->default_args = "off"; | 
|  | } |