Home | History | Annotate | Line # | Download | only in tui
tui-regs.c revision 1.10
      1   1.1  christos /* TUI display registers in window.
      2   1.1  christos 
      3  1.10  christos    Copyright (C) 1998-2023 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 "defs.h"
     23   1.1  christos #include "arch-utils.h"
     24   1.1  christos #include "tui/tui.h"
     25   1.1  christos #include "tui/tui-data.h"
     26   1.1  christos #include "symtab.h"
     27   1.1  christos #include "gdbtypes.h"
     28   1.1  christos #include "gdbcmd.h"
     29   1.1  christos #include "frame.h"
     30   1.1  christos #include "regcache.h"
     31   1.1  christos #include "inferior.h"
     32   1.1  christos #include "target.h"
     33   1.1  christos #include "tui/tui-layout.h"
     34   1.1  christos #include "tui/tui-win.h"
     35   1.1  christos #include "tui/tui-wingeneral.h"
     36   1.1  christos #include "tui/tui-file.h"
     37   1.1  christos #include "tui/tui-regs.h"
     38   1.3  christos #include "tui/tui-io.h"
     39   1.1  christos #include "reggroups.h"
     40   1.1  christos #include "valprint.h"
     41   1.5  christos #include "completer.h"
     42   1.1  christos 
     43   1.1  christos #include "gdb_curses.h"
     44   1.1  christos 
     45   1.9  christos /* A subclass of string_file that expands tab characters.  */
     46   1.9  christos class tab_expansion_file : public string_file
     47   1.9  christos {
     48   1.9  christos public:
     49   1.1  christos 
     50   1.9  christos   tab_expansion_file () = default;
     51   1.1  christos 
     52   1.9  christos   void write (const char *buf, long length_buf) override;
     53   1.1  christos 
     54   1.9  christos private:
     55   1.1  christos 
     56   1.9  christos   int m_column = 0;
     57   1.9  christos };
     58   1.1  christos 
     59   1.9  christos void
     60   1.9  christos tab_expansion_file::write (const char *buf, long length_buf)
     61   1.9  christos {
     62   1.9  christos   for (long i = 0; i < length_buf; ++i)
     63   1.9  christos     {
     64   1.9  christos       if (buf[i] == '\t')
     65   1.9  christos 	{
     66   1.9  christos 	  do
     67   1.9  christos 	    {
     68   1.9  christos 	      string_file::write (" ", 1);
     69   1.9  christos 	      ++m_column;
     70   1.9  christos 	    }
     71   1.9  christos 	  while ((m_column % 8) != 0);
     72   1.9  christos 	}
     73   1.9  christos       else
     74   1.9  christos 	{
     75   1.9  christos 	  string_file::write (&buf[i], 1);
     76   1.9  christos 	  if (buf[i] == '\n')
     77   1.9  christos 	    m_column = 0;
     78   1.9  christos 	  else
     79   1.9  christos 	    ++m_column;
     80   1.9  christos 	}
     81   1.9  christos     }
     82   1.9  christos }
     83   1.1  christos 
     84   1.9  christos /* Get the register from the frame and return a printable
     85   1.9  christos    representation of it.  */
     86   1.1  christos 
     87   1.9  christos static std::string
     88  1.10  christos tui_register_format (frame_info_ptr frame, int regnum)
     89   1.1  christos {
     90   1.9  christos   struct gdbarch *gdbarch = get_frame_arch (frame);
     91   1.9  christos 
     92   1.9  christos   /* Expand tabs into spaces, since ncurses on MS-Windows doesn't.  */
     93   1.9  christos   tab_expansion_file stream;
     94   1.9  christos 
     95   1.9  christos   scoped_restore save_pagination
     96  1.10  christos     = make_scoped_restore (&pagination_enabled, false);
     97   1.9  christos   scoped_restore save_stdout
     98   1.9  christos     = make_scoped_restore (&gdb_stdout, &stream);
     99   1.9  christos 
    100   1.9  christos   gdbarch_print_registers_info (gdbarch, &stream, frame, regnum, 1);
    101   1.1  christos 
    102   1.9  christos   /* Remove the possible \n.  */
    103  1.10  christos   std::string str = stream.release ();
    104   1.9  christos   if (!str.empty () && str.back () == '\n')
    105   1.9  christos     str.resize (str.size () - 1);
    106   1.9  christos 
    107   1.9  christos   return str;
    108   1.9  christos }
    109   1.9  christos 
    110   1.9  christos /* Get the register value from the given frame and format it for the
    111   1.9  christos    display.  When changep is set, check if the new register value has
    112   1.9  christos    changed with respect to the previous call.  */
    113   1.9  christos static void
    114  1.10  christos tui_get_register (frame_info_ptr frame,
    115  1.10  christos 		  struct tui_data_item_window *data,
    116   1.9  christos 		  int regnum, bool *changedp)
    117   1.9  christos {
    118   1.9  christos   if (changedp)
    119   1.9  christos     *changedp = false;
    120  1.10  christos   if (target_has_registers ())
    121   1.1  christos     {
    122   1.9  christos       std::string new_content = tui_register_format (frame, regnum);
    123   1.9  christos 
    124   1.9  christos       if (changedp != NULL && data->content != new_content)
    125   1.9  christos 	*changedp = true;
    126   1.9  christos 
    127   1.9  christos       data->content = std::move (new_content);
    128   1.1  christos     }
    129   1.9  christos }
    130   1.9  christos 
    131   1.9  christos /* See tui-regs.h.  */
    132   1.9  christos 
    133   1.9  christos int
    134   1.9  christos tui_data_window::last_regs_line_no () const
    135   1.9  christos {
    136   1.9  christos   int num_lines = m_regs_content.size () / m_regs_column_count;
    137   1.9  christos   if (m_regs_content.size () % m_regs_column_count)
    138   1.9  christos     num_lines++;
    139   1.1  christos   return num_lines;
    140   1.1  christos }
    141   1.1  christos 
    142   1.9  christos /* See tui-regs.h.  */
    143   1.1  christos 
    144   1.1  christos int
    145   1.9  christos tui_data_window::line_from_reg_element_no (int element_no) const
    146   1.1  christos {
    147   1.9  christos   if (element_no < m_regs_content.size ())
    148   1.1  christos     {
    149   1.1  christos       int i, line = (-1);
    150   1.1  christos 
    151   1.1  christos       i = 1;
    152   1.1  christos       while (line == (-1))
    153   1.1  christos 	{
    154   1.9  christos 	  if (element_no < m_regs_column_count * i)
    155   1.1  christos 	    line = i - 1;
    156   1.1  christos 	  else
    157   1.1  christos 	    i++;
    158   1.1  christos 	}
    159   1.1  christos 
    160   1.1  christos       return line;
    161   1.1  christos     }
    162   1.1  christos   else
    163   1.1  christos     return (-1);
    164   1.1  christos }
    165   1.1  christos 
    166   1.9  christos /* See tui-regs.h.  */
    167   1.1  christos 
    168   1.1  christos int
    169   1.9  christos tui_data_window::first_reg_element_no_inline (int line_no) const
    170   1.1  christos {
    171   1.9  christos   if (line_no * m_regs_column_count <= m_regs_content.size ())
    172   1.9  christos     return ((line_no + 1) * m_regs_column_count) - m_regs_column_count;
    173   1.1  christos   else
    174   1.1  christos     return (-1);
    175   1.1  christos }
    176   1.1  christos 
    177   1.1  christos /* Show the registers of the given group in the data window
    178   1.1  christos    and refresh the window.  */
    179   1.1  christos void
    180  1.10  christos tui_data_window::show_registers (const reggroup *group)
    181   1.1  christos {
    182   1.1  christos   if (group == 0)
    183   1.1  christos     group = general_reggroup;
    184   1.1  christos 
    185  1.10  christos   if (target_has_registers () && target_has_stack () && target_has_memory ())
    186   1.1  christos     {
    187   1.9  christos       show_register_group (group, get_selected_frame (NULL),
    188   1.9  christos 			   group == m_current_group);
    189   1.9  christos 
    190   1.9  christos       /* Clear all notation of changed values.  */
    191   1.9  christos       for (auto &&data_item_win : m_regs_content)
    192   1.9  christos 	data_item_win.highlight = false;
    193   1.9  christos       m_current_group = group;
    194   1.1  christos     }
    195   1.9  christos   else
    196   1.1  christos     {
    197   1.9  christos       m_current_group = 0;
    198   1.9  christos       m_regs_content.clear ();
    199   1.1  christos     }
    200   1.1  christos 
    201   1.9  christos   rerender ();
    202   1.1  christos }
    203   1.1  christos 
    204   1.1  christos 
    205   1.1  christos /* Set the data window to display the registers of the register group
    206   1.1  christos    using the given frame.  Values are refreshed only when
    207   1.9  christos    refresh_values_only is true.  */
    208   1.1  christos 
    209   1.9  christos void
    210  1.10  christos tui_data_window::show_register_group (const reggroup *group,
    211  1.10  christos 				      frame_info_ptr frame,
    212   1.9  christos 				      bool refresh_values_only)
    213   1.1  christos {
    214   1.1  christos   struct gdbarch *gdbarch = get_frame_arch (frame);
    215   1.1  christos   int nr_regs;
    216   1.1  christos   int regnum, pos;
    217   1.1  christos 
    218   1.1  christos   /* Make a new title showing which group we display.  */
    219  1.10  christos   title = string_printf ("Register group: %s", group->name ());
    220   1.1  christos 
    221   1.1  christos   /* See how many registers must be displayed.  */
    222   1.1  christos   nr_regs = 0;
    223   1.8  christos   for (regnum = 0; regnum < gdbarch_num_cooked_regs (gdbarch); regnum++)
    224   1.1  christos     {
    225   1.1  christos       const char *name;
    226   1.1  christos 
    227   1.1  christos       /* Must be in the group.  */
    228   1.1  christos       if (!gdbarch_register_reggroup_p (gdbarch, regnum, group))
    229   1.1  christos 	continue;
    230   1.1  christos 
    231   1.1  christos       /* If the register name is empty, it is undefined for this
    232   1.1  christos 	 processor, so don't display anything.  */
    233   1.1  christos       name = gdbarch_register_name (gdbarch, regnum);
    234  1.10  christos       if (*name == '\0')
    235   1.1  christos 	continue;
    236   1.1  christos 
    237   1.1  christos       nr_regs++;
    238   1.1  christos     }
    239   1.1  christos 
    240   1.9  christos   m_regs_content.resize (nr_regs);
    241   1.9  christos 
    242   1.9  christos   /* Now set the register names and values.  */
    243   1.9  christos   pos = 0;
    244   1.9  christos   for (regnum = 0; regnum < gdbarch_num_cooked_regs (gdbarch); regnum++)
    245   1.1  christos     {
    246   1.9  christos       struct tui_data_item_window *data_item_win;
    247   1.9  christos       const char *name;
    248   1.9  christos 
    249   1.9  christos       /* Must be in the group.  */
    250   1.9  christos       if (!gdbarch_register_reggroup_p (gdbarch, regnum, group))
    251   1.9  christos 	continue;
    252   1.9  christos 
    253   1.9  christos       /* If the register name is empty, it is undefined for this
    254   1.9  christos 	 processor, so don't display anything.  */
    255   1.9  christos       name = gdbarch_register_name (gdbarch, regnum);
    256  1.10  christos       if (*name == '\0')
    257   1.9  christos 	continue;
    258   1.9  christos 
    259   1.9  christos       data_item_win = &m_regs_content[pos];
    260   1.9  christos       if (!refresh_values_only)
    261   1.9  christos 	{
    262   1.9  christos 	  data_item_win->regno = regnum;
    263   1.9  christos 	  data_item_win->highlight = false;
    264   1.9  christos 	}
    265   1.9  christos       tui_get_register (frame, data_item_win, regnum, 0);
    266   1.9  christos       pos++;
    267   1.1  christos     }
    268   1.9  christos }
    269   1.9  christos 
    270   1.9  christos /* See tui-regs.h.  */
    271   1.1  christos 
    272   1.9  christos void
    273   1.9  christos tui_data_window::display_registers_from (int start_element_no)
    274   1.9  christos {
    275   1.9  christos   int max_len = 0;
    276   1.9  christos   for (auto &&data_item_win : m_regs_content)
    277   1.1  christos     {
    278   1.9  christos       int len = data_item_win.content.size ();
    279   1.9  christos 
    280   1.9  christos       if (len > max_len)
    281   1.9  christos 	max_len = len;
    282   1.1  christos     }
    283   1.9  christos   m_item_width = max_len + 1;
    284  1.10  christos 
    285  1.10  christos   int i;
    286  1.10  christos   /* Mark register windows above the visible area.  */
    287  1.10  christos   for (i = 0; i < start_element_no; i++)
    288  1.10  christos     m_regs_content[i].y = 0;
    289   1.1  christos 
    290   1.9  christos   m_regs_column_count = (width - 2) / m_item_width;
    291   1.9  christos   if (m_regs_column_count == 0)
    292   1.9  christos     m_regs_column_count = 1;
    293   1.9  christos   m_item_width = (width - 2) / m_regs_column_count;
    294   1.9  christos 
    295   1.9  christos   /* Now create each data "sub" window, and write the display into
    296   1.9  christos      it.  */
    297   1.9  christos   int cur_y = 1;
    298   1.9  christos   while (i < m_regs_content.size () && cur_y <= height - 2)
    299   1.1  christos     {
    300   1.9  christos       for (int j = 0;
    301   1.9  christos 	   j < m_regs_column_count && i < m_regs_content.size ();
    302   1.9  christos 	   j++)
    303   1.1  christos 	{
    304   1.9  christos 	  /* Create the window if necessary.  */
    305   1.9  christos 	  m_regs_content[i].x = (m_item_width * j) + 1;
    306   1.9  christos 	  m_regs_content[i].y = cur_y;
    307   1.9  christos 	  m_regs_content[i].visible = true;
    308   1.9  christos 	  m_regs_content[i].rerender (handle.get (), m_item_width);
    309   1.9  christos 	  i++;		/* Next register.  */
    310   1.1  christos 	}
    311   1.9  christos       cur_y++;		/* Next row.  */
    312   1.9  christos     }
    313  1.10  christos 
    314  1.10  christos   /* Mark register windows below the visible area.  */
    315  1.10  christos   for (; i < m_regs_content.size (); i++)
    316  1.10  christos     m_regs_content[i].y = 0;
    317  1.10  christos 
    318  1.10  christos   refresh_window ();
    319   1.9  christos }
    320   1.1  christos 
    321   1.9  christos /* See tui-regs.h.  */
    322   1.9  christos 
    323   1.9  christos void
    324   1.9  christos tui_data_window::display_reg_element_at_line (int start_element_no,
    325   1.9  christos 					      int start_line_no)
    326   1.9  christos {
    327   1.9  christos   int element_no = start_element_no;
    328   1.9  christos 
    329   1.9  christos   if (start_element_no != 0 && start_line_no != 0)
    330   1.9  christos     {
    331   1.9  christos       int last_line_no, first_line_on_last_page;
    332   1.1  christos 
    333   1.9  christos       last_line_no = last_regs_line_no ();
    334   1.9  christos       first_line_on_last_page = last_line_no - (height - 2);
    335   1.9  christos       if (first_line_on_last_page < 0)
    336   1.9  christos 	first_line_on_last_page = 0;
    337   1.1  christos 
    338   1.9  christos       /* If the element_no causes us to scroll past the end of the
    339   1.9  christos 	 registers, adjust what element to really start the
    340   1.9  christos 	 display at.  */
    341   1.9  christos       if (start_line_no > first_line_on_last_page)
    342   1.9  christos 	element_no = first_reg_element_no_inline (first_line_on_last_page);
    343   1.1  christos     }
    344   1.9  christos   display_registers_from (element_no);
    345   1.1  christos }
    346   1.1  christos 
    347   1.9  christos /* See tui-regs.h.  */
    348   1.1  christos 
    349   1.9  christos int
    350   1.9  christos tui_data_window::display_registers_from_line (int line_no)
    351   1.1  christos {
    352   1.9  christos   int element_no;
    353   1.9  christos 
    354   1.9  christos   if (line_no < 0)
    355   1.9  christos     line_no = 0;
    356   1.9  christos   else
    357   1.1  christos     {
    358   1.9  christos       /* Make sure that we don't display off the end of the
    359   1.9  christos 	 registers.  */
    360   1.9  christos       if (line_no >= last_regs_line_no ())
    361   1.9  christos 	{
    362   1.9  christos 	  line_no = line_from_reg_element_no (m_regs_content.size () - 1);
    363   1.9  christos 	  if (line_no < 0)
    364   1.9  christos 	    line_no = 0;
    365   1.9  christos 	}
    366   1.9  christos     }
    367   1.9  christos 
    368   1.9  christos   element_no = first_reg_element_no_inline (line_no);
    369   1.9  christos   if (element_no < m_regs_content.size ())
    370   1.9  christos     display_reg_element_at_line (element_no, line_no);
    371   1.9  christos   else
    372   1.9  christos     line_no = (-1);
    373   1.9  christos 
    374   1.9  christos   return line_no;
    375   1.9  christos }
    376   1.1  christos 
    377   1.1  christos 
    378   1.9  christos /* Answer the index first element displayed.  If none are displayed,
    379   1.9  christos    then return (-1).  */
    380   1.9  christos int
    381   1.9  christos tui_data_window::first_data_item_displayed ()
    382   1.9  christos {
    383   1.9  christos   for (int i = 0; i < m_regs_content.size (); i++)
    384   1.9  christos     {
    385   1.9  christos       if (m_regs_content[i].visible)
    386   1.9  christos 	return i;
    387   1.1  christos     }
    388   1.9  christos 
    389   1.9  christos   return -1;
    390   1.1  christos }
    391   1.1  christos 
    392   1.9  christos /* See tui-regs.h.  */
    393   1.9  christos 
    394   1.9  christos void
    395   1.9  christos tui_data_window::delete_data_content_windows ()
    396   1.9  christos {
    397   1.9  christos   for (auto &win : m_regs_content)
    398   1.9  christos     win.visible = false;
    399   1.9  christos }
    400   1.1  christos 
    401   1.1  christos 
    402   1.9  christos void
    403   1.9  christos tui_data_window::erase_data_content (const char *prompt)
    404   1.1  christos {
    405   1.9  christos   werase (handle.get ());
    406   1.9  christos   check_and_display_highlight_if_needed ();
    407   1.9  christos   if (prompt != NULL)
    408   1.1  christos     {
    409   1.9  christos       int half_width = (width - 2) / 2;
    410   1.9  christos       int x_pos;
    411   1.1  christos 
    412   1.9  christos       if (strlen (prompt) >= half_width)
    413   1.9  christos 	x_pos = 1;
    414   1.1  christos       else
    415   1.9  christos 	x_pos = half_width - strlen (prompt);
    416   1.9  christos       mvwaddstr (handle.get (), (height / 2), x_pos, (char *) prompt);
    417   1.9  christos     }
    418   1.9  christos   tui_wrefresh (handle.get ());
    419   1.9  christos }
    420   1.9  christos 
    421   1.9  christos /* See tui-regs.h.  */
    422   1.1  christos 
    423   1.9  christos void
    424   1.9  christos tui_data_window::rerender ()
    425   1.9  christos {
    426   1.9  christos   if (m_regs_content.empty ())
    427   1.9  christos     erase_data_content (_("[ Register Values Unavailable ]"));
    428   1.9  christos   else
    429   1.9  christos     {
    430   1.9  christos       erase_data_content (NULL);
    431   1.9  christos       delete_data_content_windows ();
    432   1.9  christos       display_registers_from (0);
    433   1.9  christos     }
    434   1.9  christos }
    435   1.9  christos 
    436   1.9  christos 
    437   1.9  christos /* Scroll the data window vertically forward or backward.  */
    438   1.9  christos void
    439   1.9  christos tui_data_window::do_scroll_vertical (int num_to_scroll)
    440   1.9  christos {
    441   1.9  christos   int first_element_no;
    442   1.9  christos   int first_line = (-1);
    443   1.1  christos 
    444   1.9  christos   first_element_no = first_data_item_displayed ();
    445   1.9  christos   if (first_element_no < m_regs_content.size ())
    446   1.9  christos     first_line = line_from_reg_element_no (first_element_no);
    447   1.9  christos   else
    448   1.9  christos     { /* Calculate the first line from the element number which is in
    449  1.10  christos 	the general data content.  */
    450   1.1  christos     }
    451   1.1  christos 
    452   1.9  christos   if (first_line >= 0)
    453   1.9  christos     {
    454   1.9  christos       first_line += num_to_scroll;
    455   1.9  christos       erase_data_content (NULL);
    456   1.9  christos       delete_data_content_windows ();
    457   1.9  christos       display_registers_from_line (first_line);
    458   1.9  christos     }
    459   1.1  christos }
    460   1.1  christos 
    461   1.1  christos /* This function check all displayed registers for changes in values,
    462   1.1  christos    given a particular frame.  If the values have changed, they are
    463   1.1  christos    updated with the new value and highlighted.  */
    464   1.1  christos void
    465  1.10  christos tui_data_window::check_register_values (frame_info_ptr frame)
    466   1.1  christos {
    467   1.9  christos   if (m_regs_content.empty ())
    468   1.9  christos     show_registers (m_current_group);
    469   1.9  christos   else
    470   1.1  christos     {
    471   1.9  christos       for (auto &&data_item_win : m_regs_content)
    472   1.9  christos 	{
    473   1.9  christos 	  int was_hilighted;
    474   1.9  christos 
    475   1.9  christos 	  was_hilighted = data_item_win.highlight;
    476   1.1  christos 
    477   1.9  christos 	  tui_get_register (frame, &data_item_win,
    478   1.9  christos 			    data_item_win.regno,
    479   1.9  christos 			    &data_item_win.highlight);
    480   1.1  christos 
    481  1.10  christos 	  /* Register windows whose y == 0 are outside the visible area.  */
    482  1.10  christos 	  if ((data_item_win.highlight || was_hilighted)
    483  1.10  christos 	      && data_item_win.y > 0)
    484   1.9  christos 	    data_item_win.rerender (handle.get (), m_item_width);
    485   1.1  christos 	}
    486   1.1  christos     }
    487   1.9  christos 
    488   1.9  christos   tui_wrefresh (handle.get ());
    489   1.1  christos }
    490   1.1  christos 
    491   1.1  christos /* Display a register in a window.  If hilite is TRUE, then the value
    492   1.1  christos    will be displayed in reverse video.  */
    493   1.9  christos void
    494   1.9  christos tui_data_item_window::rerender (WINDOW *handle, int field_width)
    495   1.1  christos {
    496   1.9  christos   if (highlight)
    497   1.9  christos     /* We ignore the return value, casting it to void in order to avoid
    498   1.9  christos        a compiler warning.  The warning itself was introduced by a patch
    499   1.9  christos        to ncurses 5.7 dated 2009-08-29, changing this macro to expand
    500   1.9  christos        to code that causes the compiler to generate an unused-value
    501   1.9  christos        warning.  */
    502   1.9  christos     (void) wstandout (handle);
    503   1.9  christos 
    504   1.9  christos   mvwaddnstr (handle, y, x, content.c_str (), field_width - 1);
    505  1.10  christos   if (content.size () < field_width)
    506  1.10  christos     waddstr (handle, n_spaces (field_width - content.size ()));
    507   1.1  christos 
    508   1.9  christos   if (highlight)
    509   1.9  christos     /* We ignore the return value, casting it to void in order to avoid
    510   1.9  christos        a compiler warning.  The warning itself was introduced by a patch
    511   1.9  christos        to ncurses 5.7 dated 2009-08-29, changing this macro to expand
    512   1.9  christos        to code that causes the compiler to generate an unused-value
    513   1.9  christos        warning.  */
    514   1.9  christos     (void) wstandend (handle);
    515   1.1  christos }
    516   1.1  christos 
    517  1.10  christos /* Helper for "tui reg next", returns the next register group after
    518  1.10  christos    CURRENT_GROUP in the register group list for GDBARCH, with wrap around
    519  1.10  christos    behaviour.
    520  1.10  christos 
    521  1.10  christos    If CURRENT_GROUP is nullptr (e.g. if the tui register window has only
    522  1.10  christos    just been displayed and has no current group selected) or the currently
    523  1.10  christos    selected register group can't be found (e.g. if the architecture has
    524  1.10  christos    changed since the register window was last updated), then the first
    525  1.10  christos    register group will be returned.  */
    526  1.10  christos 
    527  1.10  christos static const reggroup *
    528  1.10  christos tui_reg_next (const reggroup *current_group, struct gdbarch *gdbarch)
    529  1.10  christos {
    530  1.10  christos   const std::vector<const reggroup *> &groups = gdbarch_reggroups (gdbarch);
    531  1.10  christos   auto it = std::find (groups.begin (), groups.end (), current_group);
    532  1.10  christos   if (it != groups.end ())
    533  1.10  christos     it++;
    534  1.10  christos   if (it == groups.end ())
    535  1.10  christos     return groups.front ();
    536  1.10  christos   return *it;
    537  1.10  christos }
    538  1.10  christos 
    539  1.10  christos /* Helper for "tui reg prev", returns the register group previous to
    540  1.10  christos    CURRENT_GROUP in the register group list for GDBARCH, with wrap around
    541  1.10  christos    behaviour.
    542  1.10  christos 
    543  1.10  christos    If CURRENT_GROUP is nullptr (e.g. if the tui register window has only
    544  1.10  christos    just been displayed and has no current group selected) or the currently
    545  1.10  christos    selected register group can't be found (e.g. if the architecture has
    546  1.10  christos    changed since the register window was last updated), then the last
    547  1.10  christos    register group will be returned.  */
    548  1.10  christos 
    549  1.10  christos static const reggroup *
    550  1.10  christos tui_reg_prev (const reggroup *current_group, struct gdbarch *gdbarch)
    551  1.10  christos {
    552  1.10  christos   const std::vector<const reggroup *> &groups = gdbarch_reggroups (gdbarch);
    553  1.10  christos   auto it = std::find (groups.rbegin (), groups.rend (), current_group);
    554  1.10  christos   if (it != groups.rend ())
    555  1.10  christos     it++;
    556  1.10  christos   if (it == groups.rend ())
    557  1.10  christos     return groups.back ();
    558  1.10  christos   return *it;
    559   1.1  christos }
    560   1.1  christos 
    561   1.5  christos /* Implement the 'tui reg' command.  Changes the register group displayed
    562   1.5  christos    in the tui register window.  Displays the tui register window if it is
    563   1.5  christos    not already on display.  */
    564   1.5  christos 
    565   1.1  christos static void
    566   1.8  christos tui_reg_command (const char *args, int from_tty)
    567   1.1  christos {
    568   1.5  christos   struct gdbarch *gdbarch = get_current_arch ();
    569   1.5  christos 
    570   1.5  christos   if (args != NULL)
    571   1.5  christos     {
    572   1.5  christos       size_t len = strlen (args);
    573   1.5  christos 
    574   1.5  christos       /* Make sure the curses mode is enabled.  */
    575   1.5  christos       tui_enable ();
    576   1.5  christos 
    577   1.9  christos       tui_suppress_output suppress;
    578   1.9  christos 
    579   1.5  christos       /* Make sure the register window is visible.  If not, select an
    580   1.5  christos 	 appropriate layout.  We need to do this before trying to run the
    581   1.5  christos 	 'next' or 'prev' commands.  */
    582   1.9  christos       if (TUI_DATA_WIN == NULL || !TUI_DATA_WIN->is_visible ())
    583   1.9  christos 	tui_regs_layout ();
    584   1.5  christos 
    585  1.10  christos       const reggroup *match = nullptr;
    586  1.10  christos       const reggroup *current_group = TUI_DATA_WIN->get_current_group ();
    587   1.5  christos       if (strncmp (args, "next", len) == 0)
    588   1.9  christos 	match = tui_reg_next (current_group, gdbarch);
    589   1.5  christos       else if (strncmp (args, "prev", len) == 0)
    590   1.9  christos 	match = tui_reg_prev (current_group, gdbarch);
    591  1.10  christos       else
    592   1.5  christos 	{
    593  1.10  christos 	  /* This loop matches on the initial part of a register group
    594  1.10  christos 	     name.  If this initial part in ARGS matches only one register
    595  1.10  christos 	     group then the switch is made.  */
    596  1.10  christos 	  for (const struct reggroup *group : gdbarch_reggroups (gdbarch))
    597   1.5  christos 	    {
    598  1.10  christos 	      if (strncmp (group->name (), args, len) == 0)
    599  1.10  christos 		{
    600  1.10  christos 		  if (match != NULL)
    601  1.10  christos 		    error (_("ambiguous register group name '%s'"), args);
    602  1.10  christos 		  match = group;
    603  1.10  christos 		}
    604   1.5  christos 	    }
    605   1.5  christos 	}
    606   1.5  christos 
    607   1.5  christos       if (match == NULL)
    608   1.5  christos 	error (_("unknown register group '%s'"), args);
    609   1.5  christos 
    610   1.9  christos       TUI_DATA_WIN->show_registers (match);
    611   1.5  christos     }
    612   1.5  christos   else
    613   1.5  christos     {
    614  1.10  christos       gdb_printf (_("\"tui reg\" must be followed by the name of "
    615  1.10  christos 		    "either a register group,\nor one of 'next' "
    616  1.10  christos 		    "or 'prev'.  Known register groups are:\n"));
    617   1.5  christos 
    618  1.10  christos       bool first = true;
    619  1.10  christos       for (const struct reggroup *group : gdbarch_reggroups (gdbarch))
    620   1.5  christos 	{
    621   1.5  christos 	  if (!first)
    622  1.10  christos 	    gdb_printf (", ");
    623  1.10  christos 	  first = false;
    624  1.10  christos 	  gdb_printf ("%s", group->name ());
    625   1.5  christos 	}
    626   1.5  christos 
    627  1.10  christos       gdb_printf ("\n");
    628   1.5  christos     }
    629   1.1  christos }
    630   1.1  christos 
    631   1.5  christos /* Complete names of register groups, and add the special "prev" and "next"
    632   1.5  christos    names.  */
    633   1.5  christos 
    634   1.8  christos static void
    635   1.5  christos tui_reggroup_completer (struct cmd_list_element *ignore,
    636   1.8  christos 			completion_tracker &tracker,
    637   1.5  christos 			const char *text, const char *word)
    638   1.1  christos {
    639   1.9  christos   static const char * const extra[] = { "next", "prev", NULL };
    640   1.5  christos 
    641   1.8  christos   reggroup_completer (ignore, tracker, text, word);
    642   1.1  christos 
    643   1.9  christos   complete_on_enum (tracker, extra, text, word);
    644   1.1  christos }
    645   1.1  christos 
    646   1.9  christos void _initialize_tui_regs ();
    647   1.1  christos void
    648   1.9  christos _initialize_tui_regs ()
    649   1.1  christos {
    650   1.5  christos   struct cmd_list_element **tuicmd, *cmd;
    651   1.1  christos 
    652   1.1  christos   tuicmd = tui_get_cmd_list ();
    653   1.1  christos 
    654   1.5  christos   cmd = add_cmd ("reg", class_tui, tui_reg_command, _("\
    655   1.9  christos TUI command to control the register window.\n\
    656   1.9  christos Usage: tui reg NAME\n\
    657   1.9  christos NAME is the name of the register group to display"), tuicmd);
    658   1.5  christos   set_cmd_completer (cmd, tui_reggroup_completer);
    659   1.1  christos }
    660