GDB (API)
|
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 }