xref: /netbsd/external/gpl3/gdb/dist/gdb/tui/tui-interp.c (revision 1424dfb3)
1 /* TUI Interpreter definitions for GDB, the GNU debugger.
2 
3    Copyright (C) 2003-2020 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/cli-interp.h"
22 #include "interps.h"
23 #include "top.h"
24 #include "event-top.h"
25 #include "gdbsupport/event-loop.h"
26 #include "ui-out.h"
27 #include "cli-out.h"
28 #include "tui/tui-data.h"
29 #include "tui/tui-win.h"
30 #include "tui/tui.h"
31 #include "tui/tui-io.h"
32 #include "infrun.h"
33 #include "observable.h"
34 #include "gdbthread.h"
35 #include "inferior.h"
36 #include "main.h"
37 
38 /* Set to true when the TUI mode must be activated when we first start
39    gdb.  */
40 static bool tui_start_enabled = false;
41 
42 class tui_interp final : public cli_interp_base
43 {
44 public:
tui_interp(const char * name)45   explicit tui_interp (const char *name)
46     : cli_interp_base (name)
47   {}
48 
49   void init (bool top_level) override;
50   void resume () override;
51   void suspend () override;
52   gdb_exception exec (const char *command_str) override;
53   ui_out *interp_ui_out () override;
54 };
55 
56 /* Returns the INTERP if the INTERP is a TUI, and returns NULL
57    otherwise.  */
58 
59 static tui_interp *
as_tui_interp(struct interp * interp)60 as_tui_interp (struct interp *interp)
61 {
62   return dynamic_cast<tui_interp *> (interp);
63 }
64 
65 /* Cleanup the tui before exiting.  */
66 
67 static void
tui_exit(void)68 tui_exit (void)
69 {
70   /* Disable the tui.  Curses mode is left leaving the screen in a
71      clean state (see endwin()).  */
72   tui_disable ();
73 }
74 
75 /* Observers for several run control events.  If the interpreter is
76    quiet (i.e., another interpreter is being run with
77    interpreter-exec), print nothing.  */
78 
79 /* Observer for the normal_stop notification.  */
80 
81 static void
tui_on_normal_stop(struct bpstats * bs,int print_frame)82 tui_on_normal_stop (struct bpstats *bs, int print_frame)
83 {
84   if (!print_frame)
85     return;
86 
87   SWITCH_THRU_ALL_UIS ()
88     {
89       struct interp *interp = top_level_interpreter ();
90       struct interp *tui = as_tui_interp (interp);
91       struct thread_info *thread;
92 
93       if (tui == NULL)
94 	continue;
95 
96       thread = inferior_thread ();
97       if (should_print_stop_to_console (interp, thread))
98 	print_stop_event (tui->interp_ui_out ());
99     }
100 }
101 
102 /* Observer for the signal_received notification.  */
103 
104 static void
tui_on_signal_received(enum gdb_signal siggnal)105 tui_on_signal_received (enum gdb_signal siggnal)
106 {
107   SWITCH_THRU_ALL_UIS ()
108     {
109       struct interp *tui = as_tui_interp (top_level_interpreter ());
110 
111       if (tui == NULL)
112 	continue;
113 
114       print_signal_received_reason (tui->interp_ui_out (), siggnal);
115     }
116 }
117 
118 /* Observer for the end_stepping_range notification.  */
119 
120 static void
tui_on_end_stepping_range(void)121 tui_on_end_stepping_range (void)
122 {
123   SWITCH_THRU_ALL_UIS ()
124     {
125       struct interp *tui = as_tui_interp (top_level_interpreter ());
126 
127       if (tui == NULL)
128 	continue;
129 
130       print_end_stepping_range_reason (tui->interp_ui_out ());
131     }
132 }
133 
134 /* Observer for the signal_exited notification.  */
135 
136 static void
tui_on_signal_exited(enum gdb_signal siggnal)137 tui_on_signal_exited (enum gdb_signal siggnal)
138 {
139   SWITCH_THRU_ALL_UIS ()
140     {
141       struct interp *tui = as_tui_interp (top_level_interpreter ());
142 
143       if (tui == NULL)
144 	continue;
145 
146       print_signal_exited_reason (tui->interp_ui_out (), siggnal);
147     }
148 }
149 
150 /* Observer for the exited notification.  */
151 
152 static void
tui_on_exited(int exitstatus)153 tui_on_exited (int exitstatus)
154 {
155   SWITCH_THRU_ALL_UIS ()
156     {
157       struct interp *tui = as_tui_interp (top_level_interpreter ());
158 
159       if (tui == NULL)
160 	continue;
161 
162       print_exited_reason (tui->interp_ui_out (), exitstatus);
163     }
164 }
165 
166 /* Observer for the no_history notification.  */
167 
168 static void
tui_on_no_history(void)169 tui_on_no_history (void)
170 {
171   SWITCH_THRU_ALL_UIS ()
172     {
173       struct interp *tui = as_tui_interp (top_level_interpreter ());
174 
175       if (tui == NULL)
176 	continue;
177 
178       print_no_history_reason (tui->interp_ui_out ());
179     }
180 }
181 
182 /* Observer for the sync_execution_done notification.  */
183 
184 static void
tui_on_sync_execution_done(void)185 tui_on_sync_execution_done (void)
186 {
187   struct interp *tui = as_tui_interp (top_level_interpreter ());
188 
189   if (tui == NULL)
190     return;
191 
192   display_gdb_prompt (NULL);
193 }
194 
195 /* Observer for the command_error notification.  */
196 
197 static void
tui_on_command_error(void)198 tui_on_command_error (void)
199 {
200   struct interp *tui = as_tui_interp (top_level_interpreter ());
201 
202   if (tui == NULL)
203     return;
204 
205   display_gdb_prompt (NULL);
206 }
207 
208 /* Observer for the user_selected_context_changed notification.  */
209 
210 static void
tui_on_user_selected_context_changed(user_selected_what selection)211 tui_on_user_selected_context_changed (user_selected_what selection)
212 {
213   /* This event is suppressed.  */
214   if (cli_suppress_notification.user_selected_context)
215     return;
216 
217   thread_info *tp = inferior_ptid != null_ptid ? inferior_thread () : NULL;
218 
219   SWITCH_THRU_ALL_UIS ()
220     {
221       struct interp *tui = as_tui_interp (top_level_interpreter ());
222 
223       if (tui == NULL)
224 	continue;
225 
226       if (selection & USER_SELECTED_INFERIOR)
227 	print_selected_inferior (tui->interp_ui_out ());
228 
229       if (tp != NULL
230 	  && ((selection & (USER_SELECTED_THREAD | USER_SELECTED_FRAME))))
231 	print_selected_thread_frame (tui->interp_ui_out (), selection);
232 
233     }
234 }
235 
236 /* These implement the TUI interpreter.  */
237 
238 void
init(bool top_level)239 tui_interp::init (bool top_level)
240 {
241   /* Install exit handler to leave the screen in a good shape.  */
242   atexit (tui_exit);
243 
244   tui_initialize_io ();
245   tui_initialize_win ();
246   if (gdb_stdout->isatty ())
247     tui_ensure_readline_initialized ();
248 }
249 
250 void
resume()251 tui_interp::resume ()
252 {
253   struct ui *ui = current_ui;
254   struct ui_file *stream;
255 
256   /* gdb_setup_readline will change gdb_stdout.  If the TUI was
257      previously writing to gdb_stdout, then set it to the new
258      gdb_stdout afterwards.  */
259 
260   stream = tui_old_uiout->set_stream (gdb_stdout);
261   if (stream != gdb_stdout)
262     {
263       tui_old_uiout->set_stream (stream);
264       stream = NULL;
265     }
266 
267   gdb_setup_readline (1);
268 
269   ui->input_handler = command_line_handler;
270 
271   if (stream != NULL)
272     tui_old_uiout->set_stream (gdb_stdout);
273 
274   if (tui_start_enabled)
275     tui_enable ();
276 }
277 
278 void
suspend()279 tui_interp::suspend ()
280 {
281   tui_start_enabled = tui_active;
282   tui_disable ();
283 }
284 
285 ui_out *
interp_ui_out()286 tui_interp::interp_ui_out ()
287 {
288   if (tui_active)
289     return tui_out;
290   else
291     return tui_old_uiout;
292 }
293 
294 gdb_exception
exec(const char * command_str)295 tui_interp::exec (const char *command_str)
296 {
297   internal_error (__FILE__, __LINE__, _("tui_exec called"));
298 }
299 
300 
301 /* Factory for TUI interpreters.  */
302 
303 static struct interp *
tui_interp_factory(const char * name)304 tui_interp_factory (const char *name)
305 {
306   return new tui_interp (name);
307 }
308 
309 void _initialize_tui_interp ();
310 void
_initialize_tui_interp()311 _initialize_tui_interp ()
312 {
313   interp_factory_register (INTERP_TUI, tui_interp_factory);
314 
315   if (interpreter_p && strcmp (interpreter_p, INTERP_TUI) == 0)
316     tui_start_enabled = true;
317 
318   if (interpreter_p && strcmp (interpreter_p, INTERP_CONSOLE) == 0)
319     {
320       xfree (interpreter_p);
321       interpreter_p = xstrdup (INTERP_TUI);
322     }
323 
324   /* If changing this, remember to update cli-interp.c as well.  */
325   gdb::observers::normal_stop.attach (tui_on_normal_stop);
326   gdb::observers::signal_received.attach (tui_on_signal_received);
327   gdb::observers::end_stepping_range.attach (tui_on_end_stepping_range);
328   gdb::observers::signal_exited.attach (tui_on_signal_exited);
329   gdb::observers::exited.attach (tui_on_exited);
330   gdb::observers::no_history.attach (tui_on_no_history);
331   gdb::observers::sync_execution_done.attach (tui_on_sync_execution_done);
332   gdb::observers::command_error.attach (tui_on_command_error);
333   gdb::observers::user_selected_context_changed.attach
334     (tui_on_user_selected_context_changed);
335 }
336