Home | History | Annotate | Line # | Download | only in tui
      1 /* TUI display source/assembly window.
      2 
      3    Copyright (C) 1998-2024 Free Software Foundation, Inc.
      4 
      5    Contributed by Hewlett-Packard Company.
      6 
      7    This file is part of GDB.
      8 
      9    This program is free software; you can redistribute it and/or modify
     10    it under the terms of the GNU General Public License as published by
     11    the Free Software Foundation; either version 3 of the License, or
     12    (at your option) any later version.
     13 
     14    This program is distributed in the hope that it will be useful,
     15    but WITHOUT ANY WARRANTY; without even the implied warranty of
     16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17    GNU General Public License for more details.
     18 
     19    You should have received a copy of the GNU General Public License
     20    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     21 
     22 #ifndef TUI_TUI_WINSOURCE_H
     23 #define TUI_TUI_WINSOURCE_H
     24 
     25 #include "tui/tui-data.h"
     26 #include "symtab.h"
     27 
     28 enum tui_line_or_address_kind
     29 {
     30   LOA_LINE,
     31   LOA_ADDRESS
     32 };
     33 
     34 /* Structure describing source line or line address.  */
     35 struct tui_line_or_address
     36 {
     37   enum tui_line_or_address_kind loa;
     38   union
     39     {
     40       int line_no;
     41       CORE_ADDR addr;
     42     } u;
     43 };
     44 
     45 /* Flags to tell what kind of breakpoint is at current line.  */
     46 enum tui_bp_flag
     47 {
     48   TUI_BP_ENABLED = 0x01,
     49   TUI_BP_DISABLED = 0x02,
     50   TUI_BP_HIT = 0x04,
     51   TUI_BP_CONDITIONAL = 0x08,
     52   TUI_BP_HARDWARE = 0x10
     53 };
     54 
     55 DEF_ENUM_FLAGS_TYPE (enum tui_bp_flag, tui_bp_flags);
     56 
     57 /* Position of breakpoint markers in the exec info string.  */
     58 #define TUI_BP_HIT_POS      0
     59 #define TUI_BP_BREAK_POS    1
     60 #define TUI_EXEC_POS        2
     61 #define TUI_EXECINFO_SIZE   3
     62 
     63 /* Elements in the Source/Disassembly Window.  */
     64 struct tui_source_element
     65 {
     66   tui_source_element ()
     67   {
     68     line_or_addr.loa = LOA_LINE;
     69     line_or_addr.u.line_no = 0;
     70   }
     71 
     72   DISABLE_COPY_AND_ASSIGN (tui_source_element);
     73 
     74   tui_source_element (tui_source_element &&other)
     75     : line (std::move (other.line)),
     76       line_or_addr (other.line_or_addr),
     77       is_exec_point (other.is_exec_point),
     78       break_mode (other.break_mode)
     79   {
     80   }
     81 
     82   std::string line;
     83   struct tui_line_or_address line_or_addr;
     84   bool is_exec_point = false;
     85   tui_bp_flags break_mode = 0;
     86 };
     87 
     88 
     89 /* The base class for all source-like windows, namely the source and
     90    disassembly windows.  */
     91 
     92 struct tui_source_window_base : public tui_win_info
     93 {
     94 protected:
     95   tui_source_window_base ();
     96   ~tui_source_window_base ();
     97 
     98   DISABLE_COPY_AND_ASSIGN (tui_source_window_base);
     99 
    100   void do_scroll_horizontal (int num_to_scroll) override;
    101 
    102   /* Erase the content and display STRING.  */
    103   void do_erase_source_content (const char *string);
    104 
    105   void rerender () override;
    106 
    107   virtual bool set_contents (struct gdbarch *gdbarch,
    108 			     const struct symtab_and_line &sal) = 0;
    109 
    110   /* Return the number of extra margin characters needed by this
    111      instance.  */
    112   virtual int extra_margin () const
    113   {
    114     return 0;
    115   }
    116 
    117   /* Display the line number in the window margin.  OFFSET indicates
    118      which line to display; it is 0-based, with 0 meaning the line at
    119      the top of the window.  */
    120   virtual void show_line_number (int offset) const
    121   {
    122   }
    123 
    124   /* Redraw the complete line of a source or disassembly window.  */
    125   void show_source_line (int lineno);
    126 
    127   /* Where to start generating content from.  */
    128   struct tui_line_or_address m_start_line_or_addr;
    129 
    130   /* Architecture associated with code at this location.  */
    131   struct gdbarch *m_gdbarch = nullptr;
    132 
    133   std::vector<tui_source_element> m_content;
    134 
    135   /* Length of longest line to be displayed.  */
    136   int m_max_length;
    137 
    138 public:
    139 
    140   /* Refill the source window's source cache and update it.  If this
    141      is a disassembly window, then just update it.  */
    142   void refill ();
    143 
    144   /* Set the location of the execution point.  */
    145   void set_is_exec_point_at (struct tui_line_or_address l);
    146 
    147   void update_tab_width () override;
    148 
    149   virtual bool location_matches_p (struct bp_location *loc, int line_no) = 0;
    150 
    151   /* Fill in the left margin of the current window with execution indicator
    152      information, e.g. breakpoint indicators, and line numbers.  When
    153      REFRESH_P is true this function will call refresh_window to ensure
    154      updates are written to the screen, otherwise the refresh is skipped,
    155      which will leave the on screen contents out of date.  When passing
    156      false for REFRESH_P you should be planning to call refresh_window
    157      yourself.  */
    158   void update_exec_info (bool refresh_p = true);
    159 
    160   /* Update the window to display the given location.  Does nothing if
    161      the location is already displayed.  */
    162   virtual void maybe_update (const frame_info_ptr &fi, symtab_and_line sal) = 0;
    163 
    164   void update_source_window_as_is  (struct gdbarch *gdbarch,
    165 				    const struct symtab_and_line &sal);
    166   void update_source_window (struct gdbarch *gdbarch,
    167 			     const struct symtab_and_line &sal);
    168 
    169   /* Scan the source window and the breakpoints to update the
    170      break_mode information for each line.  Returns true if something
    171      changed and the execution window must be refreshed.  See
    172      tui_update_all_breakpoint_info for a description of
    173      BEING_DELETED.  */
    174   bool update_breakpoint_info (struct breakpoint *being_deleted,
    175 			       bool current_only);
    176 
    177   /* Erase the source content.  */
    178   virtual void erase_source_content () = 0;
    179 
    180   void refresh_window () override;
    181 
    182   /* Return the start address and gdbarch.  */
    183   virtual void display_start_addr (struct gdbarch **gdbarch_p,
    184 				   CORE_ADDR *addr_p) = 0;
    185 
    186   /* Function to ensure that the source or disassembly window
    187      reflects the input address.  Single window variant of
    188      update_source_windows_with_addr.  */
    189   void update_source_window_with_addr (struct gdbarch *, CORE_ADDR);
    190 
    191 private:
    192 
    193   /* Used for horizontal scroll.  */
    194   int m_horizontal_offset = 0;
    195 
    196   /* Check that the current values of M_HORIZONTAL_OFFSET and M_PAD_OFFSET
    197      make sense given the current M_MAX_LENGTH (content width), WIDTH
    198      (window size), and window margins.  After calling this function
    199      M_HORIZONTAL_OFFSET and M_PAD_OFFSET might have been adjusted to
    200      reduce unnecessary whitespace on the right side of the window.
    201 
    202      If M_PAD_OFFSET is adjusted then this function returns true
    203      indicating that the pad contents need to be reloaded by calling
    204      show_source_content.  If M_PAD_OFFSET is not adjusted then this
    205      function returns false, the window contents might still need
    206      redrawing if M_HORIZONTAL_OFFSET was adjusted, but right now, this
    207      function is only called in contexts where the window is going to be
    208      redrawn anyway.  */
    209   bool validate_scroll_offsets ();
    210 
    211   /* Return the size of the left margin space, this is the space used to
    212      display things like breakpoint markers.  */
    213   int left_margin () const
    214   { return TUI_EXECINFO_SIZE + extra_margin (); }
    215 
    216   /* Return the width of the area that is available for window content.
    217      This is the window width minus the borders and the left margin, which
    218      is used for displaying things like breakpoint markers.  */
    219   int view_width () const
    220   { return width - left_margin () - box_size (); }
    221 
    222   void show_source_content ();
    223 
    224   /* Write STRING to the window M_PAD, but skip the first SKIP printable
    225      characters.  Any escape sequences within the first SKIP characters are
    226      still processed though.  This means if we have this string:
    227 
    228      "\033[31mABCDEFGHIJKLM\033[0m"
    229 
    230      and call this function with a skip value of 3, then we effectively
    231      write this string to M_PAD:
    232 
    233      "\033[31mDEFGHIJKLM\033[0m"
    234 
    235      the initial escape that sets the color will still be applied.  */
    236   void puts_to_pad_with_skip (const char *string, int skip);
    237 
    238   /* Called when the user "set style enabled" setting is changed.  */
    239   void style_changed ();
    240 
    241   /* A token used to register and unregister an observer.  */
    242   gdb::observers::token m_observable;
    243 
    244   /* Pad to hold some, or all, of the window contents.  Content is then
    245      copied from this pad to the screen as the user scrolls horizontally,
    246      this avoids the need to recalculate the screen contents each time the
    247      user does a horizontal scroll.  */
    248   std::unique_ptr<WINDOW, curses_deleter> m_pad;
    249 
    250   /* When M_PAD was allocated, this holds the width that was initially
    251      asked for.  If we ask for a very large pad then the allocation may
    252      fail, and we might instead allocate a narrower pad.  */
    253   int m_pad_requested_width = 0;
    254 
    255   /* If M_PAD is not as wide as the content (so less than M_MAX_LENGTH)
    256      then this value indicates the offset at which the pad contents begin.  */
    257   int m_pad_offset = 0;
    258 };
    259 
    260 
    261 /* A wrapper for a TUI window iterator that only iterates over source
    262    windows.  */
    263 
    264 struct tui_source_window_iterator
    265 {
    266 public:
    267 
    268   typedef std::vector<tui_win_info *>::iterator inner_iterator;
    269 
    270   typedef tui_source_window_iterator self_type;
    271   typedef struct tui_source_window_base *value_type;
    272   typedef struct tui_source_window_base *&reference;
    273   typedef struct tui_source_window_base **pointer;
    274   typedef std::forward_iterator_tag iterator_category;
    275   typedef int difference_type;
    276 
    277   explicit tui_source_window_iterator (const inner_iterator &it,
    278 				       const inner_iterator &end)
    279     : m_iter (it),
    280       m_end (end)
    281   {
    282     advance ();
    283   }
    284 
    285   explicit tui_source_window_iterator (const inner_iterator &it)
    286     : m_iter (it)
    287   {
    288   }
    289 
    290   bool operator!= (const self_type &other) const
    291   {
    292     return m_iter != other.m_iter;
    293   }
    294 
    295   value_type operator* () const
    296   {
    297     return dynamic_cast<tui_source_window_base *> (*m_iter);
    298   }
    299 
    300   self_type &operator++ ()
    301   {
    302     ++m_iter;
    303     advance ();
    304     return *this;
    305   }
    306 
    307 private:
    308 
    309   void advance ()
    310   {
    311     while (m_iter != m_end
    312 	   && dynamic_cast<tui_source_window_base *> (*m_iter) == nullptr)
    313       ++m_iter;
    314   }
    315 
    316   inner_iterator m_iter;
    317   inner_iterator m_end;
    318 };
    319 
    320 /* A range adapter for source windows.  */
    321 
    322 struct tui_source_windows
    323 {
    324   /* Work around Wmaybe-uninitialized warning with g++ 11.0.0, see also
    325      PR gcc/96295.  Note that "tui_source_windows () = default" doesn't work
    326      around the warning.  */
    327   tui_source_windows () {}
    328 
    329   tui_source_window_iterator begin () const
    330   {
    331     return tui_source_window_iterator (tui_windows.begin (),
    332 				       tui_windows.end ());
    333   }
    334 
    335   tui_source_window_iterator end () const
    336   {
    337     return tui_source_window_iterator (tui_windows.end ());
    338   }
    339 };
    340 
    341 /* Update the execution windows to show the active breakpoints.  This
    342    is called whenever a breakpoint is inserted, removed or has its
    343    state changed.  Normally BEING_DELETED is nullptr; if not nullptr,
    344    it indicates a breakpoint that is in the process of being deleted,
    345    and which should therefore be ignored by the update.  This is done
    346    because the relevant observer is notified before the breakpoint is
    347    removed from the list of breakpoints.  */
    348 extern void tui_update_all_breakpoint_info (struct breakpoint *being_deleted);
    349 
    350 /* Function to display the "main" routine.  */
    351 extern void tui_display_main (void);
    352 extern void tui_update_source_windows_with_addr (struct gdbarch *, CORE_ADDR);
    353 extern void tui_update_source_windows_with_line (struct symtab_and_line sal);
    354 
    355 /* Extract some source text from PTR.  Returns a string holding the
    356    desired text.  PTR is updated to point to the start of the next
    357    line.  If LENGTH is non-NULL, then the length of the line is stored
    358    there.  Escape sequences are not counted against the length.
    359    Actually an approximation is used -- each byte of a multi-byte
    360    sequence counts as a character here.  */
    361 
    362 extern std::string tui_copy_source_line (const char **ptr,
    363 					 int *length = nullptr);
    364 
    365 /* Constant definitions. */
    366 #define SCROLL_THRESHOLD 2	/* Threshold for lazy scroll.  */
    367 
    368 #endif /* TUI_TUI_WINSOURCE_H */
    369