1 /* GDB hooks for TUI. 2 3 Copyright (C) 2001-2024 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 "symtab.h" 21 #include "inferior.h" 22 #include "command.h" 23 #include "bfd.h" 24 #include "symfile.h" 25 #include "objfiles.h" 26 #include "target.h" 27 #include "gdbcore.h" 28 #include "gdbsupport/event-loop.h" 29 #include "event-top.h" 30 #include "frame.h" 31 #include "breakpoint.h" 32 #include "ui-out.h" 33 #include "top.h" 34 #include "observable.h" 35 #include "source.h" 36 #include <unistd.h> 37 #include <fcntl.h> 38 39 #include "tui/tui.h" 40 #include "tui/tui-hooks.h" 41 #include "tui/tui-data.h" 42 #include "tui/tui-layout.h" 43 #include "tui/tui-io.h" 44 #include "tui/tui-regs.h" 45 #include "tui/tui-win.h" 46 #include "tui/tui-status.h" 47 #include "tui/tui-winsource.h" 48 49 #include "gdb_curses.h" 50 51 static void 52 tui_new_objfile_hook (struct objfile* objfile) 53 { 54 if (tui_active) 55 tui_display_main (); 56 } 57 58 /* Observer for the register_changed notification. */ 59 60 static void 61 tui_register_changed (const frame_info_ptr &frame, int regno) 62 { 63 frame_info_ptr fi; 64 65 if (!tui_is_window_visible (DATA_WIN)) 66 return; 67 68 /* The frame of the register that was changed may differ from the selected 69 frame, but we only want to show the register values of the selected frame. 70 And even if the frames differ a register change made in one can still show 71 up in the other. So we always use the selected frame here, and ignore 72 FRAME. */ 73 fi = get_selected_frame (NULL); 74 TUI_DATA_WIN->check_register_values (fi); 75 } 76 77 /* Breakpoint creation hook. 78 Update the screen to show the new breakpoint. */ 79 static void 80 tui_event_create_breakpoint (struct breakpoint *b) 81 { 82 tui_update_all_breakpoint_info (nullptr); 83 } 84 85 /* Breakpoint deletion hook. 86 Refresh the screen to update the breakpoint marks. */ 87 static void 88 tui_event_delete_breakpoint (struct breakpoint *b) 89 { 90 tui_update_all_breakpoint_info (b); 91 } 92 93 static void 94 tui_event_modify_breakpoint (struct breakpoint *b) 95 { 96 tui_update_all_breakpoint_info (nullptr); 97 } 98 99 /* This is set to true if the next window refresh should come from the 100 current stack frame. */ 101 102 static bool from_stack; 103 104 /* This is set to true if the next window refresh should come from the 105 current source symtab. */ 106 107 static bool from_source_symtab; 108 109 /* Refresh TUI's frame and register information. This is a hook intended to be 110 used to update the screen after potential frame and register changes. */ 111 112 static void 113 tui_refresh_frame_and_register_information () 114 { 115 if (!from_stack && !from_source_symtab) 116 return; 117 118 target_terminal::scoped_restore_terminal_state term_state; 119 target_terminal::ours_for_output (); 120 121 if (from_stack) 122 { 123 frame_info_ptr fi; 124 if (has_stack_frames ()) 125 { 126 fi = get_selected_frame (NULL); 127 128 /* Display the frame position (even if there is no symbols or 129 the PC is not known). */ 130 tui_show_frame_info (fi); 131 } 132 133 /* Refresh the register window if it's visible. */ 134 if (tui_is_window_visible (DATA_WIN)) 135 TUI_DATA_WIN->check_register_values (fi); 136 } 137 else 138 { 139 /* Make sure that the source window is displayed. */ 140 tui_add_win_to_layout (SRC_WIN); 141 142 struct symtab_and_line sal = get_current_source_symtab_and_line (); 143 tui_update_source_windows_with_line (sal); 144 } 145 } 146 147 /* Dummy callback for deprecated_print_frame_info_listing_hook which is called 148 from print_frame_info. */ 149 150 static void 151 tui_dummy_print_frame_info_listing_hook (struct symtab *s, 152 int line, 153 int stopline, 154 int noerror) 155 { 156 } 157 158 /* Perform all necessary cleanups regarding our module's inferior data 159 that is required after the inferior INF just exited. */ 160 161 static void 162 tui_inferior_exit (struct inferior *inf) 163 { 164 /* Leave the SingleKey mode to make sure the gdb prompt is visible. */ 165 tui_set_key_mode (TUI_COMMAND_MODE); 166 tui_show_frame_info (0); 167 tui_display_main (); 168 from_stack = true; 169 } 170 171 /* Observer for the before_prompt notification. */ 172 173 static void 174 tui_before_prompt (const char *current_gdb_prompt) 175 { 176 tui_refresh_frame_and_register_information (); 177 from_stack = false; 178 from_source_symtab = false; 179 } 180 181 /* Observer for the normal_stop notification. */ 182 183 static void 184 tui_normal_stop (struct bpstat *bs, int print_frame) 185 { 186 from_stack = true; 187 } 188 189 /* Observer for user_selected_context_changed. */ 190 191 static void 192 tui_context_changed (user_selected_what ignore) 193 { 194 from_stack = true; 195 } 196 197 /* Observer for current_source_symtab_and_line_changed. */ 198 199 static void 200 tui_symtab_changed () 201 { 202 from_source_symtab = true; 203 } 204 205 /* Token associated with observers registered while TUI hooks are 206 installed. */ 207 static const gdb::observers::token tui_observers_token {}; 208 209 /* Attach or detach a single observer, according to ATTACH. */ 210 211 template<typename T> 212 static void 213 attach_or_detach (T &observable, typename T::func_type func, bool attach) 214 { 215 if (attach) 216 observable.attach (func, tui_observers_token, "tui-hooks"); 217 else 218 observable.detach (tui_observers_token); 219 } 220 221 /* Attach or detach TUI observers, according to ATTACH. */ 222 223 static void 224 tui_attach_detach_observers (bool attach) 225 { 226 attach_or_detach (gdb::observers::breakpoint_created, 227 tui_event_create_breakpoint, attach); 228 attach_or_detach (gdb::observers::breakpoint_deleted, 229 tui_event_delete_breakpoint, attach); 230 attach_or_detach (gdb::observers::breakpoint_modified, 231 tui_event_modify_breakpoint, attach); 232 attach_or_detach (gdb::observers::inferior_exit, 233 tui_inferior_exit, attach); 234 attach_or_detach (gdb::observers::before_prompt, 235 tui_before_prompt, attach); 236 attach_or_detach (gdb::observers::normal_stop, 237 tui_normal_stop, attach); 238 attach_or_detach (gdb::observers::register_changed, 239 tui_register_changed, attach); 240 attach_or_detach (gdb::observers::user_selected_context_changed, 241 tui_context_changed, attach); 242 attach_or_detach (gdb::observers::current_source_symtab_and_line_changed, 243 tui_symtab_changed, attach); 244 } 245 246 /* Install the TUI specific hooks. */ 247 void 248 tui_install_hooks (void) 249 { 250 /* If this hook is not set to something then print_frame_info will 251 assume that the CLI, not the TUI, is active, and will print the frame info 252 for us in such a way that we are not prepared to handle. This hook is 253 otherwise effectively obsolete. */ 254 deprecated_print_frame_info_listing_hook 255 = tui_dummy_print_frame_info_listing_hook; 256 257 /* Install the event hooks. */ 258 tui_attach_detach_observers (true); 259 } 260 261 /* Remove the TUI specific hooks. */ 262 void 263 tui_remove_hooks (void) 264 { 265 deprecated_print_frame_info_listing_hook = 0; 266 267 /* Remove our observers. */ 268 tui_attach_detach_observers (false); 269 } 270 271 void _initialize_tui_hooks (); 272 void 273 _initialize_tui_hooks () 274 { 275 /* Install the permanent hooks. */ 276 gdb::observers::new_objfile.attach (tui_new_objfile_hook, "tui-hooks"); 277 } 278