Home | History | Annotate | Line # | Download | only in tui
      1   1.1  christos /* TUI display source/assembly window.
      2   1.1  christos 
      3  1.11  christos    Copyright (C) 1998-2024 Free Software Foundation, Inc.
      4   1.1  christos 
      5   1.1  christos    Contributed by Hewlett-Packard Company.
      6   1.1  christos 
      7   1.1  christos    This file is part of GDB.
      8   1.1  christos 
      9   1.1  christos    This program is free software; you can redistribute it and/or modify
     10   1.1  christos    it under the terms of the GNU General Public License as published by
     11   1.1  christos    the Free Software Foundation; either version 3 of the License, or
     12   1.1  christos    (at your option) any later version.
     13   1.1  christos 
     14   1.1  christos    This program is distributed in the hope that it will be useful,
     15   1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     16   1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17   1.1  christos    GNU General Public License for more details.
     18   1.1  christos 
     19   1.1  christos    You should have received a copy of the GNU General Public License
     20   1.1  christos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     21   1.1  christos 
     22  1.12  christos #include "observable.h"
     23   1.1  christos #include "symtab.h"
     24   1.1  christos #include "frame.h"
     25   1.1  christos #include "breakpoint.h"
     26   1.1  christos #include "value.h"
     27   1.1  christos #include "source.h"
     28   1.1  christos #include "objfiles.h"
     29  1.11  christos #include "gdbsupport/gdb-safe-ctype.h"
     30   1.1  christos 
     31   1.1  christos #include "tui/tui.h"
     32   1.1  christos #include "tui/tui-data.h"
     33   1.8  christos #include "tui/tui-io.h"
     34  1.11  christos #include "tui/tui-status.h"
     35   1.1  christos #include "tui/tui-win.h"
     36   1.1  christos #include "tui/tui-winsource.h"
     37   1.1  christos #include "tui/tui-source.h"
     38   1.1  christos #include "tui/tui-disasm.h"
     39  1.10  christos #include "tui/tui-location.h"
     40   1.1  christos #include "gdb_curses.h"
     41   1.1  christos 
     42  1.11  christos /* ncurses returns -1, but BSD segfaults; the code assumes ncurses */
     43  1.11  christos #define tui_getmaxx(w)	((w) ? getmaxx (w) : -1)
     44  1.11  christos #define tui_getmaxy(w)	((w) ? getmaxy (w) : -1)
     45  1.11  christos 
     46   1.1  christos /* Function to display the "main" routine.  */
     47   1.1  christos void
     48   1.9  christos tui_display_main ()
     49   1.1  christos {
     50   1.9  christos   auto adapter = tui_source_windows ();
     51   1.9  christos   if (adapter.begin () != adapter.end ())
     52   1.1  christos     {
     53   1.1  christos       struct gdbarch *gdbarch;
     54   1.1  christos       CORE_ADDR addr;
     55   1.1  christos 
     56   1.1  christos       tui_get_begin_asm_address (&gdbarch, &addr);
     57   1.1  christos       if (addr != (CORE_ADDR) 0)
     58   1.1  christos 	{
     59   1.3  christos 	  struct symtab *s;
     60   1.1  christos 
     61   1.1  christos 	  tui_update_source_windows_with_addr (gdbarch, addr);
     62   1.3  christos 	  s = find_pc_line_symtab (addr);
     63  1.10  christos 	  tui_location.set_location (s);
     64   1.1  christos 	}
     65   1.1  christos     }
     66   1.1  christos }
     67   1.1  christos 
     68   1.9  christos /* See tui-winsource.h.  */
     69   1.1  christos 
     70   1.9  christos std::string
     71  1.10  christos tui_copy_source_line (const char **ptr, int *length)
     72   1.9  christos {
     73   1.9  christos   const char *lineptr = *ptr;
     74   1.9  christos 
     75   1.9  christos   /* Init the line with the line number.  */
     76   1.9  christos   std::string result;
     77   1.9  christos 
     78   1.9  christos   int column = 0;
     79   1.9  christos   char c;
     80   1.9  christos   do
     81   1.9  christos     {
     82   1.9  christos       int skip_bytes;
     83   1.9  christos 
     84   1.9  christos       c = *lineptr;
     85   1.9  christos       if (c == '\033' && skip_ansi_escape (lineptr, &skip_bytes))
     86   1.9  christos 	{
     87   1.9  christos 	  /* We always have to preserve escapes.  */
     88   1.9  christos 	  result.append (lineptr, lineptr + skip_bytes);
     89   1.9  christos 	  lineptr += skip_bytes;
     90   1.9  christos 	  continue;
     91   1.9  christos 	}
     92   1.9  christos       if (c == '\0')
     93   1.9  christos 	break;
     94   1.9  christos 
     95   1.9  christos       ++lineptr;
     96   1.9  christos       ++column;
     97   1.9  christos 
     98   1.9  christos       auto process_tab = [&] ()
     99   1.9  christos 	{
    100   1.9  christos 	  int max_tab_len = tui_tab_width;
    101   1.9  christos 
    102   1.9  christos 	  --column;
    103   1.9  christos 	  for (int j = column % max_tab_len;
    104  1.10  christos 	       j < max_tab_len;
    105   1.9  christos 	       column++, j++)
    106  1.10  christos 	    result.push_back (' ');
    107   1.9  christos 	};
    108   1.9  christos 
    109   1.9  christos       if (c == '\n' || c == '\r' || c == '\0')
    110   1.9  christos 	{
    111   1.9  christos 	  /* Nothing.  */
    112   1.9  christos 	}
    113  1.10  christos       else if (c == '\t')
    114  1.10  christos 	process_tab ();
    115  1.10  christos       else if (ISCNTRL (c))
    116   1.9  christos 	{
    117   1.9  christos 	  result.push_back ('^');
    118   1.9  christos 	  result.push_back (c + 0100);
    119  1.10  christos 	  ++column;
    120   1.9  christos 	}
    121   1.9  christos       else if (c == 0177)
    122   1.9  christos 	{
    123   1.9  christos 	  result.push_back ('^');
    124   1.9  christos 	  result.push_back ('?');
    125  1.10  christos 	  ++column;
    126   1.9  christos 	}
    127   1.9  christos       else
    128   1.9  christos 	result.push_back (c);
    129   1.9  christos     }
    130   1.9  christos   while (c != '\0' && c != '\n' && c != '\r');
    131   1.9  christos 
    132   1.9  christos   if (c == '\r' && *lineptr == '\n')
    133   1.9  christos     ++lineptr;
    134   1.9  christos   *ptr = lineptr;
    135   1.9  christos 
    136  1.10  christos   if (length != nullptr)
    137  1.10  christos     *length = column;
    138  1.10  christos 
    139   1.9  christos   return result;
    140   1.9  christos }
    141   1.9  christos 
    142   1.9  christos void
    143   1.9  christos tui_source_window_base::style_changed ()
    144   1.9  christos {
    145   1.9  christos   if (tui_active && is_visible ())
    146   1.9  christos     refill ();
    147   1.9  christos }
    148   1.1  christos 
    149   1.1  christos /* Function to display source in the source window.  This function
    150   1.1  christos    initializes the horizontal scroll to 0.  */
    151   1.1  christos void
    152   1.9  christos tui_source_window_base::update_source_window
    153   1.9  christos   (struct gdbarch *gdbarch,
    154   1.9  christos    const struct symtab_and_line &sal)
    155   1.1  christos {
    156   1.9  christos   m_horizontal_offset = 0;
    157   1.9  christos   update_source_window_as_is (gdbarch, sal);
    158   1.1  christos }
    159   1.1  christos 
    160   1.1  christos 
    161   1.1  christos /* Function to display source in the source/asm window.  This function
    162   1.1  christos    shows the source as specified by the horizontal offset.  */
    163   1.1  christos void
    164   1.9  christos tui_source_window_base::update_source_window_as_is
    165   1.9  christos   (struct gdbarch *gdbarch,
    166   1.9  christos    const struct symtab_and_line &sal)
    167   1.1  christos {
    168   1.9  christos   bool ret = set_contents (gdbarch, sal);
    169   1.1  christos 
    170   1.9  christos   if (!ret)
    171   1.9  christos     erase_source_content ();
    172   1.1  christos   else
    173   1.1  christos     {
    174  1.11  christos       validate_scroll_offsets ();
    175   1.9  christos       update_breakpoint_info (nullptr, false);
    176  1.11  christos       update_exec_info (false);
    177   1.9  christos       show_source_content ();
    178   1.1  christos     }
    179   1.1  christos }
    180   1.1  christos 
    181   1.1  christos 
    182  1.11  christos /* See tui-winsource.h.  */
    183  1.11  christos void
    184  1.11  christos tui_source_window_base::update_source_window_with_addr (struct gdbarch *gdbarch,
    185  1.11  christos 							CORE_ADDR addr)
    186  1.11  christos {
    187  1.11  christos   struct symtab_and_line sal {};
    188  1.11  christos   if (addr != 0)
    189  1.11  christos     sal = find_pc_line (addr, 0);
    190  1.11  christos 
    191  1.11  christos   update_source_window (gdbarch, sal);
    192  1.11  christos }
    193  1.11  christos 
    194  1.11  christos /* Function to ensure that the source and/or disassembly windows
    195   1.1  christos    reflect the input address.  */
    196   1.1  christos void
    197   1.1  christos tui_update_source_windows_with_addr (struct gdbarch *gdbarch, CORE_ADDR addr)
    198   1.1  christos {
    199   1.9  christos   struct symtab_and_line sal {};
    200   1.1  christos   if (addr != 0)
    201   1.9  christos     sal = find_pc_line (addr, 0);
    202   1.1  christos 
    203   1.9  christos   for (struct tui_source_window_base *win_info : tui_source_windows ())
    204   1.9  christos     win_info->update_source_window (gdbarch, sal);
    205   1.1  christos }
    206   1.1  christos 
    207   1.9  christos /* Function to ensure that the source and/or disassembly windows
    208   1.9  christos    reflect the symtab and line.  */
    209   1.1  christos void
    210   1.9  christos tui_update_source_windows_with_line (struct symtab_and_line sal)
    211   1.1  christos {
    212   1.9  christos   struct gdbarch *gdbarch = nullptr;
    213   1.9  christos   if (sal.symtab != nullptr)
    214   1.9  christos     {
    215   1.9  christos       find_line_pc (sal.symtab, sal.line, &sal.pc);
    216  1.10  christos       gdbarch = sal.symtab->compunit ()->objfile ()->arch ();
    217   1.1  christos     }
    218   1.1  christos 
    219   1.9  christos   for (struct tui_source_window_base *win_info : tui_source_windows ())
    220   1.9  christos     win_info->update_source_window (gdbarch, sal);
    221   1.1  christos }
    222   1.1  christos 
    223   1.1  christos void
    224   1.9  christos tui_source_window_base::do_erase_source_content (const char *str)
    225   1.1  christos {
    226  1.11  christos   m_content.clear ();
    227  1.11  christos   if (handle != nullptr)
    228  1.11  christos     center_string (str);
    229  1.11  christos }
    230  1.11  christos 
    231  1.11  christos /* See tui-winsource.h.  */
    232   1.9  christos 
    233  1.11  christos void
    234  1.11  christos tui_source_window_base::puts_to_pad_with_skip (const char *string, int skip)
    235  1.11  christos {
    236  1.11  christos   gdb_assert (m_pad.get () != nullptr);
    237  1.11  christos   WINDOW *w = m_pad.get ();
    238  1.11  christos 
    239  1.11  christos   while (skip > 0)
    240   1.1  christos     {
    241  1.11  christos       const char *next = strpbrk (string, "\033");
    242  1.11  christos 
    243  1.11  christos       /* Print the plain text prefix.  */
    244  1.11  christos       size_t n_chars = next == nullptr ? strlen (string) : next - string;
    245  1.11  christos       if (n_chars > 0)
    246  1.11  christos 	{
    247  1.11  christos 	  if (skip > 0)
    248  1.11  christos 	    {
    249  1.11  christos 	      if (skip < n_chars)
    250  1.11  christos 		{
    251  1.11  christos 		  string += skip;
    252  1.11  christos 		  n_chars -= skip;
    253  1.11  christos 		  skip = 0;
    254  1.11  christos 		}
    255  1.11  christos 	      else
    256  1.11  christos 		{
    257  1.11  christos 		  skip -= n_chars;
    258  1.11  christos 		  string += n_chars;
    259  1.11  christos 		  n_chars = 0;
    260  1.11  christos 		}
    261  1.11  christos 	    }
    262  1.11  christos 
    263  1.11  christos 	  if (n_chars > 0)
    264  1.11  christos 	    {
    265  1.11  christos 	      std::string copy (string, n_chars);
    266  1.11  christos 	      tui_puts (copy.c_str (), w);
    267  1.11  christos 	    }
    268  1.11  christos 	}
    269  1.11  christos 
    270  1.11  christos       /* We finished.  */
    271  1.11  christos       if (next == nullptr)
    272  1.11  christos 	break;
    273  1.11  christos 
    274  1.11  christos       gdb_assert (*next == '\033');
    275   1.1  christos 
    276  1.11  christos       int n_read;
    277  1.11  christos       if (skip_ansi_escape (next, &n_read))
    278  1.11  christos 	{
    279  1.11  christos 	  std::string copy (next, n_read);
    280  1.11  christos 	  tui_puts (copy.c_str (), w);
    281  1.11  christos 	  next += n_read;
    282  1.11  christos 	}
    283   1.9  christos       else
    284  1.11  christos 	gdb_assert_not_reached ("unhandled escape");
    285   1.1  christos 
    286  1.11  christos       string = next;
    287   1.1  christos     }
    288  1.11  christos 
    289  1.11  christos   if (*string != '\0')
    290  1.11  christos     tui_puts (string, w);
    291   1.1  christos }
    292   1.1  christos 
    293   1.9  christos /* Redraw the complete line of a source or disassembly window.  */
    294   1.1  christos void
    295   1.9  christos tui_source_window_base::show_source_line (int lineno)
    296   1.1  christos {
    297   1.9  christos   struct tui_source_element *line;
    298   1.9  christos 
    299  1.10  christos   line = &m_content[lineno];
    300   1.9  christos   if (line->is_exec_point)
    301  1.10  christos     tui_set_reverse_mode (m_pad.get (), true);
    302   1.9  christos 
    303  1.10  christos   wmove (m_pad.get (), lineno, 0);
    304  1.11  christos   puts_to_pad_with_skip (line->line.c_str (), m_pad_offset);
    305  1.11  christos 
    306   1.9  christos   if (line->is_exec_point)
    307  1.10  christos     tui_set_reverse_mode (m_pad.get (), false);
    308  1.10  christos }
    309  1.10  christos 
    310  1.10  christos /* See tui-winsource.h.  */
    311   1.1  christos 
    312  1.10  christos void
    313  1.10  christos tui_source_window_base::refresh_window ()
    314  1.10  christos {
    315  1.11  christos   TUI_SCOPED_DEBUG_START_END ("window `%s`", name ());
    316  1.11  christos 
    317  1.10  christos   /* tui_win_info::refresh_window would draw the empty background window to
    318  1.10  christos      the screen, potentially creating a flicker.  */
    319  1.10  christos   wnoutrefresh (handle.get ());
    320  1.10  christos 
    321  1.12  christos   if (m_content.empty ())
    322  1.12  christos     return;
    323  1.12  christos 
    324  1.11  christos   int pad_width = tui_getmaxx (m_pad.get ());
    325  1.11  christos   int left_margin = this->left_margin ();
    326  1.11  christos   int view_width = this->view_width ();
    327  1.11  christos   int content_width = m_max_length;
    328  1.11  christos   int pad_x = m_horizontal_offset - m_pad_offset;
    329  1.11  christos 
    330  1.11  christos   tui_debug_printf ("pad_width = %d, left_margin = %d, view_width = %d",
    331  1.11  christos 		    pad_width, left_margin, view_width);
    332  1.11  christos   tui_debug_printf ("content_width = %d, pad_x = %d, m_horizontal_offset = %d",
    333  1.11  christos 		    content_width, pad_x, m_horizontal_offset);
    334  1.11  christos   tui_debug_printf ("m_pad_offset = %d", m_pad_offset);
    335  1.11  christos 
    336  1.11  christos   gdb_assert (m_pad_offset >= 0);
    337  1.11  christos   gdb_assert (m_horizontal_offset + view_width
    338  1.11  christos 	      <= std::max (content_width, view_width));
    339  1.11  christos   gdb_assert (pad_x >= 0);
    340  1.11  christos   gdb_assert (m_horizontal_offset >= 0);
    341  1.11  christos 
    342  1.11  christos   /* This function can be called before the pad has been allocated, this
    343  1.11  christos      should only occur during the initial startup.  In this case the first
    344  1.11  christos      condition in the following asserts will not be true, but the nullptr
    345  1.11  christos      check will.  */
    346  1.11  christos   gdb_assert (pad_width > 0 || m_pad.get () == nullptr);
    347  1.11  christos   gdb_assert (pad_x + view_width <= pad_width || m_pad.get () == nullptr);
    348  1.11  christos 
    349  1.11  christos   int sminrow = y + box_width ();
    350  1.11  christos   int smincol = x + box_width () + left_margin;
    351  1.11  christos   int smaxrow = sminrow + m_content.size () - 1;
    352  1.11  christos   int smaxcol = smincol + view_width - 1;
    353  1.11  christos   if (m_pad.get ())
    354  1.12  christos     pnoutrefresh (m_pad.get (), 0, pad_x, sminrow, smincol, smaxrow, smaxcol);
    355   1.9  christos }
    356   1.9  christos 
    357   1.9  christos void
    358   1.9  christos tui_source_window_base::show_source_content ()
    359   1.9  christos {
    360  1.11  christos   TUI_SCOPED_DEBUG_START_END ("window `%s`", name ());
    361  1.11  christos 
    362   1.9  christos   gdb_assert (!m_content.empty ());
    363   1.1  christos 
    364  1.11  christos   /* The pad should be at least as wide as the window, but ideally, as wide
    365  1.11  christos      as the content, however, for some very wide content this might not be
    366  1.11  christos      possible.  */
    367  1.11  christos   int required_pad_width = std::max (m_max_length, width);
    368  1.11  christos   int required_pad_height = m_content.size ();
    369  1.11  christos 
    370  1.11  christos   /* If the required pad width is wider than the previously requested pad
    371  1.11  christos      width, then we might want to grow the pad.  */
    372  1.11  christos   if (required_pad_width > m_pad_requested_width
    373  1.11  christos       || required_pad_height > tui_getmaxy (m_pad.get ()))
    374  1.11  christos     {
    375  1.11  christos       /* The current pad width.  */
    376  1.11  christos       int pad_width = m_pad == nullptr ? 0 : tui_getmaxx (m_pad.get ());
    377  1.11  christos 
    378  1.11  christos       gdb_assert (pad_width <= m_pad_requested_width);
    379  1.11  christos 
    380  1.11  christos       /* If the current pad width is smaller than the previously requested
    381  1.11  christos 	 pad width, then this means we previously failed to allocate a
    382  1.11  christos 	 bigger pad.  There's no point asking again, so we'll just make so
    383  1.11  christos 	 with the pad we currently have.  */
    384  1.11  christos       if (pad_width == m_pad_requested_width
    385  1.11  christos 	  || required_pad_height > tui_getmaxy (m_pad.get ()))
    386  1.11  christos 	{
    387  1.11  christos 	  pad_width = required_pad_width;
    388  1.10  christos 
    389  1.11  christos 	  do
    390  1.11  christos 	    {
    391  1.11  christos 	      /* Try to allocate a new pad.  */
    392  1.11  christos 	      m_pad.reset (newpad (required_pad_height, pad_width));
    393  1.10  christos 
    394  1.11  christos 	      if (m_pad == nullptr)
    395  1.11  christos 		{
    396  1.11  christos 		  int reduced_width = std::max (pad_width / 2, width);
    397  1.11  christos 		  if (reduced_width == pad_width)
    398  1.11  christos 		    error (_("failed to setup source window"));
    399  1.11  christos 		  pad_width = reduced_width;
    400  1.11  christos 		}
    401  1.11  christos 	    }
    402  1.11  christos 	  while (m_pad == nullptr);
    403  1.11  christos 	}
    404  1.11  christos 
    405  1.11  christos       m_pad_requested_width = required_pad_width;
    406  1.11  christos       tui_debug_printf ("requested width %d, allocated width %d",
    407  1.11  christos 			required_pad_width, tui_getmaxx (m_pad.get ()));
    408  1.11  christos     }
    409  1.11  christos 
    410  1.11  christos   gdb_assert (m_pad != nullptr);
    411  1.10  christos   werase (m_pad.get ());
    412  1.10  christos   for (int lineno = 0; lineno < m_content.size (); lineno++)
    413   1.9  christos     show_source_line (lineno);
    414   1.1  christos 
    415  1.12  christos   /* Calling check_and_display_highlight_if_needed will call
    416  1.12  christos      refresh_window.  */
    417  1.12  christos   check_and_display_highlight_if_needed ();
    418   1.1  christos }
    419   1.1  christos 
    420   1.9  christos tui_source_window_base::tui_source_window_base ()
    421   1.9  christos {
    422   1.9  christos   m_start_line_or_addr.loa = LOA_ADDRESS;
    423   1.9  christos   m_start_line_or_addr.u.addr = 0;
    424   1.9  christos 
    425  1.10  christos   gdb::observers::styling_changed.attach
    426   1.9  christos     (std::bind (&tui_source_window::style_changed, this),
    427  1.10  christos      m_observable, "tui-winsource");
    428   1.9  christos }
    429   1.1  christos 
    430   1.9  christos tui_source_window_base::~tui_source_window_base ()
    431   1.1  christos {
    432  1.10  christos   gdb::observers::styling_changed.detach (m_observable);
    433   1.9  christos }
    434   1.1  christos 
    435   1.9  christos /* See tui-data.h.  */
    436   1.1  christos 
    437   1.9  christos void
    438   1.9  christos tui_source_window_base::update_tab_width ()
    439   1.9  christos {
    440   1.9  christos   werase (handle.get ());
    441   1.9  christos   rerender ();
    442   1.1  christos }
    443   1.1  christos 
    444   1.1  christos void
    445   1.9  christos tui_source_window_base::rerender ()
    446   1.1  christos {
    447  1.11  christos   TUI_SCOPED_DEBUG_START_END ("window `%s`", name ());
    448  1.11  christos 
    449   1.9  christos   if (!m_content.empty ())
    450   1.1  christos     {
    451  1.12  christos       symtab_and_line cursal
    452  1.12  christos 	= get_current_source_symtab_and_line (current_program_space);
    453   1.1  christos 
    454   1.9  christos       if (m_start_line_or_addr.loa == LOA_LINE)
    455   1.9  christos 	cursal.line = m_start_line_or_addr.u.line_no;
    456   1.9  christos       else
    457   1.9  christos 	cursal.pc = m_start_line_or_addr.u.addr;
    458   1.9  christos       update_source_window (m_gdbarch, cursal);
    459   1.9  christos     }
    460   1.9  christos   else if (deprecated_safe_get_selected_frame () != NULL)
    461   1.9  christos     {
    462  1.12  christos       symtab_and_line cursal
    463  1.12  christos 	= get_current_source_symtab_and_line (current_program_space);
    464  1.10  christos       frame_info_ptr frame = deprecated_safe_get_selected_frame ();
    465   1.9  christos       struct gdbarch *gdbarch = get_frame_arch (frame);
    466   1.9  christos 
    467   1.9  christos       struct symtab *s = find_pc_line_symtab (get_frame_pc (frame));
    468  1.12  christos       if (this != tui_src_win ())
    469   1.9  christos 	find_line_pc (s, cursal.line, &cursal.pc);
    470  1.11  christos 
    471  1.11  christos       /* This centering code is copied from tui_source_window::maybe_update.
    472  1.11  christos 	 It would be nice to do centering more often, and do it in just one
    473  1.11  christos 	 location.  But since this is a regression fix, handle this
    474  1.11  christos 	 conservatively for now.  */
    475  1.11  christos       int start_line = (cursal.line - ((height - box_size ()) / 2)) + 1;
    476  1.11  christos       if (start_line <= 0)
    477  1.11  christos 	start_line = 1;
    478  1.11  christos       cursal.line = start_line;
    479  1.11  christos 
    480   1.9  christos       update_source_window (gdbarch, cursal);
    481   1.1  christos     }
    482   1.1  christos   else
    483  1.11  christos     {
    484  1.11  christos       CORE_ADDR addr;
    485  1.11  christos       struct gdbarch *gdbarch;
    486  1.11  christos       tui_get_begin_asm_address (&gdbarch, &addr);
    487  1.11  christos       if (addr == 0)
    488  1.11  christos 	erase_source_content ();
    489  1.11  christos       else
    490  1.11  christos 	update_source_window_with_addr (gdbarch, addr);
    491  1.11  christos     }
    492   1.1  christos }
    493   1.1  christos 
    494   1.9  christos /* See tui-data.h.  */
    495   1.8  christos 
    496   1.8  christos void
    497   1.9  christos tui_source_window_base::refill ()
    498   1.8  christos {
    499   1.9  christos   symtab_and_line sal {};
    500   1.8  christos 
    501  1.12  christos   if (this == tui_src_win ())
    502   1.8  christos     {
    503  1.12  christos       sal = get_current_source_symtab_and_line (current_program_space);
    504   1.9  christos       if (sal.symtab == NULL)
    505   1.9  christos 	{
    506  1.10  christos 	  frame_info_ptr fi = deprecated_safe_get_selected_frame ();
    507   1.9  christos 	  if (fi != nullptr)
    508   1.9  christos 	    sal = find_pc_line (get_frame_pc (fi), 0);
    509   1.9  christos 	}
    510   1.8  christos     }
    511   1.8  christos 
    512   1.9  christos   if (sal.pspace == nullptr)
    513   1.9  christos     sal.pspace = current_program_space;
    514   1.9  christos 
    515   1.9  christos   if (m_start_line_or_addr.loa == LOA_LINE)
    516   1.9  christos     sal.line = m_start_line_or_addr.u.line_no;
    517   1.9  christos   else
    518   1.9  christos     sal.pc = m_start_line_or_addr.u.addr;
    519   1.9  christos 
    520   1.9  christos   update_source_window_as_is (m_gdbarch, sal);
    521   1.8  christos }
    522   1.1  christos 
    523  1.11  christos /* See tui-winsource.h.  */
    524  1.11  christos 
    525  1.11  christos bool
    526  1.11  christos tui_source_window_base::validate_scroll_offsets ()
    527  1.11  christos {
    528  1.11  christos   TUI_SCOPED_DEBUG_START_END ("window `%s`", name ());
    529  1.11  christos 
    530  1.11  christos   int original_pad_offset = m_pad_offset;
    531  1.11  christos 
    532  1.11  christos   if (m_horizontal_offset < 0)
    533  1.11  christos     m_horizontal_offset = 0;
    534  1.11  christos 
    535  1.11  christos   int content_width = m_max_length;
    536  1.11  christos   int pad_width = tui_getmaxx (m_pad.get ());
    537  1.11  christos   int view_width = this->view_width ();
    538  1.11  christos 
    539  1.11  christos   tui_debug_printf ("pad_width = %d, view_width = %d, content_width = %d",
    540  1.11  christos 		    pad_width, view_width, content_width);
    541  1.11  christos   tui_debug_printf ("original_pad_offset = %d, m_horizontal_offset = %d",
    542  1.11  christos 		    original_pad_offset, m_horizontal_offset);
    543  1.11  christos 
    544  1.11  christos   if (m_horizontal_offset + view_width > content_width)
    545  1.11  christos     m_horizontal_offset = std::max (content_width - view_width, 0);
    546  1.11  christos 
    547  1.11  christos   if ((m_horizontal_offset + view_width) > (m_pad_offset + pad_width))
    548  1.11  christos     {
    549  1.11  christos       m_pad_offset = std::min (m_horizontal_offset, content_width - pad_width);
    550  1.11  christos       m_pad_offset = std::max (m_pad_offset, 0);
    551  1.11  christos     }
    552  1.11  christos   else if (m_horizontal_offset < m_pad_offset)
    553  1.11  christos     m_pad_offset = std::max (m_horizontal_offset + view_width - pad_width, 0);
    554  1.11  christos 
    555  1.11  christos   gdb_assert (m_pad_offset >= 0);
    556  1.11  christos   return (original_pad_offset != m_pad_offset);
    557  1.11  christos }
    558  1.11  christos 
    559   1.1  christos /* Scroll the source forward or backward horizontally.  */
    560   1.8  christos 
    561   1.1  christos void
    562   1.9  christos tui_source_window_base::do_scroll_horizontal (int num_to_scroll)
    563   1.1  christos {
    564   1.9  christos   if (!m_content.empty ())
    565   1.1  christos     {
    566  1.11  christos       m_horizontal_offset += num_to_scroll;
    567  1.11  christos 
    568  1.11  christos       if (validate_scroll_offsets ())
    569  1.11  christos 	show_source_content ();
    570  1.11  christos 
    571  1.10  christos       refresh_window ();
    572   1.1  christos     }
    573   1.1  christos }
    574   1.1  christos 
    575   1.1  christos 
    576   1.9  christos /* Set or clear the is_exec_point flag in the line whose line is
    577   1.1  christos    line_no.  */
    578   1.1  christos 
    579   1.1  christos void
    580   1.9  christos tui_source_window_base::set_is_exec_point_at (struct tui_line_or_address l)
    581   1.1  christos {
    582   1.9  christos   bool changed = false;
    583   1.1  christos   int i;
    584   1.1  christos 
    585   1.1  christos   i = 0;
    586   1.9  christos   while (i < m_content.size ())
    587   1.1  christos     {
    588   1.9  christos       bool new_state;
    589   1.1  christos       struct tui_line_or_address content_loa =
    590   1.9  christos 	m_content[i].line_or_addr;
    591   1.1  christos 
    592   1.1  christos       if (content_loa.loa == l.loa
    593   1.1  christos 	  && ((l.loa == LOA_LINE && content_loa.u.line_no == l.u.line_no)
    594  1.10  christos 	      || (l.loa == LOA_ADDRESS && content_loa.u.addr == l.u.addr)))
    595  1.10  christos 	new_state = true;
    596   1.1  christos       else
    597   1.9  christos 	new_state = false;
    598   1.9  christos       if (new_state != m_content[i].is_exec_point)
    599  1.10  christos 	{
    600  1.10  christos 	  changed = true;
    601  1.10  christos 	  m_content[i].is_exec_point = new_state;
    602  1.10  christos 	}
    603   1.1  christos       i++;
    604   1.1  christos     }
    605   1.1  christos   if (changed)
    606   1.9  christos     refill ();
    607   1.1  christos }
    608   1.1  christos 
    609   1.9  christos /* See tui-winsource.h.  */
    610   1.9  christos 
    611   1.1  christos void
    612   1.9  christos tui_update_all_breakpoint_info (struct breakpoint *being_deleted)
    613   1.1  christos {
    614   1.9  christos   for (tui_source_window_base *win : tui_source_windows ())
    615   1.1  christos     {
    616   1.9  christos       if (win->update_breakpoint_info (being_deleted, false))
    617   1.9  christos 	win->update_exec_info ();
    618   1.1  christos     }
    619   1.1  christos }
    620   1.1  christos 
    621   1.1  christos 
    622   1.9  christos /* Scan the source window and the breakpoints to update the break_mode
    623   1.1  christos    information for each line.
    624   1.1  christos 
    625   1.9  christos    Returns true if something changed and the execution window must be
    626   1.1  christos    refreshed.  */
    627   1.1  christos 
    628   1.9  christos bool
    629   1.9  christos tui_source_window_base::update_breakpoint_info
    630   1.9  christos   (struct breakpoint *being_deleted, bool current_only)
    631   1.1  christos {
    632   1.1  christos   int i;
    633   1.9  christos   bool need_refresh = false;
    634   1.1  christos 
    635   1.9  christos   for (i = 0; i < m_content.size (); i++)
    636   1.1  christos     {
    637   1.1  christos       struct tui_source_element *line;
    638   1.1  christos 
    639   1.9  christos       line = &m_content[i];
    640   1.1  christos       if (current_only && !line->is_exec_point)
    641  1.10  christos 	 continue;
    642   1.1  christos 
    643   1.1  christos       /* Scan each breakpoint to see if the current line has something to
    644  1.10  christos 	 do with it.  Identify enable/disabled breakpoints as well as
    645  1.10  christos 	 those that we already hit.  */
    646   1.9  christos       tui_bp_flags mode = 0;
    647  1.11  christos       for (breakpoint &bp : all_breakpoints ())
    648  1.10  christos 	{
    649  1.11  christos 	  if (&bp == being_deleted)
    650  1.10  christos 	    continue;
    651   1.1  christos 
    652  1.11  christos 	  for (bp_location &loc : bp.locations ())
    653   1.1  christos 	    {
    654  1.11  christos 	      if (location_matches_p (&loc, i))
    655   1.1  christos 		{
    656  1.11  christos 		  if (bp.enable_state == bp_disabled)
    657   1.1  christos 		    mode |= TUI_BP_DISABLED;
    658   1.1  christos 		  else
    659   1.1  christos 		    mode |= TUI_BP_ENABLED;
    660  1.11  christos 		  if (bp.hit_count)
    661   1.1  christos 		    mode |= TUI_BP_HIT;
    662  1.11  christos 		  if (bp.first_loc ().cond)
    663   1.1  christos 		    mode |= TUI_BP_CONDITIONAL;
    664  1.11  christos 		  if (bp.type == bp_hardware_breakpoint)
    665   1.1  christos 		    mode |= TUI_BP_HARDWARE;
    666   1.1  christos 		}
    667   1.1  christos 	    }
    668  1.10  christos 	}
    669  1.10  christos 
    670   1.9  christos       if (line->break_mode != mode)
    671  1.10  christos 	{
    672  1.10  christos 	  line->break_mode = mode;
    673  1.10  christos 	  need_refresh = true;
    674  1.10  christos 	}
    675   1.1  christos     }
    676   1.1  christos   return need_refresh;
    677   1.1  christos }
    678   1.1  christos 
    679  1.11  christos /* See tui-winsource.h.  */
    680  1.11  christos 
    681   1.1  christos void
    682  1.11  christos tui_source_window_base::update_exec_info (bool refresh_p)
    683   1.1  christos {
    684   1.9  christos   update_breakpoint_info (nullptr, true);
    685   1.9  christos   for (int i = 0; i < m_content.size (); i++)
    686   1.1  christos     {
    687   1.9  christos       struct tui_source_element *src_element = &m_content[i];
    688  1.11  christos       /* Add 1 for '\0'.  */
    689  1.11  christos       char element[TUI_EXECINFO_SIZE + 1];
    690  1.11  christos       /* Initialize all but last element.  */
    691  1.11  christos       char space = tui_left_margin_verbose ? '_' : ' ';
    692  1.11  christos       memset (element, space, TUI_EXECINFO_SIZE);
    693  1.11  christos       /* Initialize last element.  */
    694  1.11  christos       element[TUI_EXECINFO_SIZE] = '\0';
    695   1.1  christos 
    696   1.9  christos       /* Now update the exec info content based upon the state
    697   1.9  christos 	 of each line as indicated by the source content.  */
    698   1.9  christos       tui_bp_flags mode = src_element->break_mode;
    699   1.9  christos       if (mode & TUI_BP_HIT)
    700   1.9  christos 	element[TUI_BP_HIT_POS] = (mode & TUI_BP_HARDWARE) ? 'H' : 'B';
    701   1.9  christos       else if (mode & (TUI_BP_ENABLED | TUI_BP_DISABLED))
    702   1.9  christos 	element[TUI_BP_HIT_POS] = (mode & TUI_BP_HARDWARE) ? 'h' : 'b';
    703   1.1  christos 
    704   1.9  christos       if (mode & TUI_BP_ENABLED)
    705   1.9  christos 	element[TUI_BP_BREAK_POS] = '+';
    706   1.9  christos       else if (mode & TUI_BP_DISABLED)
    707   1.9  christos 	element[TUI_BP_BREAK_POS] = '-';
    708   1.1  christos 
    709   1.9  christos       if (src_element->is_exec_point)
    710   1.9  christos 	element[TUI_EXEC_POS] = '>';
    711   1.1  christos 
    712  1.11  christos       mvwaddstr (handle.get (), i + box_width (), box_width (), element);
    713  1.10  christos 
    714  1.10  christos       show_line_number (i);
    715   1.1  christos     }
    716  1.11  christos   if (refresh_p)
    717  1.11  christos     refresh_window ();
    718   1.1  christos }
    719