xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/cli/cli-interp.c (revision 3117ece4fc4a4ca4489ba793710b60b0d26bab6c)
1 /* CLI Definitions for GDB, the GNU debugger.
2 
3    Copyright (C) 2002-2023 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 "defs.h"
21 #include "cli-interp.h"
22 #include "interps.h"
23 #include "event-top.h"
24 #include "ui-out.h"
25 #include "cli-out.h"
26 #include "top.h"		/* for "execute_command" */
27 #include "infrun.h"
28 #include "observable.h"
29 #include "gdbthread.h"
30 #include "thread-fsm.h"
31 #include "inferior.h"
32 
33 cli_interp_base::cli_interp_base (const char *name)
34   : interp (name)
35 {}
36 
37 cli_interp_base::~cli_interp_base ()
38 {}
39 
40 /* The console interpreter.  */
41 
42 class cli_interp final : public cli_interp_base
43 {
44  public:
45   explicit cli_interp (const char *name);
46   ~cli_interp () = default;
47 
48   void init (bool top_level) override;
49   void resume () override;
50   void suspend () override;
51   gdb_exception exec (const char *command_str) override;
52   ui_out *interp_ui_out () override;
53 
54 private:
55 
56   /* The ui_out for the console interpreter.  */
57   std::unique_ptr<cli_ui_out> m_cli_uiout;
58 };
59 
60 cli_interp::cli_interp (const char *name)
61   : cli_interp_base (name),
62     m_cli_uiout (new cli_ui_out (gdb_stdout))
63 {
64 }
65 
66 /* Suppress notification struct.  */
67 struct cli_suppress_notification cli_suppress_notification;
68 
69 /* Returns the INTERP's data cast as cli_interp_base if INTERP is a
70    console-like interpreter, and returns NULL otherwise.  */
71 
72 static cli_interp_base *
73 as_cli_interp_base (interp *interp)
74 {
75   return dynamic_cast<cli_interp_base *> (interp);
76 }
77 
78 /* Longjmp-safe wrapper for "execute_command".  */
79 static struct gdb_exception safe_execute_command (struct ui_out *uiout,
80 						  const char *command,
81 						  int from_tty);
82 
83 /* See cli-interp.h.
84 
85    Breakpoint hits should always be mirrored to a console.  Deciding
86    what to mirror to a console wrt to breakpoints and random stops
87    gets messy real fast.  E.g., say "s" trips on a breakpoint.  We'd
88    clearly want to mirror the event to the console in this case.  But
89    what about more complicated cases like "s&; thread n; s&", and one
90    of those steps spawning a new thread, and that thread hitting a
91    breakpoint?  It's impossible in general to track whether the thread
92    had any relation to the commands that had been executed.  So we
93    just simplify and always mirror breakpoints and random events to
94    all consoles.
95 
96    OTOH, we should print the source line to the console when stepping
97    or other similar commands, iff the step was started by that console
98    (or in MI's case, by a console command), but not if it was started
99    with MI's -exec-step or similar.  */
100 
101 int
102 should_print_stop_to_console (struct interp *console_interp,
103 			      struct thread_info *tp)
104 {
105   if ((bpstat_what (tp->control.stop_bpstat).main_action
106        == BPSTAT_WHAT_STOP_NOISY)
107       || tp->thread_fsm () == nullptr
108       || tp->thread_fsm ()->command_interp == console_interp
109       || !tp->thread_fsm ()->finished_p ())
110     return 1;
111   return 0;
112 }
113 
114 /* Observers for several run control events.  If the interpreter is
115    quiet (i.e., another interpreter is being run with
116    interpreter-exec), print nothing.  These are named "cli_base" as
117    they print to both CLI interpreters and TUI interpreters.  */
118 
119 /* Observer for the normal_stop notification.  */
120 
121 static void
122 cli_base_on_normal_stop (struct bpstat *bs, int print_frame)
123 {
124   if (!print_frame)
125     return;
126 
127   /* This event is suppressed.  */
128   if (cli_suppress_notification.normal_stop)
129     return;
130 
131   SWITCH_THRU_ALL_UIS ()
132     {
133       struct interp *interp = top_level_interpreter ();
134       cli_interp_base *cli = as_cli_interp_base (interp);
135       if (cli == nullptr)
136 	continue;
137 
138       thread_info *thread = inferior_thread ();
139       if (should_print_stop_to_console (interp, thread))
140 	print_stop_event (cli->interp_ui_out ());
141     }
142 }
143 
144 /* Observer for the signal_received notification.  */
145 
146 static void
147 cli_base_on_signal_received (enum gdb_signal siggnal)
148 {
149   SWITCH_THRU_ALL_UIS ()
150     {
151       cli_interp_base *cli = as_cli_interp_base (top_level_interpreter ());
152       if (cli == nullptr)
153 	continue;
154 
155       print_signal_received_reason (cli->interp_ui_out (), siggnal);
156     }
157 }
158 
159 /* Observer for the end_stepping_range notification.  */
160 
161 static void
162 cli_base_on_end_stepping_range ()
163 {
164   SWITCH_THRU_ALL_UIS ()
165     {
166       cli_interp_base *cli = as_cli_interp_base (top_level_interpreter ());
167       if (cli == nullptr)
168 	continue;
169 
170       print_end_stepping_range_reason (cli->interp_ui_out ());
171     }
172 }
173 
174 /* Observer for the signalled notification.  */
175 
176 static void
177 cli_base_on_signal_exited (enum gdb_signal siggnal)
178 {
179   SWITCH_THRU_ALL_UIS ()
180     {
181       cli_interp_base *cli = as_cli_interp_base (top_level_interpreter ());
182       if (cli == nullptr)
183 	continue;
184 
185       print_signal_exited_reason (cli->interp_ui_out (), siggnal);
186     }
187 }
188 
189 /* Observer for the exited notification.  */
190 
191 static void
192 cli_base_on_exited (int exitstatus)
193 {
194   SWITCH_THRU_ALL_UIS ()
195     {
196       cli_interp_base *cli = as_cli_interp_base (top_level_interpreter ());
197       if (cli == nullptr)
198 	continue;
199 
200       print_exited_reason (cli->interp_ui_out (), exitstatus);
201     }
202 }
203 
204 /* Observer for the no_history notification.  */
205 
206 static void
207 cli_base_on_no_history ()
208 {
209   SWITCH_THRU_ALL_UIS ()
210     {
211       cli_interp_base *cli = as_cli_interp_base (top_level_interpreter ());
212       if (cli == nullptr)
213 	continue;
214 
215       print_no_history_reason (cli->interp_ui_out ());
216     }
217 }
218 
219 /* Observer for the sync_execution_done notification.  */
220 
221 static void
222 cli_base_on_sync_execution_done ()
223 {
224   cli_interp_base *cli = as_cli_interp_base (top_level_interpreter ());
225   if (cli == nullptr)
226     return;
227 
228   display_gdb_prompt (NULL);
229 }
230 
231 /* Observer for the command_error notification.  */
232 
233 static void
234 cli_base_on_command_error ()
235 {
236   cli_interp_base *cli = as_cli_interp_base (top_level_interpreter ());
237   if (cli == nullptr)
238     return;
239 
240   display_gdb_prompt (NULL);
241 }
242 
243 /* Observer for the user_selected_context_changed notification.  */
244 
245 static void
246 cli_base_on_user_selected_context_changed (user_selected_what selection)
247 {
248   /* This event is suppressed.  */
249   if (cli_suppress_notification.user_selected_context)
250     return;
251 
252   thread_info *tp = inferior_ptid != null_ptid ? inferior_thread () : nullptr;
253 
254   SWITCH_THRU_ALL_UIS ()
255     {
256       cli_interp_base *cli = as_cli_interp_base (top_level_interpreter ());
257       if (cli == nullptr)
258 	continue;
259 
260       if (selection & USER_SELECTED_INFERIOR)
261 	print_selected_inferior (cli->interp_ui_out ());
262 
263       if (tp != nullptr
264 	  && ((selection & (USER_SELECTED_THREAD | USER_SELECTED_FRAME))))
265 	print_selected_thread_frame (cli->interp_ui_out (), selection);
266     }
267 }
268 
269 /* pre_command_loop implementation.  */
270 
271 void
272 cli_interp_base::pre_command_loop ()
273 {
274   display_gdb_prompt (0);
275 }
276 
277 /* These implement the cli out interpreter: */
278 
279 void
280 cli_interp::init (bool top_level)
281 {
282 }
283 
284 void
285 cli_interp::resume ()
286 {
287   struct ui *ui = current_ui;
288   struct ui_file *stream;
289 
290   /*sync_execution = 1; */
291 
292   /* gdb_setup_readline will change gdb_stdout.  If the CLI was
293      previously writing to gdb_stdout, then set it to the new
294      gdb_stdout afterwards.  */
295 
296   stream = m_cli_uiout->set_stream (gdb_stdout);
297   if (stream != gdb_stdout)
298     {
299       m_cli_uiout->set_stream (stream);
300       stream = NULL;
301     }
302 
303   gdb_setup_readline (1);
304 
305   ui->input_handler = command_line_handler;
306 
307   if (stream != NULL)
308     m_cli_uiout->set_stream (gdb_stdout);
309 }
310 
311 void
312 cli_interp::suspend ()
313 {
314   gdb_disable_readline ();
315 }
316 
317 gdb_exception
318 cli_interp::exec (const char *command_str)
319 {
320   struct ui_file *old_stream;
321   struct gdb_exception result;
322 
323   /* gdb_stdout could change between the time m_cli_uiout was
324      initialized and now.  Since we're probably using a different
325      interpreter which has a new ui_file for gdb_stdout, use that one
326      instead of the default.
327 
328      It is important that it gets reset everytime, since the user
329      could set gdb to use a different interpreter.  */
330   old_stream = m_cli_uiout->set_stream (gdb_stdout);
331   result = safe_execute_command (m_cli_uiout.get (), command_str, 1);
332   m_cli_uiout->set_stream (old_stream);
333   return result;
334 }
335 
336 bool
337 cli_interp_base::supports_command_editing ()
338 {
339   return true;
340 }
341 
342 static struct gdb_exception
343 safe_execute_command (struct ui_out *command_uiout, const char *command,
344 		      int from_tty)
345 {
346   struct gdb_exception e;
347 
348   /* Save and override the global ``struct ui_out'' builder.  */
349   scoped_restore saved_uiout = make_scoped_restore (&current_uiout,
350 						    command_uiout);
351 
352   try
353     {
354       execute_command (command, from_tty);
355     }
356   catch (gdb_exception &exception)
357     {
358       e = std::move (exception);
359     }
360 
361   /* FIXME: cagney/2005-01-13: This shouldn't be needed.  Instead the
362      caller should print the exception.  */
363   exception_print (gdb_stderr, e);
364   return e;
365 }
366 
367 ui_out *
368 cli_interp::interp_ui_out ()
369 {
370   return m_cli_uiout.get ();
371 }
372 
373 /* See cli-interp.h.  */
374 
375 void
376 cli_interp_base::set_logging (ui_file_up logfile, bool logging_redirect,
377 			      bool debug_redirect)
378 {
379   if (logfile != nullptr)
380     {
381       gdb_assert (m_saved_output == nullptr);
382       m_saved_output.reset (new saved_output_files);
383       m_saved_output->out = gdb_stdout;
384       m_saved_output->err = gdb_stderr;
385       m_saved_output->log = gdb_stdlog;
386       m_saved_output->targ = gdb_stdtarg;
387       m_saved_output->targerr = gdb_stdtargerr;
388 
389       ui_file *logfile_p = logfile.get ();
390       m_saved_output->logfile_holder = std::move (logfile);
391 
392       /* The new stdout and stderr only depend on whether logging
393 	 redirection is being done.  */
394       ui_file *new_stdout = logfile_p;
395       ui_file *new_stderr = logfile_p;
396       if (!logging_redirect)
397 	{
398 	  m_saved_output->stdout_holder.reset
399 	    (new tee_file (gdb_stdout, logfile_p));
400 	  new_stdout = m_saved_output->stdout_holder.get ();
401 	  m_saved_output->stderr_holder.reset
402 	    (new tee_file (gdb_stderr, logfile_p));
403 	  new_stderr = m_saved_output->stderr_holder.get ();
404 	}
405 
406       m_saved_output->stdlog_holder.reset
407 	(new timestamped_file (debug_redirect ? logfile_p : new_stderr));
408 
409       gdb_stdout = new_stdout;
410       gdb_stdlog = m_saved_output->stdlog_holder.get ();
411       gdb_stderr = new_stderr;
412       gdb_stdtarg = new_stderr;
413       gdb_stdtargerr = new_stderr;
414     }
415   else
416     {
417       gdb_stdout = m_saved_output->out;
418       gdb_stderr = m_saved_output->err;
419       gdb_stdlog = m_saved_output->log;
420       gdb_stdtarg = m_saved_output->targ;
421       gdb_stdtargerr = m_saved_output->targerr;
422 
423       m_saved_output.reset (nullptr);
424     }
425 }
426 
427 /* Factory for CLI interpreters.  */
428 
429 static struct interp *
430 cli_interp_factory (const char *name)
431 {
432   return new cli_interp (name);
433 }
434 
435 /* Standard gdb initialization hook.  */
436 
437 void _initialize_cli_interp ();
438 void
439 _initialize_cli_interp ()
440 {
441   interp_factory_register (INTERP_CONSOLE, cli_interp_factory);
442 
443   /* Note these all work for both the CLI and TUI interpreters.  */
444   gdb::observers::normal_stop.attach (cli_base_on_normal_stop,
445 				      "cli-interp-base");
446   gdb::observers::end_stepping_range.attach (cli_base_on_end_stepping_range,
447 					     "cli-interp-base");
448   gdb::observers::signal_received.attach (cli_base_on_signal_received,
449 					  "cli-interp-base");
450   gdb::observers::signal_exited.attach (cli_base_on_signal_exited,
451 					"cli-interp-base");
452   gdb::observers::exited.attach (cli_base_on_exited, "cli-interp-base");
453   gdb::observers::no_history.attach (cli_base_on_no_history, "cli-interp-base");
454   gdb::observers::sync_execution_done.attach (cli_base_on_sync_execution_done,
455 					      "cli-interp-base");
456   gdb::observers::command_error.attach (cli_base_on_command_error,
457 					"cli-interp-base");
458   gdb::observers::user_selected_context_changed.attach
459     (cli_base_on_user_selected_context_changed, "cli-interp-base");
460 }
461