1 /* TUI display registers in window.
3 Copyright (C) 1998-2024 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/>. */
22 #include "arch-utils.h"
24 #include "tui/tui-data.h"
27 #include "cli/cli-cmds.h"
32 #include "tui/tui-layout.h"
33 #include "tui/tui-win.h"
34 #include "tui/tui-wingeneral.h"
35 #include "tui/tui-file.h"
36 #include "tui/tui-regs.h"
37 #include "tui/tui-io.h"
38 #include "reggroups.h"
40 #include "completer.h"
42 #include "gdb_curses.h"
44 /* A subclass of string_file that expands tab characters. */
45 class tab_expansion_file
: public string_file
49 tab_expansion_file () = default;
51 void write (const char *buf
, long length_buf
) override
;
59 tab_expansion_file::write (const char *buf
, long length_buf
)
61 for (long i
= 0; i
< length_buf
; ++i
)
67 string_file::write (" ", 1);
70 while ((m_column
% 8) != 0);
74 string_file::write (&buf
[i
], 1);
83 /* Get the register from the frame and return a printable
84 representation of it. */
87 tui_register_format (const frame_info_ptr
&frame
, int regnum
)
89 struct gdbarch
*gdbarch
= get_frame_arch (frame
);
91 /* Expand tabs into spaces, since ncurses on MS-Windows doesn't. */
92 tab_expansion_file stream
;
93 gdbarch_print_registers_info (gdbarch
, &stream
, frame
, regnum
, 1);
95 /* Remove the possible \n. */
96 std::string str
= stream
.release ();
97 if (!str
.empty () && str
.back () == '\n')
103 /* Compute the register value from the given frame and format it for
104 the display. update 'content' and set 'highlight' if the contents
107 tui_register_info::update (const frame_info_ptr
&frame
)
109 std::string new_content
= tui_register_format (frame
, m_regno
);
110 highlight
= content
!= new_content
;
111 content
= std::move (new_content
);
114 /* See tui-regs.h. */
117 tui_data_window::last_regs_line_no () const
119 int num_lines
= m_regs_content
.size () / m_regs_column_count
;
120 if (m_regs_content
.size () % m_regs_column_count
)
125 /* See tui-regs.h. */
128 tui_data_window::line_from_reg_element_no (int element_no
) const
130 if (element_no
< m_regs_content
.size ())
137 if (element_no
< m_regs_column_count
* i
)
149 /* See tui-regs.h. */
152 tui_data_window::first_reg_element_no_inline (int line_no
) const
154 if (line_no
* m_regs_column_count
<= m_regs_content
.size ())
155 return ((line_no
+ 1) * m_regs_column_count
) - m_regs_column_count
;
160 /* Show the registers of the given group in the data window
161 and refresh the window. */
163 tui_data_window::set_register_group (const reggroup
*group
)
165 update_register_data (group
);
169 /* Set the data window to display the registers of the register group
170 using the given frame. */
173 tui_data_window::update_register_data (const reggroup
*group
)
175 if (group
== nullptr)
176 group
= general_reggroup
;
178 if (!target_has_registers ()
179 || !target_has_stack ()
180 || !target_has_memory ())
182 set_title (_("Registers"));
183 m_current_group
= nullptr;
185 m_regs_content
.clear ();
189 frame_info_ptr frame
= get_selected_frame (nullptr);
190 struct gdbarch
*gdbarch
= get_frame_arch (frame
);
192 if (m_current_group
== group
&& m_gdbarch
== gdbarch
)
194 /* Nothing to do here. */
198 m_current_group
= group
;
201 /* Make a new title showing which group we display. */
202 this->set_title (string_printf ("Register group: %s", group
->name ()));
204 /* Create the registers. */
205 m_regs_content
.clear ();
208 regnum
< gdbarch_num_cooked_regs (gdbarch
);
211 /* Must be in the group. */
212 if (!gdbarch_register_reggroup_p (gdbarch
, regnum
, group
))
215 /* If the register name is empty, it is undefined for this
216 processor, so don't display anything. */
217 const char *name
= gdbarch_register_name (gdbarch
, regnum
);
221 m_regs_content
.emplace_back (regnum
, frame
);
225 /* See tui-regs.h. */
228 tui_data_window::display_registers_from (int start_element_no
)
230 werase (handle
.get ());
231 check_and_display_highlight_if_needed ();
233 /* In case the regs window is not boxed, we'll write the last char in the
234 last line here, causing a scroll, so prevent that. */
235 scrollok (handle
.get (), FALSE
);
238 for (auto &&data_item_win
: m_regs_content
)
240 int len
= data_item_win
.content
.size ();
245 m_item_width
= max_len
+ 1;
248 /* Mark register windows above the visible area. */
249 for (i
= 0; i
< start_element_no
; i
++)
250 m_regs_content
[i
].y
= 0;
252 m_regs_column_count
= (width
- box_size ()) / m_item_width
;
253 if (m_regs_column_count
== 0)
254 m_regs_column_count
= 1;
255 m_item_width
= (width
- box_size ()) / m_regs_column_count
;
257 /* Now create each data "sub" window, and write the display into
259 int cur_y
= box_width ();
260 while (i
< m_regs_content
.size () && cur_y
<= height
- box_size ())
263 j
< m_regs_column_count
&& i
< m_regs_content
.size ();
266 /* Create the window if necessary. */
267 m_regs_content
[i
].x
= box_width () + (m_item_width
* j
);
268 m_regs_content
[i
].y
= cur_y
;
269 m_regs_content
[i
].rerender (handle
.get (), m_item_width
);
270 i
++; /* Next register. */
272 cur_y
++; /* Next row. */
275 /* Mark register windows below the visible area. */
276 for (; i
< m_regs_content
.size (); i
++)
277 m_regs_content
[i
].y
= 0;
282 /* See tui-regs.h. */
285 tui_data_window::display_reg_element_at_line (int start_element_no
,
288 int element_no
= start_element_no
;
290 if (start_element_no
!= 0 && start_line_no
!= 0)
292 int last_line_no
, first_line_on_last_page
;
294 last_line_no
= last_regs_line_no ();
295 first_line_on_last_page
= last_line_no
- (height
- box_size ());
296 if (first_line_on_last_page
< 0)
297 first_line_on_last_page
= 0;
299 /* If the element_no causes us to scroll past the end of the
300 registers, adjust what element to really start the
302 if (start_line_no
> first_line_on_last_page
)
303 element_no
= first_reg_element_no_inline (first_line_on_last_page
);
305 display_registers_from (element_no
);
308 /* See tui-regs.h. */
311 tui_data_window::display_registers_from_line (int line_no
)
319 /* Make sure that we don't display off the end of the
321 if (line_no
>= last_regs_line_no ())
323 line_no
= line_from_reg_element_no (m_regs_content
.size () - 1);
329 element_no
= first_reg_element_no_inline (line_no
);
330 if (element_no
< m_regs_content
.size ())
331 display_reg_element_at_line (element_no
, line_no
);
339 /* Answer the index first element displayed. If none are displayed,
342 tui_data_window::first_data_item_displayed ()
344 for (int i
= 0; i
< m_regs_content
.size (); i
++)
346 if (m_regs_content
[i
].visible ())
354 tui_data_window::erase_data_content ()
356 center_string (_("[ Register Values Unavailable ]"));
359 /* See tui-regs.h. */
362 tui_data_window::rerender ()
364 if (m_regs_content
.empty ())
365 erase_data_content ();
367 display_registers_from (0);
368 tui_wrefresh (handle
.get ());
372 /* Scroll the data window vertically forward or backward. */
374 tui_data_window::do_scroll_vertical (int num_to_scroll
)
376 int first_element_no
;
377 int first_line
= (-1);
379 first_element_no
= first_data_item_displayed ();
380 if (first_element_no
< m_regs_content
.size ())
381 first_line
= line_from_reg_element_no (first_element_no
);
383 { /* Calculate the first line from the element number which is in
384 the general data content. */
389 first_line
+= num_to_scroll
;
390 display_registers_from_line (first_line
);
394 /* This function check all displayed registers for changes in values,
395 given a particular frame. If the values have changed, they are
396 updated with the new value and highlighted. */
398 tui_data_window::check_register_values (const frame_info_ptr
&frame
)
400 if (frame
== nullptr)
401 set_register_group (nullptr);
404 /* If the frame architecture changed, we need to reset the
406 struct gdbarch
*gdbarch
= get_frame_arch (frame
);
407 if (gdbarch
!= m_gdbarch
)
408 set_register_group (nullptr);
411 for (tui_register_info
&data_item_win
: m_regs_content
)
413 bool was_hilighted
= data_item_win
.highlight
;
415 data_item_win
.update (frame
);
417 /* Register windows whose y == 0 are outside the visible area. */
418 if ((data_item_win
.highlight
|| was_hilighted
)
419 && data_item_win
.visible ())
420 data_item_win
.rerender (handle
.get (), m_item_width
);
423 tui_wrefresh (handle
.get ());
427 /* Display a register in a window. If hilite is TRUE, then the value
428 will be displayed in reverse video. */
430 tui_register_info::rerender (WINDOW
*handle
, int field_width
)
433 /* We ignore the return value, casting it to void in order to avoid
434 a compiler warning. The warning itself was introduced by a patch
435 to ncurses 5.7 dated 2009-08-29, changing this macro to expand
436 to code that causes the compiler to generate an unused-value
438 (void) wstandout (handle
);
440 mvwaddnstr (handle
, y
, x
, content
.c_str (), field_width
- 1);
441 if (content
.size () < field_width
)
442 waddstr (handle
, n_spaces (field_width
- content
.size ()));
445 /* We ignore the return value, casting it to void in order to avoid
446 a compiler warning. The warning itself was introduced by a patch
447 to ncurses 5.7 dated 2009-08-29, changing this macro to expand
448 to code that causes the compiler to generate an unused-value
450 (void) wstandend (handle
);
453 /* Helper for "tui reg next", returns the next register group after
454 CURRENT_GROUP in the register group list for GDBARCH, with wrap around
457 If CURRENT_GROUP is nullptr (e.g. if the tui register window has only
458 just been displayed and has no current group selected) or the currently
459 selected register group can't be found (e.g. if the architecture has
460 changed since the register window was last updated), then the first
461 register group will be returned. */
463 static const reggroup
*
464 tui_reg_next (const reggroup
*current_group
, struct gdbarch
*gdbarch
)
466 const std::vector
<const reggroup
*> &groups
= gdbarch_reggroups (gdbarch
);
467 auto it
= std::find (groups
.begin (), groups
.end (), current_group
);
468 if (it
!= groups
.end ())
470 if (it
== groups
.end ())
471 return groups
.front ();
475 /* Helper for "tui reg prev", returns the register group previous to
476 CURRENT_GROUP in the register group list for GDBARCH, with wrap around
479 If CURRENT_GROUP is nullptr (e.g. if the tui register window has only
480 just been displayed and has no current group selected) or the currently
481 selected register group can't be found (e.g. if the architecture has
482 changed since the register window was last updated), then the last
483 register group will be returned. */
485 static const reggroup
*
486 tui_reg_prev (const reggroup
*current_group
, struct gdbarch
*gdbarch
)
488 const std::vector
<const reggroup
*> &groups
= gdbarch_reggroups (gdbarch
);
489 auto it
= std::find (groups
.rbegin (), groups
.rend (), current_group
);
490 if (it
!= groups
.rend ())
492 if (it
== groups
.rend ())
493 return groups
.back ();
497 /* Implement the 'tui reg' command. Changes the register group displayed
498 in the tui register window. Displays the tui register window if it is
499 not already on display. */
502 tui_reg_command (const char *args
, int from_tty
)
504 struct gdbarch
*gdbarch
= get_current_arch ();
508 size_t len
= strlen (args
);
510 /* Make sure the curses mode is enabled. */
513 tui_suppress_output suppress
;
515 /* Make sure the register window is visible. If not, select an
516 appropriate layout. We need to do this before trying to run the
517 'next' or 'prev' commands. */
518 if (TUI_DATA_WIN
== NULL
|| !TUI_DATA_WIN
->is_visible ())
521 const reggroup
*match
= nullptr;
522 const reggroup
*current_group
= TUI_DATA_WIN
->get_current_group ();
523 if (strncmp (args
, "next", len
) == 0)
524 match
= tui_reg_next (current_group
, gdbarch
);
525 else if (strncmp (args
, "prev", len
) == 0)
526 match
= tui_reg_prev (current_group
, gdbarch
);
529 /* This loop matches on the initial part of a register group
530 name. If this initial part in ARGS matches only one register
531 group then the switch is made. */
532 for (const struct reggroup
*group
: gdbarch_reggroups (gdbarch
))
534 if (strncmp (group
->name (), args
, len
) == 0)
537 error (_("ambiguous register group name '%s'"), args
);
544 error (_("unknown register group '%s'"), args
);
546 TUI_DATA_WIN
->set_register_group (match
);
550 gdb_printf (_("\"tui reg\" must be followed by the name of "
551 "either a register group,\nor one of 'next' "
552 "or 'prev'. Known register groups are:\n"));
555 for (const struct reggroup
*group
: gdbarch_reggroups (gdbarch
))
560 gdb_printf ("%s", group
->name ());
567 /* Complete names of register groups, and add the special "prev" and "next"
571 tui_reggroup_completer (struct cmd_list_element
*ignore
,
572 completion_tracker
&tracker
,
573 const char *text
, const char *word
)
575 static const char * const extra
[] = { "next", "prev", NULL
};
577 reggroup_completer (ignore
, tracker
, text
, word
);
579 complete_on_enum (tracker
, extra
, text
, word
);
582 void _initialize_tui_regs ();
584 _initialize_tui_regs ()
586 struct cmd_list_element
**tuicmd
, *cmd
;
588 tuicmd
= tui_get_cmd_list ();
590 cmd
= add_cmd ("reg", class_tui
, tui_reg_command
, _("\
591 TUI command to control the register window.\n\
592 Usage: tui reg NAME\n\
593 NAME is the name of the register group to display"), tuicmd
);
594 set_cmd_completer (cmd
, tui_reggroup_completer
);