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