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: 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 279 tui_interp::suspend () 280 { 281 tui_start_enabled = tui_active; 282 tui_disable (); 283 } 284 285 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 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 * 304 tui_interp_factory (const char *name) 305 { 306 return new tui_interp (name); 307 } 308 309 void _initialize_tui_interp (); 310 void 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