]>
Commit | Line | Data |
---|---|---|
1 | /* Command-line output logging for GDB, the GNU debugger. | |
2 | ||
3 | Copyright (C) 2003-2025 Free Software Foundation, Inc. | |
4 | ||
5 | This file is part of GDB. | |
6 | ||
7 | This program is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 3 of the License, or | |
10 | (at your option) any later version. | |
11 | ||
12 | This program is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
19 | ||
20 | #include "cli/cli-cmds.h" | |
21 | #include "ui-out.h" | |
22 | #include "interps.h" | |
23 | #include "cli/cli-style.h" | |
24 | #include "cli/cli-decode.h" | |
25 | ||
26 | static std::string saved_filename; | |
27 | ||
28 | static std::string logging_filename = "gdb.txt"; | |
29 | static void | |
30 | show_logging_filename (struct ui_file *file, int from_tty, | |
31 | struct cmd_list_element *c, const char *value) | |
32 | { | |
33 | gdb_printf (file, _("The current logfile is \"%ps\".\n"), | |
34 | styled_string (file_name_style.style (), value)); | |
35 | } | |
36 | ||
37 | static bool logging_overwrite; | |
38 | ||
39 | static void | |
40 | maybe_warn_already_logging () | |
41 | { | |
42 | if (!saved_filename.empty ()) | |
43 | warning (_("Currently logging to %s. Turn the logging off and on to " | |
44 | "make the new setting effective."), saved_filename.c_str ()); | |
45 | } | |
46 | ||
47 | static void | |
48 | set_logging_overwrite (const char *args, | |
49 | int from_tty, struct cmd_list_element *c) | |
50 | { | |
51 | maybe_warn_already_logging (); | |
52 | } | |
53 | ||
54 | static void | |
55 | show_logging_overwrite (struct ui_file *file, int from_tty, | |
56 | struct cmd_list_element *c, const char *value) | |
57 | { | |
58 | if (logging_overwrite) | |
59 | gdb_printf (file, _("on: Logging overwrites the log file.\n")); | |
60 | else | |
61 | gdb_printf (file, _("off: Logging appends to the log file.\n")); | |
62 | } | |
63 | ||
64 | /* Value as configured by the user. */ | |
65 | static bool logging_redirect; | |
66 | static bool debug_redirect; | |
67 | ||
68 | static void | |
69 | set_logging_redirect (const char *args, | |
70 | int from_tty, struct cmd_list_element *c) | |
71 | { | |
72 | maybe_warn_already_logging (); | |
73 | } | |
74 | ||
75 | static void | |
76 | show_logging_redirect (struct ui_file *file, int from_tty, | |
77 | struct cmd_list_element *c, const char *value) | |
78 | { | |
79 | if (logging_redirect) | |
80 | gdb_printf (file, _("on: Output will go only to the log file.\n")); | |
81 | else | |
82 | gdb_printf | |
83 | (file, | |
84 | _("off: Output will go to both the screen and the log file.\n")); | |
85 | } | |
86 | ||
87 | static void | |
88 | show_logging_debug_redirect (struct ui_file *file, int from_tty, | |
89 | struct cmd_list_element *c, const char *value) | |
90 | { | |
91 | if (debug_redirect) | |
92 | gdb_printf (file, _("on: Debug output will go only to the log file.\n")); | |
93 | else | |
94 | gdb_printf | |
95 | (file, | |
96 | _("off: Debug output will go to both the screen and the log file.\n")); | |
97 | } | |
98 | ||
99 | /* If we've pushed output files, close them and pop them. */ | |
100 | static void | |
101 | pop_output_files (void) | |
102 | { | |
103 | current_interp_set_logging (NULL, false, false); | |
104 | ||
105 | /* Stay consistent with handle_redirections. */ | |
106 | if (!current_uiout->is_mi_like_p ()) | |
107 | current_uiout->redirect (NULL); | |
108 | } | |
109 | ||
110 | /* This is a helper for the `set logging' command. */ | |
111 | static void | |
112 | handle_redirections (int from_tty) | |
113 | { | |
114 | if (!saved_filename.empty ()) | |
115 | { | |
116 | gdb_printf ("Already logging to %s.\n", | |
117 | saved_filename.c_str ()); | |
118 | return; | |
119 | } | |
120 | ||
121 | stdio_file_up log (new no_terminal_escape_file ()); | |
122 | if (!log->open (logging_filename.c_str (), logging_overwrite ? "w" : "a")) | |
123 | perror_with_name (_("set logging")); | |
124 | ||
125 | /* Redirects everything to gdb_stdout while this is running. */ | |
126 | if (from_tty) | |
127 | { | |
128 | if (!logging_redirect) | |
129 | gdb_printf ("Copying output to %s.\n", | |
130 | logging_filename.c_str ()); | |
131 | else | |
132 | gdb_printf ("Redirecting output to %s.\n", | |
133 | logging_filename.c_str ()); | |
134 | ||
135 | if (!debug_redirect) | |
136 | gdb_printf ("Copying debug output to %s.\n", | |
137 | logging_filename.c_str ()); | |
138 | else | |
139 | gdb_printf ("Redirecting debug output to %s.\n", | |
140 | logging_filename.c_str ()); | |
141 | } | |
142 | ||
143 | saved_filename = logging_filename; | |
144 | ||
145 | /* Let the interpreter do anything it needs. */ | |
146 | current_interp_set_logging (std::move (log), logging_redirect, | |
147 | debug_redirect); | |
148 | ||
149 | /* Redirect the current ui-out object's output to the log. Use | |
150 | gdb_stdout, not log, since the interpreter may have created a tee | |
151 | that wraps the log. Don't do the redirect for MI, it confuses | |
152 | MI's ui-out scheme. Note that we may get here with MI as current | |
153 | interpreter, but with the current ui_out as a CLI ui_out, with | |
154 | '-interpreter-exec console "set logging on"'. */ | |
155 | if (!current_uiout->is_mi_like_p ()) | |
156 | current_uiout->redirect (gdb_stdout); | |
157 | } | |
158 | ||
159 | static void | |
160 | set_logging_on (const char *args, int from_tty) | |
161 | { | |
162 | const char *rest = args; | |
163 | ||
164 | if (rest && *rest) | |
165 | logging_filename = rest; | |
166 | ||
167 | handle_redirections (from_tty); | |
168 | } | |
169 | ||
170 | static void | |
171 | set_logging_off (const char *args, int from_tty) | |
172 | { | |
173 | if (saved_filename.empty ()) | |
174 | return; | |
175 | ||
176 | pop_output_files (); | |
177 | if (from_tty) | |
178 | gdb_printf ("Done logging to %s.\n", | |
179 | saved_filename.c_str ()); | |
180 | saved_filename.clear (); | |
181 | } | |
182 | ||
183 | static bool logging_enabled; | |
184 | ||
185 | static void | |
186 | set_logging_enabled (const char *args, | |
187 | int from_tty, struct cmd_list_element *c) | |
188 | { | |
189 | if (logging_enabled) | |
190 | set_logging_on (args, from_tty); | |
191 | else | |
192 | set_logging_off (args, from_tty); | |
193 | } | |
194 | ||
195 | static void | |
196 | show_logging_enabled (struct ui_file *file, int from_tty, | |
197 | struct cmd_list_element *c, const char *value) | |
198 | { | |
199 | if (logging_enabled) | |
200 | gdb_printf (file, _("on: Logging is enabled.\n")); | |
201 | else | |
202 | gdb_printf (file, _("off: Logging is disabled.\n")); | |
203 | } | |
204 | ||
205 | INIT_GDB_FILE (cli_logging) | |
206 | { | |
207 | static struct cmd_list_element *set_logging_cmdlist, *show_logging_cmdlist; | |
208 | ||
209 | /* Set/show logging. */ | |
210 | add_setshow_prefix_cmd ("logging", class_support, | |
211 | _("Set logging options."), | |
212 | _("Show logging options."), | |
213 | &set_logging_cmdlist, &show_logging_cmdlist, | |
214 | &setlist, &showlist); | |
215 | ||
216 | /* Set/show logging overwrite. */ | |
217 | add_setshow_boolean_cmd ("overwrite", class_support, &logging_overwrite, _("\ | |
218 | Set whether logging overwrites or appends to the log file."), _("\ | |
219 | Show whether logging overwrites or appends to the log file."), _("\ | |
220 | If set, logging overwrites the log file."), | |
221 | set_logging_overwrite, | |
222 | show_logging_overwrite, | |
223 | &set_logging_cmdlist, &show_logging_cmdlist); | |
224 | ||
225 | /* Set/show logging redirect. */ | |
226 | add_setshow_boolean_cmd ("redirect", class_support, &logging_redirect, _("\ | |
227 | Set the logging output mode."), _("\ | |
228 | Show the logging output mode."), _("\ | |
229 | If redirect is off, output will go to both the screen and the log file.\n\ | |
230 | If redirect is on, output will go only to the log file."), | |
231 | set_logging_redirect, | |
232 | show_logging_redirect, | |
233 | &set_logging_cmdlist, &show_logging_cmdlist); | |
234 | ||
235 | /* Set/show logging debugredirect. */ | |
236 | add_setshow_boolean_cmd ("debugredirect", class_support, | |
237 | &debug_redirect, _("\ | |
238 | Set the logging debug output mode."), _("\ | |
239 | Show the logging debug output mode."), _("\ | |
240 | If debug redirect is off, debug will go to both the screen and the log file.\n\ | |
241 | If debug redirect is on, debug will go only to the log file."), | |
242 | set_logging_redirect, | |
243 | show_logging_debug_redirect, | |
244 | &set_logging_cmdlist, &show_logging_cmdlist); | |
245 | ||
246 | /* Set/show logging file. */ | |
247 | add_setshow_filename_cmd ("file", class_support, &logging_filename, _("\ | |
248 | Set the current logfile."), _("\ | |
249 | Show the current logfile."), _("\ | |
250 | The logfile is used when directing GDB's output."), | |
251 | NULL, | |
252 | show_logging_filename, | |
253 | &set_logging_cmdlist, &show_logging_cmdlist); | |
254 | ||
255 | /* Set/show logging enabled. */ | |
256 | set_show_commands setshow_logging_enabled_cmds | |
257 | = add_setshow_boolean_cmd ("enabled", class_support, &logging_enabled, | |
258 | _("Enable logging."), | |
259 | _("Show whether logging is enabled."), | |
260 | _("When on, enable logging."), | |
261 | set_logging_enabled, | |
262 | show_logging_enabled, | |
263 | &set_logging_cmdlist, &show_logging_cmdlist); | |
264 | ||
265 | /* Set logging on, deprecated alias. */ | |
266 | cmd_list_element *set_logging_on_cmd | |
267 | = add_alias_cmd ("on", setshow_logging_enabled_cmds.set, class_support, | |
268 | false, &set_logging_cmdlist); | |
269 | deprecate_cmd (set_logging_on_cmd, "set logging enabled on"); | |
270 | set_logging_on_cmd->default_args = "on"; | |
271 | ||
272 | /* Set logging off, deprecated alias. */ | |
273 | cmd_list_element *set_logging_off_cmd | |
274 | = add_alias_cmd ("off", setshow_logging_enabled_cmds.set, class_support, | |
275 | false, &set_logging_cmdlist); | |
276 | deprecate_cmd (set_logging_off_cmd, "set logging enabled off"); | |
277 | set_logging_off_cmd->default_args = "off"; | |
278 | } |