Commit | Line | Data |
---|---|---|
021e7609 AC |
1 | /* TUI Interpreter definitions for GDB, the GNU debugger. |
2 | ||
42a4f53d | 3 | Copyright (C) 2003-2019 Free Software Foundation, Inc. |
021e7609 AC |
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 | |
a9762ec7 | 9 | the Free Software Foundation; either version 3 of the License, or |
021e7609 AC |
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 | |
a9762ec7 | 18 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
021e7609 AC |
19 | |
20 | #include "defs.h" | |
3c216924 | 21 | #include "cli/cli-interp.h" |
021e7609 AC |
22 | #include "interps.h" |
23 | #include "top.h" | |
24 | #include "event-top.h" | |
25 | #include "event-loop.h" | |
26 | #include "ui-out.h" | |
95cd630e | 27 | #include "cli-out.h" |
d7b2e967 | 28 | #include "tui/tui-data.h" |
d7b2e967 | 29 | #include "tui/tui-win.h" |
021e7609 | 30 | #include "tui/tui.h" |
d7b2e967 | 31 | #include "tui/tui-io.h" |
fd664c91 | 32 | #include "infrun.h" |
76727919 | 33 | #include "observable.h" |
eaae60fd | 34 | #include "gdbthread.h" |
00431a78 | 35 | #include "inferior.h" |
b0be6c91 | 36 | #include "main.h" |
fd664c91 | 37 | |
1cc6d956 MS |
38 | /* Set to 1 when the TUI mode must be activated when we first start |
39 | gdb. */ | |
63858210 SC |
40 | static int tui_start_enabled = 0; |
41 | ||
d6f9b0fb PA |
42 | class tui_interp final : public cli_interp_base |
43 | { | |
44 | public: | |
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 | ||
73ab01a0 PA |
56 | /* Returns the INTERP if the INTERP is a TUI, and returns NULL |
57 | otherwise. */ | |
58 | ||
d6f9b0fb | 59 | static tui_interp * |
73ab01a0 PA |
60 | as_tui_interp (struct interp *interp) |
61 | { | |
716b8bc5 | 62 | return dynamic_cast<tui_interp *> (interp); |
73ab01a0 | 63 | } |
fd664c91 | 64 | |
021e7609 AC |
65 | /* Cleanup the tui before exiting. */ |
66 | ||
67 | static void | |
68 | tui_exit (void) | |
69 | { | |
1cc6d956 MS |
70 | /* Disable the tui. Curses mode is left leaving the screen in a |
71 | clean state (see endwin()). */ | |
021e7609 AC |
72 | tui_disable (); |
73 | } | |
74 | ||
fd664c91 PA |
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 | ||
243a9253 PA |
79 | /* Observer for the normal_stop notification. */ |
80 | ||
81 | static void | |
82 | tui_on_normal_stop (struct bpstats *bs, int print_frame) | |
83 | { | |
eaae60fd PA |
84 | if (!print_frame) |
85 | return; | |
86 | ||
0e454242 | 87 | SWITCH_THRU_ALL_UIS () |
243a9253 | 88 | { |
eaae60fd PA |
89 | struct interp *interp = top_level_interpreter (); |
90 | struct interp *tui = as_tui_interp (interp); | |
91 | struct thread_info *thread; | |
73ab01a0 PA |
92 | |
93 | if (tui == NULL) | |
94 | continue; | |
95 | ||
eaae60fd PA |
96 | thread = inferior_thread (); |
97 | if (should_print_stop_to_console (interp, thread)) | |
d6f9b0fb | 98 | print_stop_event (tui->interp_ui_out ()); |
243a9253 PA |
99 | } |
100 | } | |
101 | ||
fd664c91 PA |
102 | /* Observer for the signal_received notification. */ |
103 | ||
104 | static void | |
105 | tui_on_signal_received (enum gdb_signal siggnal) | |
106 | { | |
0e454242 | 107 | SWITCH_THRU_ALL_UIS () |
73ab01a0 PA |
108 | { |
109 | struct interp *tui = as_tui_interp (top_level_interpreter ()); | |
110 | ||
111 | if (tui == NULL) | |
112 | continue; | |
113 | ||
d6f9b0fb | 114 | print_signal_received_reason (tui->interp_ui_out (), siggnal); |
73ab01a0 | 115 | } |
fd664c91 PA |
116 | } |
117 | ||
118 | /* Observer for the end_stepping_range notification. */ | |
119 | ||
120 | static void | |
121 | tui_on_end_stepping_range (void) | |
122 | { | |
0e454242 | 123 | SWITCH_THRU_ALL_UIS () |
73ab01a0 PA |
124 | { |
125 | struct interp *tui = as_tui_interp (top_level_interpreter ()); | |
126 | ||
127 | if (tui == NULL) | |
128 | continue; | |
129 | ||
d6f9b0fb | 130 | print_end_stepping_range_reason (tui->interp_ui_out ()); |
73ab01a0 | 131 | } |
fd664c91 PA |
132 | } |
133 | ||
134 | /* Observer for the signal_exited notification. */ | |
135 | ||
136 | static void | |
137 | tui_on_signal_exited (enum gdb_signal siggnal) | |
138 | { | |
0e454242 | 139 | SWITCH_THRU_ALL_UIS () |
73ab01a0 PA |
140 | { |
141 | struct interp *tui = as_tui_interp (top_level_interpreter ()); | |
142 | ||
143 | if (tui == NULL) | |
144 | continue; | |
145 | ||
d6f9b0fb | 146 | print_signal_exited_reason (tui->interp_ui_out (), siggnal); |
73ab01a0 | 147 | } |
fd664c91 PA |
148 | } |
149 | ||
150 | /* Observer for the exited notification. */ | |
151 | ||
152 | static void | |
153 | tui_on_exited (int exitstatus) | |
154 | { | |
0e454242 | 155 | SWITCH_THRU_ALL_UIS () |
73ab01a0 PA |
156 | { |
157 | struct interp *tui = as_tui_interp (top_level_interpreter ()); | |
158 | ||
159 | if (tui == NULL) | |
160 | continue; | |
161 | ||
d6f9b0fb | 162 | print_exited_reason (tui->interp_ui_out (), exitstatus); |
73ab01a0 | 163 | } |
fd664c91 PA |
164 | } |
165 | ||
166 | /* Observer for the no_history notification. */ | |
167 | ||
168 | static void | |
169 | tui_on_no_history (void) | |
170 | { | |
0e454242 | 171 | SWITCH_THRU_ALL_UIS () |
73ab01a0 PA |
172 | { |
173 | struct interp *tui = as_tui_interp (top_level_interpreter ()); | |
174 | ||
175 | if (tui == NULL) | |
176 | continue; | |
177 | ||
d6f9b0fb | 178 | print_no_history_reason (tui->interp_ui_out ()); |
73ab01a0 | 179 | } |
fd664c91 PA |
180 | } |
181 | ||
92bcb5f9 PA |
182 | /* Observer for the sync_execution_done notification. */ |
183 | ||
184 | static void | |
185 | tui_on_sync_execution_done (void) | |
186 | { | |
73ab01a0 PA |
187 | struct interp *tui = as_tui_interp (top_level_interpreter ()); |
188 | ||
189 | if (tui == NULL) | |
190 | return; | |
191 | ||
192 | display_gdb_prompt (NULL); | |
92bcb5f9 PA |
193 | } |
194 | ||
195 | /* Observer for the command_error notification. */ | |
196 | ||
197 | static void | |
198 | tui_on_command_error (void) | |
199 | { | |
73ab01a0 PA |
200 | struct interp *tui = as_tui_interp (top_level_interpreter ()); |
201 | ||
202 | if (tui == NULL) | |
203 | return; | |
204 | ||
205 | display_gdb_prompt (NULL); | |
92bcb5f9 PA |
206 | } |
207 | ||
4034d0ff AT |
208 | /* Observer for the user_selected_context_changed notification. */ |
209 | ||
210 | static void | |
211 | tui_on_user_selected_context_changed (user_selected_what selection) | |
212 | { | |
4034d0ff AT |
213 | /* This event is suppressed. */ |
214 | if (cli_suppress_notification.user_selected_context) | |
215 | return; | |
216 | ||
151bb4a5 | 217 | thread_info *tp = inferior_ptid != null_ptid ? inferior_thread () : NULL; |
4034d0ff | 218 | |
0e454242 | 219 | SWITCH_THRU_ALL_UIS () |
4034d0ff AT |
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) | |
d6f9b0fb | 227 | print_selected_inferior (tui->interp_ui_out ()); |
4034d0ff AT |
228 | |
229 | if (tp != NULL | |
230 | && ((selection & (USER_SELECTED_THREAD | USER_SELECTED_FRAME)))) | |
d6f9b0fb | 231 | print_selected_thread_frame (tui->interp_ui_out (), selection); |
4034d0ff AT |
232 | |
233 | } | |
234 | } | |
235 | ||
021e7609 AC |
236 | /* These implement the TUI interpreter. */ |
237 | ||
d6f9b0fb PA |
238 | void |
239 | tui_interp::init (bool top_level) | |
021e7609 AC |
240 | { |
241 | /* Install exit handler to leave the screen in a good shape. */ | |
242 | atexit (tui_exit); | |
243 | ||
021e7609 | 244 | tui_initialize_io (); |
9612b5ec | 245 | tui_initialize_win (); |
1180b2c8 L |
246 | if (ui_file_isatty (gdb_stdout)) |
247 | tui_initialize_readline (); | |
021e7609 AC |
248 | } |
249 | ||
d6f9b0fb PA |
250 | void |
251 | tui_interp::resume () | |
021e7609 | 252 | { |
3c216924 | 253 | struct ui *ui = current_ui; |
95cd630e DJ |
254 | struct ui_file *stream; |
255 | ||
1cc6d956 MS |
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. */ | |
95cd630e | 259 | |
112e8700 | 260 | stream = tui_old_uiout->set_stream (gdb_stdout); |
95cd630e DJ |
261 | if (stream != gdb_stdout) |
262 | { | |
112e8700 | 263 | tui_old_uiout->set_stream (stream); |
95cd630e DJ |
264 | stream = NULL; |
265 | } | |
266 | ||
3c216924 PA |
267 | gdb_setup_readline (1); |
268 | ||
269 | ui->input_handler = command_line_handler; | |
95cd630e DJ |
270 | |
271 | if (stream != NULL) | |
112e8700 | 272 | tui_old_uiout->set_stream (gdb_stdout); |
95cd630e | 273 | |
63858210 SC |
274 | if (tui_start_enabled) |
275 | tui_enable (); | |
021e7609 AC |
276 | } |
277 | ||
d6f9b0fb PA |
278 | void |
279 | tui_interp::suspend () | |
021e7609 | 280 | { |
63858210 | 281 | tui_start_enabled = tui_active; |
021e7609 | 282 | tui_disable (); |
021e7609 AC |
283 | } |
284 | ||
d6f9b0fb PA |
285 | ui_out * |
286 | tui_interp::interp_ui_out () | |
4801a9a3 PA |
287 | { |
288 | if (tui_active) | |
289 | return tui_out; | |
290 | else | |
291 | return tui_old_uiout; | |
292 | } | |
293 | ||
d6f9b0fb PA |
294 | gdb_exception |
295 | tui_interp::exec (const char *command_str) | |
021e7609 | 296 | { |
e2e0b3e5 | 297 | internal_error (__FILE__, __LINE__, _("tui_exec called")); |
021e7609 AC |
298 | } |
299 | ||
8322445e PA |
300 | |
301 | /* Factory for TUI interpreters. */ | |
302 | ||
303 | static struct interp * | |
304 | tui_interp_factory (const char *name) | |
305 | { | |
d6f9b0fb | 306 | return new tui_interp (name); |
8322445e PA |
307 | } |
308 | ||
021e7609 AC |
309 | void |
310 | _initialize_tui_interp (void) | |
311 | { | |
8322445e PA |
312 | interp_factory_register (INTERP_TUI, tui_interp_factory); |
313 | ||
cc4349ed | 314 | if (interpreter_p && strcmp (interpreter_p, INTERP_TUI) == 0) |
63858210 SC |
315 | tui_start_enabled = 1; |
316 | ||
317 | if (interpreter_p && strcmp (interpreter_p, INTERP_CONSOLE) == 0) | |
318 | { | |
319 | xfree (interpreter_p); | |
cc4349ed | 320 | interpreter_p = xstrdup (INTERP_TUI); |
63858210 | 321 | } |
73ab01a0 PA |
322 | |
323 | /* If changing this, remember to update cli-interp.c as well. */ | |
76727919 TT |
324 | gdb::observers::normal_stop.attach (tui_on_normal_stop); |
325 | gdb::observers::signal_received.attach (tui_on_signal_received); | |
326 | gdb::observers::end_stepping_range.attach (tui_on_end_stepping_range); | |
327 | gdb::observers::signal_exited.attach (tui_on_signal_exited); | |
328 | gdb::observers::exited.attach (tui_on_exited); | |
329 | gdb::observers::no_history.attach (tui_on_no_history); | |
330 | gdb::observers::sync_execution_done.attach (tui_on_sync_execution_done); | |
331 | gdb::observers::command_error.attach (tui_on_command_error); | |
332 | gdb::observers::user_selected_context_changed.attach | |
4034d0ff | 333 | (tui_on_user_selected_context_changed); |
021e7609 | 334 | } |