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