GDB (API)
/home/stan/gdb/src/gdb/cli/cli-logging.c
Go to the documentation of this file.
00001 /* Command-line output logging for GDB, the GNU debugger.
00002 
00003    Copyright (C) 2003-2013 Free Software Foundation, Inc.
00004 
00005    This file is part of GDB.
00006 
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License as published by
00009    the Free Software Foundation; either version 3 of the License, or
00010    (at your option) any later version.
00011 
00012    This program is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015    GNU General Public License for more details.
00016 
00017    You should have received a copy of the GNU General Public License
00018    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
00019 
00020 #include "defs.h"
00021 #include "gdbcmd.h"
00022 #include "ui-out.h"
00023 #include "interps.h"
00024 #include "gdb_assert.h"
00025 
00026 #include "gdb_string.h"
00027 
00028 /* These hold the pushed copies of the gdb output files.
00029    If NULL then nothing has yet been pushed.  */
00030 struct saved_output_files
00031 {
00032   struct ui_file *out;
00033   struct ui_file *err;
00034   struct ui_file *log;
00035   struct ui_file *targ;
00036   struct ui_file *targerr;
00037 };
00038 static struct saved_output_files saved_output;
00039 static char *saved_filename;
00040 
00041 static char *logging_filename;
00042 static void
00043 show_logging_filename (struct ui_file *file, int from_tty,
00044                        struct cmd_list_element *c, const char *value)
00045 {
00046   fprintf_filtered (file, _("The current logfile is \"%s\".\n"),
00047                     value);
00048 }
00049 
00050 static int logging_overwrite;
00051 
00052 static void
00053 set_logging_overwrite (char *args, int from_tty, struct cmd_list_element *c)
00054 {
00055   if (saved_filename)
00056     warning (_("Currently logging to %s.  Turn the logging off and on to "
00057                "make the new setting effective."), saved_filename);
00058 }
00059 
00060 static void
00061 show_logging_overwrite (struct ui_file *file, int from_tty,
00062                         struct cmd_list_element *c, const char *value)
00063 {
00064   fprintf_filtered (file,
00065                     _("Whether logging overwrites or "
00066                       "appends to the log file is %s.\n"),
00067                     value);
00068 }
00069 
00070 /* Value as configured by the user.  */
00071 static int logging_redirect;
00072 
00073 /* The on-disk file in use if logging is currently active together
00074    with redirection turned off (and therefore using tee_file_new).
00075    For active logging with redirection the on-disk file is directly in
00076    GDB_STDOUT and this variable is NULL.  */
00077 static struct ui_file *logging_no_redirect_file;
00078 
00079 static void
00080 set_logging_redirect (char *args, int from_tty, struct cmd_list_element *c)
00081 {
00082   struct cleanup *cleanups;
00083   struct ui_file *output, *new_logging_no_redirect_file;
00084   struct ui_out *uiout = current_uiout;
00085 
00086   if (saved_filename == NULL
00087       || (logging_redirect != 0 && logging_no_redirect_file == NULL)
00088       || (logging_redirect == 0 && logging_no_redirect_file != NULL))
00089     return;
00090 
00091   cleanups = make_cleanup (null_cleanup, NULL);
00092 
00093   if (logging_redirect != 0)
00094     {
00095       gdb_assert (logging_no_redirect_file != NULL);
00096 
00097       /* ui_out_redirect still has not been called for next
00098          gdb_stdout.  */
00099       make_cleanup_ui_file_delete (gdb_stdout);
00100 
00101       output = logging_no_redirect_file;
00102       new_logging_no_redirect_file = NULL;
00103 
00104       if (from_tty)
00105         fprintf_unfiltered (saved_output.out, "Redirecting output to %s.\n",
00106                             logging_filename);
00107     }
00108   else
00109     {
00110       gdb_assert (logging_no_redirect_file == NULL);
00111       output = tee_file_new (saved_output.out, 0, gdb_stdout, 0);
00112       if (output == NULL)
00113         perror_with_name (_("set logging"));
00114       new_logging_no_redirect_file = gdb_stdout;
00115 
00116       if (from_tty)
00117         fprintf_unfiltered (saved_output.out, "Copying output to %s.\n",
00118                             logging_filename);
00119     }
00120 
00121   /* Give the current interpreter a chance to do anything special that
00122      it might need for logging, such as updating other channels.  */
00123   if (current_interp_set_logging (1, output, NULL) == 0)
00124     {
00125       gdb_stdout = output;
00126       gdb_stdlog = output;
00127       gdb_stderr = output;
00128       gdb_stdtarg = output;
00129       gdb_stdtargerr = output;
00130     }
00131 
00132   logging_no_redirect_file = new_logging_no_redirect_file;
00133 
00134   /* There is a former output pushed on the ui_out_redirect stack.  We
00135      want to replace it by OUTPUT so we must pop the former value
00136      first.  We should either do both the pop and push or to do
00137      neither of it.  At least do not try to push OUTPUT if the pop
00138      already failed.  */
00139 
00140   if (ui_out_redirect (uiout, NULL) < 0
00141       || ui_out_redirect (uiout, output) < 0)
00142     warning (_("Current output protocol does not support redirection"));
00143 
00144   do_cleanups (cleanups);
00145 }
00146 
00147 static void
00148 show_logging_redirect (struct ui_file *file, int from_tty,
00149                        struct cmd_list_element *c, const char *value)
00150 {
00151   fprintf_filtered (file, _("The logging output mode is %s.\n"), value);
00152 }
00153 
00154 /* If we've pushed output files, close them and pop them.  */
00155 static void
00156 pop_output_files (void)
00157 {
00158   if (logging_no_redirect_file)
00159     {
00160       ui_file_delete (logging_no_redirect_file);
00161       logging_no_redirect_file = NULL;
00162     }
00163 
00164   if (current_interp_set_logging (0, NULL, NULL) == 0)
00165     {
00166       /* Only delete one of the files -- they are all set to the same
00167          value.  */
00168       ui_file_delete (gdb_stdout);
00169 
00170       gdb_stdout = saved_output.out;
00171       gdb_stderr = saved_output.err;
00172       gdb_stdlog = saved_output.log;
00173       gdb_stdtarg = saved_output.targ;
00174       gdb_stdtargerr = saved_output.targ;
00175     }
00176 
00177   saved_output.out = NULL;
00178   saved_output.err = NULL;
00179   saved_output.log = NULL;
00180   saved_output.targ = NULL;
00181   saved_output.targerr = NULL;
00182 
00183   ui_out_redirect (current_uiout, NULL);
00184 }
00185 
00186 /* This is a helper for the `set logging' command.  */
00187 static void
00188 handle_redirections (int from_tty)
00189 {
00190   struct cleanup *cleanups;
00191   struct ui_file *output;
00192   struct ui_file *no_redirect_file = NULL;
00193 
00194   if (saved_filename != NULL)
00195     {
00196       fprintf_unfiltered (gdb_stdout, "Already logging to %s.\n",
00197                           saved_filename);
00198       return;
00199     }
00200 
00201   output = gdb_fopen (logging_filename, logging_overwrite ? "w" : "a");
00202   if (output == NULL)
00203     perror_with_name (_("set logging"));
00204   cleanups = make_cleanup_ui_file_delete (output);
00205 
00206   /* Redirects everything to gdb_stdout while this is running.  */
00207   if (!logging_redirect)
00208     {
00209       no_redirect_file = output;
00210 
00211       output = tee_file_new (gdb_stdout, 0, no_redirect_file, 0);
00212       if (output == NULL)
00213         perror_with_name (_("set logging"));
00214       make_cleanup_ui_file_delete (output);
00215       if (from_tty)
00216         fprintf_unfiltered (gdb_stdout, "Copying output to %s.\n",
00217                             logging_filename);
00218       logging_no_redirect_file = no_redirect_file;
00219     }
00220   else
00221     {
00222       gdb_assert (logging_no_redirect_file == NULL);
00223 
00224       if (from_tty)
00225         fprintf_unfiltered (gdb_stdout, "Redirecting output to %s.\n",
00226                             logging_filename);
00227     }
00228 
00229   discard_cleanups (cleanups);
00230 
00231   saved_filename = xstrdup (logging_filename);
00232   saved_output.out = gdb_stdout;
00233   saved_output.err = gdb_stderr;
00234   saved_output.log = gdb_stdlog;
00235   saved_output.targ = gdb_stdtarg;
00236   saved_output.targerr = gdb_stdtargerr;
00237 
00238   /* Let the interpreter do anything it needs.  */
00239   if (current_interp_set_logging (1, output, no_redirect_file) == 0)
00240     {
00241       gdb_stdout = output;
00242       gdb_stdlog = output;
00243       gdb_stderr = output;
00244       gdb_stdtarg = output;
00245       gdb_stdtargerr = output;
00246     }
00247 
00248   /* Don't do the redirect for MI, it confuses MI's ui-out scheme.  */
00249   if (!ui_out_is_mi_like_p (current_uiout))
00250     {
00251       if (ui_out_redirect (current_uiout, output) < 0)
00252         warning (_("Current output protocol does not support redirection"));
00253     }
00254 }
00255 
00256 static void
00257 set_logging_on (char *args, int from_tty)
00258 {
00259   char *rest = args;
00260 
00261   if (rest && *rest)
00262     {
00263       xfree (logging_filename);
00264       logging_filename = xstrdup (rest);
00265     }
00266   handle_redirections (from_tty);
00267 }
00268 
00269 static void 
00270 set_logging_off (char *args, int from_tty)
00271 {
00272   if (saved_filename == NULL)
00273     return;
00274 
00275   pop_output_files ();
00276   if (from_tty)
00277     fprintf_unfiltered (gdb_stdout, "Done logging to %s.\n", saved_filename);
00278   xfree (saved_filename);
00279   saved_filename = NULL;
00280 }
00281 
00282 static void
00283 set_logging_command (char *args, int from_tty)
00284 {
00285   printf_unfiltered (_("\"set logging\" lets you log output to a file.\n"
00286                        "Usage: set logging on [FILENAME]\n"
00287                        "       set logging off\n"
00288                        "       set logging file FILENAME\n"
00289                        "       set logging overwrite [on|off]\n"
00290                        "       set logging redirect [on|off]\n"));
00291 }
00292 
00293 static void
00294 show_logging_command (char *args, int from_tty)
00295 {
00296   if (saved_filename)
00297     printf_unfiltered (_("Currently logging to \"%s\".\n"), saved_filename);
00298   if (saved_filename == NULL
00299       || strcmp (logging_filename, saved_filename) != 0)
00300     printf_unfiltered (_("Future logs will be written to %s.\n"),
00301                        logging_filename);
00302 
00303   if (logging_overwrite)
00304     printf_unfiltered (_("Logs will overwrite the log file.\n"));
00305   else
00306     printf_unfiltered (_("Logs will be appended to the log file.\n"));
00307 
00308   if (saved_filename)
00309     {
00310       if (logging_redirect)
00311         printf_unfiltered (_("Output is being sent only to the log file.\n"));
00312       else
00313         printf_unfiltered (_("Output is being logged and displayed.\n"));
00314     }
00315   else
00316     {
00317       if (logging_redirect)
00318         printf_unfiltered (_("Output will be sent only to the log file.\n"));
00319       else
00320         printf_unfiltered (_("Output will be logged and displayed.\n"));
00321     }
00322 }
00323 
00324 /* Provide a prototype to silence -Wmissing-prototypes.  */
00325 extern initialize_file_ftype _initialize_cli_logging;
00326 
00327 void
00328 _initialize_cli_logging (void)
00329 {
00330   static struct cmd_list_element *set_logging_cmdlist, *show_logging_cmdlist;
00331 
00332   add_prefix_cmd ("logging", class_support, set_logging_command,
00333                   _("Set logging options"), &set_logging_cmdlist,
00334                   "set logging ", 0, &setlist);
00335   add_prefix_cmd ("logging", class_support, show_logging_command,
00336                   _("Show logging options"), &show_logging_cmdlist,
00337                   "show logging ", 0, &showlist);
00338   add_setshow_boolean_cmd ("overwrite", class_support, &logging_overwrite, _("\
00339 Set whether logging overwrites or appends to the log file."), _("\
00340 Show whether logging overwrites or appends to the log file."), _("\
00341 If set, logging overrides the log file."),
00342                            set_logging_overwrite,
00343                            show_logging_overwrite,
00344                            &set_logging_cmdlist, &show_logging_cmdlist);
00345   add_setshow_boolean_cmd ("redirect", class_support, &logging_redirect, _("\
00346 Set the logging output mode."), _("\
00347 Show the logging output mode."), _("\
00348 If redirect is off, output will go to both the screen and the log file.\n\
00349 If redirect is on, output will go only to the log file."),
00350                            set_logging_redirect,
00351                            show_logging_redirect,
00352                            &set_logging_cmdlist, &show_logging_cmdlist);
00353   add_setshow_filename_cmd ("file", class_support, &logging_filename, _("\
00354 Set the current logfile."), _("\
00355 Show the current logfile."), _("\
00356 The logfile is used when directing GDB's output."),
00357                             NULL,
00358                             show_logging_filename,
00359                             &set_logging_cmdlist, &show_logging_cmdlist);
00360   add_cmd ("on", class_support, set_logging_on,
00361            _("Enable logging."), &set_logging_cmdlist);
00362   add_cmd ("off", class_support, set_logging_off,
00363            _("Disable logging."), &set_logging_cmdlist);
00364 
00365   logging_filename = xstrdup ("gdb.txt");
00366 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines