1 /* TUI display registers in window.
3 Copyright (C) 1998-2023 Free Software Foundation, Inc.
5 Contributed by Hewlett-Packard Company.
7 This file is part of GDB.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
23 #include "arch-utils.h"
25 #include "tui/tui-data.h"
33 #include "tui/tui-layout.h"
34 #include "tui/tui-win.h"
35 #include "tui/tui-wingeneral.h"
36 #include "tui/tui-file.h"
37 #include "tui/tui-regs.h"
38 #include "tui/tui-io.h"
39 #include "reggroups.h"
41 #include "completer.h"
43 #include "gdb_curses.h"
45 /* A subclass of string_file that expands tab characters. */
46 class tab_expansion_file
: public string_file
50 tab_expansion_file () = default;
52 void write (const char *buf
, long length_buf
) override
;
60 tab_expansion_file::write (const char *buf
, long length_buf
)
62 for (long i
= 0; i
< length_buf
; ++i
)
68 string_file::write (" ", 1);
71 while ((m_column
% 8) != 0);
75 string_file::write (&buf
[i
], 1);
84 /* Get the register from the frame and return a printable
85 representation of it. */
88 tui_register_format (frame_info_ptr frame
, int regnum
)
90 struct gdbarch
*gdbarch
= get_frame_arch (frame
);
92 /* Expand tabs into spaces, since ncurses on MS-Windows doesn't. */
93 tab_expansion_file stream
;
94 gdbarch_print_registers_info (gdbarch
, &stream
, frame
, regnum
, 1);
96 /* Remove the possible \n. */
97 std::string str
= stream
.release ();
98 if (!str
.empty () && str
.back () == '\n')
99 str
.resize (str
.size () - 1);
104 /* Get the register value from the given frame and format it for the
105 display. When changedp is set, check if the new register value has
106 changed with respect to the previous call. */
108 tui_get_register (frame_info_ptr frame
,
109 struct tui_data_item_window
*data
,
110 int regnum
, bool *changedp
)
114 if (target_has_registers ())
116 std::string new_content
= tui_register_format (frame
, regnum
);
118 if (changedp
!= NULL
&& data
->content
!= new_content
)
121 data
->content
= std::move (new_content
);
125 /* See tui-regs.h. */
128 tui_data_window::last_regs_line_no () const
130 int num_lines
= m_regs_content
.size () / m_regs_column_count
;
131 if (m_regs_content
.size () % m_regs_column_count
)
136 /* See tui-regs.h. */
139 tui_data_window::line_from_reg_element_no (int element_no
) const
141 if (element_no
< m_regs_content
.size ())
148 if (element_no
< m_regs_column_count
* i
)
160 /* See tui-regs.h. */
163 tui_data_window::first_reg_element_no_inline (int line_no
) const
165 if (line_no
* m_regs_column_count
<= m_regs_content
.size ())
166 return ((line_no
+ 1) * m_regs_column_count
) - m_regs_column_count
;
171 /* Show the registers of the given group in the data window
172 and refresh the window. */
174 tui_data_window::show_registers (const reggroup
*group
)
177 group
= general_reggroup
;
179 if (target_has_registers () && target_has_stack () && target_has_memory ())
181 show_register_group (group
, get_selected_frame (NULL
),
182 group
== m_current_group
);
184 /* Clear all notation of changed values. */
185 for (auto &&data_item_win
: m_regs_content
)
186 data_item_win
.highlight
= false;
187 m_current_group
= group
;
192 m_regs_content
.clear ();
199 /* Set the data window to display the registers of the register group
200 using the given frame. Values are refreshed only when
201 refresh_values_only is true. */
204 tui_data_window::show_register_group (const reggroup
*group
,
205 frame_info_ptr frame
,
206 bool refresh_values_only
)
208 struct gdbarch
*gdbarch
= get_frame_arch (frame
);
212 /* Make a new title showing which group we display. */
213 this->set_title (string_printf ("Register group: %s", group
->name ()));
215 /* See how many registers must be displayed. */
217 for (regnum
= 0; regnum
< gdbarch_num_cooked_regs (gdbarch
); regnum
++)
221 /* Must be in the group. */
222 if (!gdbarch_register_reggroup_p (gdbarch
, regnum
, group
))
225 /* If the register name is empty, it is undefined for this
226 processor, so don't display anything. */
227 name
= gdbarch_register_name (gdbarch
, regnum
);
234 m_regs_content
.resize (nr_regs
);
236 /* Now set the register names and values. */
238 for (regnum
= 0; regnum
< gdbarch_num_cooked_regs (gdbarch
); regnum
++)
240 struct tui_data_item_window
*data_item_win
;
243 /* Must be in the group. */
244 if (!gdbarch_register_reggroup_p (gdbarch
, regnum
, group
))
247 /* If the register name is empty, it is undefined for this
248 processor, so don't display anything. */
249 name
= gdbarch_register_name (gdbarch
, regnum
);
253 data_item_win
= &m_regs_content
[pos
];
254 if (!refresh_values_only
)
256 data_item_win
->regno
= regnum
;
257 data_item_win
->highlight
= false;
259 tui_get_register (frame
, data_item_win
, regnum
, 0);
264 /* See tui-regs.h. */
267 tui_data_window::display_registers_from (int start_element_no
)
270 for (auto &&data_item_win
: m_regs_content
)
272 int len
= data_item_win
.content
.size ();
277 m_item_width
= max_len
+ 1;
280 /* Mark register windows above the visible area. */
281 for (i
= 0; i
< start_element_no
; i
++)
282 m_regs_content
[i
].y
= 0;
284 m_regs_column_count
= (width
- box_size ()) / m_item_width
;
285 if (m_regs_column_count
== 0)
286 m_regs_column_count
= 1;
287 m_item_width
= (width
- box_size ()) / m_regs_column_count
;
289 /* Now create each data "sub" window, and write the display into
292 while (i
< m_regs_content
.size () && cur_y
<= height
- box_size ())
295 j
< m_regs_column_count
&& i
< m_regs_content
.size ();
298 /* Create the window if necessary. */
299 m_regs_content
[i
].x
= (m_item_width
* j
) + 1;
300 m_regs_content
[i
].y
= cur_y
;
301 m_regs_content
[i
].visible
= true;
302 m_regs_content
[i
].rerender (handle
.get (), m_item_width
);
303 i
++; /* Next register. */
305 cur_y
++; /* Next row. */
308 /* Mark register windows below the visible area. */
309 for (; i
< m_regs_content
.size (); i
++)
310 m_regs_content
[i
].y
= 0;
315 /* See tui-regs.h. */
318 tui_data_window::display_reg_element_at_line (int start_element_no
,
321 int element_no
= start_element_no
;
323 if (start_element_no
!= 0 && start_line_no
!= 0)
325 int last_line_no
, first_line_on_last_page
;
327 last_line_no
= last_regs_line_no ();
328 first_line_on_last_page
= last_line_no
- (height
- box_size ());
329 if (first_line_on_last_page
< 0)
330 first_line_on_last_page
= 0;
332 /* If the element_no causes us to scroll past the end of the
333 registers, adjust what element to really start the
335 if (start_line_no
> first_line_on_last_page
)
336 element_no
= first_reg_element_no_inline (first_line_on_last_page
);
338 display_registers_from (element_no
);
341 /* See tui-regs.h. */
344 tui_data_window::display_registers_from_line (int line_no
)
352 /* Make sure that we don't display off the end of the
354 if (line_no
>= last_regs_line_no ())
356 line_no
= line_from_reg_element_no (m_regs_content
.size () - 1);
362 element_no
= first_reg_element_no_inline (line_no
);
363 if (element_no
< m_regs_content
.size ())
364 display_reg_element_at_line (element_no
, line_no
);
372 /* Answer the index first element displayed. If none are displayed,
375 tui_data_window::first_data_item_displayed ()
377 for (int i
= 0; i
< m_regs_content
.size (); i
++)
379 if (m_regs_content
[i
].visible
)
386 /* See tui-regs.h. */
389 tui_data_window::delete_data_content_windows ()
391 for (auto &win
: m_regs_content
)
397 tui_data_window::erase_data_content (const char *prompt
)
399 werase (handle
.get ());
400 check_and_display_highlight_if_needed ();
403 int half_width
= (width
- box_size ()) / 2;
406 if (strlen (prompt
) >= half_width
)
409 x_pos
= half_width
- strlen (prompt
);
410 mvwaddstr (handle
.get (), (height
/ 2), x_pos
, (char *) prompt
);
412 tui_wrefresh (handle
.get ());
415 /* See tui-regs.h. */
418 tui_data_window::rerender ()
420 if (m_regs_content
.empty ())
421 erase_data_content (_("[ Register Values Unavailable ]"));
424 erase_data_content (NULL
);
425 delete_data_content_windows ();
426 display_registers_from (0);
431 /* Scroll the data window vertically forward or backward. */
433 tui_data_window::do_scroll_vertical (int num_to_scroll
)
435 int first_element_no
;
436 int first_line
= (-1);
438 first_element_no
= first_data_item_displayed ();
439 if (first_element_no
< m_regs_content
.size ())
440 first_line
= line_from_reg_element_no (first_element_no
);
442 { /* Calculate the first line from the element number which is in
443 the general data content. */
448 first_line
+= num_to_scroll
;
449 erase_data_content (NULL
);
450 delete_data_content_windows ();
451 display_registers_from_line (first_line
);
455 /* This function check all displayed registers for changes in values,
456 given a particular frame. If the values have changed, they are
457 updated with the new value and highlighted. */
459 tui_data_window::check_register_values (frame_info_ptr frame
)
461 if (m_regs_content
.empty ())
462 show_registers (m_current_group
);
465 for (auto &&data_item_win
: m_regs_content
)
469 was_hilighted
= data_item_win
.highlight
;
471 tui_get_register (frame
, &data_item_win
,
473 &data_item_win
.highlight
);
475 /* Register windows whose y == 0 are outside the visible area. */
476 if ((data_item_win
.highlight
|| was_hilighted
)
477 && data_item_win
.y
> 0)
478 data_item_win
.rerender (handle
.get (), m_item_width
);
482 tui_wrefresh (handle
.get ());
485 /* Display a register in a window. If hilite is TRUE, then the value
486 will be displayed in reverse video. */
488 tui_data_item_window::rerender (WINDOW
*handle
, int field_width
)
491 /* We ignore the return value, casting it to void in order to avoid
492 a compiler warning. The warning itself was introduced by a patch
493 to ncurses 5.7 dated 2009-08-29, changing this macro to expand
494 to code that causes the compiler to generate an unused-value
496 (void) wstandout (handle
);
498 mvwaddnstr (handle
, y
, x
, content
.c_str (), field_width
- 1);
499 if (content
.size () < field_width
)
500 waddstr (handle
, n_spaces (field_width
- content
.size ()));
503 /* We ignore the return value, casting it to void in order to avoid
504 a compiler warning. The warning itself was introduced by a patch
505 to ncurses 5.7 dated 2009-08-29, changing this macro to expand
506 to code that causes the compiler to generate an unused-value
508 (void) wstandend (handle
);
511 /* Helper for "tui reg next", returns the next register group after
512 CURRENT_GROUP in the register group list for GDBARCH, with wrap around
515 If CURRENT_GROUP is nullptr (e.g. if the tui register window has only
516 just been displayed and has no current group selected) or the currently
517 selected register group can't be found (e.g. if the architecture has
518 changed since the register window was last updated), then the first
519 register group will be returned. */
521 static const reggroup
*
522 tui_reg_next (const reggroup
*current_group
, struct gdbarch
*gdbarch
)
524 const std::vector
<const reggroup
*> &groups
= gdbarch_reggroups (gdbarch
);
525 auto it
= std::find (groups
.begin (), groups
.end (), current_group
);
526 if (it
!= groups
.end ())
528 if (it
== groups
.end ())
529 return groups
.front ();
533 /* Helper for "tui reg prev", returns the register group previous to
534 CURRENT_GROUP in the register group list for GDBARCH, with wrap around
537 If CURRENT_GROUP is nullptr (e.g. if the tui register window has only
538 just been displayed and has no current group selected) or the currently
539 selected register group can't be found (e.g. if the architecture has
540 changed since the register window was last updated), then the last
541 register group will be returned. */
543 static const reggroup
*
544 tui_reg_prev (const reggroup
*current_group
, struct gdbarch
*gdbarch
)
546 const std::vector
<const reggroup
*> &groups
= gdbarch_reggroups (gdbarch
);
547 auto it
= std::find (groups
.rbegin (), groups
.rend (), current_group
);
548 if (it
!= groups
.rend ())
550 if (it
== groups
.rend ())
551 return groups
.back ();
555 /* Implement the 'tui reg' command. Changes the register group displayed
556 in the tui register window. Displays the tui register window if it is
557 not already on display. */
560 tui_reg_command (const char *args
, int from_tty
)
562 struct gdbarch
*gdbarch
= get_current_arch ();
566 size_t len
= strlen (args
);
568 /* Make sure the curses mode is enabled. */
571 tui_suppress_output suppress
;
573 /* Make sure the register window is visible. If not, select an
574 appropriate layout. We need to do this before trying to run the
575 'next' or 'prev' commands. */
576 if (TUI_DATA_WIN
== NULL
|| !TUI_DATA_WIN
->is_visible ())
579 const reggroup
*match
= nullptr;
580 const reggroup
*current_group
= TUI_DATA_WIN
->get_current_group ();
581 if (strncmp (args
, "next", len
) == 0)
582 match
= tui_reg_next (current_group
, gdbarch
);
583 else if (strncmp (args
, "prev", len
) == 0)
584 match
= tui_reg_prev (current_group
, gdbarch
);
587 /* This loop matches on the initial part of a register group
588 name. If this initial part in ARGS matches only one register
589 group then the switch is made. */
590 for (const struct reggroup
*group
: gdbarch_reggroups (gdbarch
))
592 if (strncmp (group
->name (), args
, len
) == 0)
595 error (_("ambiguous register group name '%s'"), args
);
602 error (_("unknown register group '%s'"), args
);
604 TUI_DATA_WIN
->show_registers (match
);
608 gdb_printf (_("\"tui reg\" must be followed by the name of "
609 "either a register group,\nor one of 'next' "
610 "or 'prev'. Known register groups are:\n"));
613 for (const struct reggroup
*group
: gdbarch_reggroups (gdbarch
))
618 gdb_printf ("%s", group
->name ());
625 /* Complete names of register groups, and add the special "prev" and "next"
629 tui_reggroup_completer (struct cmd_list_element
*ignore
,
630 completion_tracker
&tracker
,
631 const char *text
, const char *word
)
633 static const char * const extra
[] = { "next", "prev", NULL
};
635 reggroup_completer (ignore
, tracker
, text
, word
);
637 complete_on_enum (tracker
, extra
, text
, word
);
640 void _initialize_tui_regs ();
642 _initialize_tui_regs ()
644 struct cmd_list_element
**tuicmd
, *cmd
;
646 tuicmd
= tui_get_cmd_list ();
648 cmd
= add_cmd ("reg", class_tui
, tui_reg_command
, _("\
649 TUI command to control the register window.\n\
650 Usage: tui reg NAME\n\
651 NAME is the name of the register group to display"), tuicmd
);
652 set_cmd_completer (cmd
, tui_reggroup_completer
);