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