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