Home | History | Annotate | Line # | Download | only in tui
      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