1 /* TUI display registers in window.
3 Copyright (C) 1998-2019 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 static void tui_display_register (struct tui_data_item_window
*data
);
47 /* Get the register from the frame and return a printable
48 representation of it. */
50 static gdb::unique_xmalloc_ptr
<char>
51 tui_register_format (struct frame_info
*frame
, int regnum
)
53 struct gdbarch
*gdbarch
= get_frame_arch (frame
);
57 scoped_restore save_pagination
58 = make_scoped_restore (&pagination_enabled
, 0);
59 scoped_restore save_stdout
60 = make_scoped_restore (&gdb_stdout
, &stream
);
62 gdbarch_print_registers_info (gdbarch
, &stream
, frame
, regnum
, 1);
64 /* Remove the possible \n. */
65 std::string
&str
= stream
.string ();
66 if (!str
.empty () && str
.back () == '\n')
67 str
.resize (str
.size () - 1);
69 /* Expand tabs into spaces, since ncurses on MS-Windows doesn't. */
70 return tui_expand_tabs (str
.c_str ());
73 /* Get the register value from the given frame and format it for the
74 display. When changep is set, check if the new register value has
75 changed with respect to the previous call. */
77 tui_get_register (struct frame_info
*frame
,
78 struct tui_data_item_window
*data
,
79 int regnum
, bool *changedp
)
83 if (target_has_registers
)
85 gdb::unique_xmalloc_ptr
<char> new_content
86 = tui_register_format (frame
, regnum
);
89 && strcmp (data
->content
.get (), new_content
.get ()) != 0)
92 data
->content
= std::move (new_content
);
99 tui_data_window::last_regs_line_no () const
101 int num_lines
= (-1);
103 if (!regs_content
.empty ())
105 num_lines
= regs_content
.size () / regs_column_count
;
106 if (regs_content
.size () % regs_column_count
)
112 /* See tui-regs.h. */
115 tui_data_window::line_from_reg_element_no (int element_no
) const
117 if (element_no
< regs_content
.size ())
124 if (element_no
< regs_column_count
* i
)
136 /* See tui-regs.h. */
139 tui_data_window::first_reg_element_no_inline (int line_no
) const
141 if (line_no
* regs_column_count
<= regs_content
.size ())
142 return ((line_no
+ 1) * regs_column_count
) - regs_column_count
;
147 /* Show the registers of the given group in the data window
148 and refresh the window. */
150 tui_data_window::show_registers (struct reggroup
*group
)
153 group
= general_reggroup
;
155 if (target_has_registers
&& target_has_stack
&& target_has_memory
)
157 show_register_group (group
, get_selected_frame (NULL
),
158 group
== current_group
);
160 /* Clear all notation of changed values. */
161 for (auto &&data_item_win
: regs_content
)
162 data_item_win
.highlight
= false;
163 current_group
= group
;
169 erase_data_content (_("[ Register Values Unavailable ]"));
174 /* Set the data window to display the registers of the register group
175 using the given frame. Values are refreshed only when
176 refresh_values_only is TRUE. */
179 tui_data_window::show_register_group (struct reggroup
*group
,
180 struct frame_info
*frame
,
181 int refresh_values_only
)
183 struct gdbarch
*gdbarch
= get_frame_arch (frame
);
187 /* Make a new title showing which group we display. */
188 title
= string_printf ("Register group: %s", reggroup_name (group
));
190 /* See how many registers must be displayed. */
192 for (regnum
= 0; regnum
< gdbarch_num_cooked_regs (gdbarch
); regnum
++)
196 /* Must be in the group. */
197 if (!gdbarch_register_reggroup_p (gdbarch
, regnum
, group
))
200 /* If the register name is empty, it is undefined for this
201 processor, so don't display anything. */
202 name
= gdbarch_register_name (gdbarch
, regnum
);
203 if (name
== 0 || *name
== '\0')
209 regs_content
.resize (nr_regs
);
211 /* Now set the register names and values. */
213 for (regnum
= 0; regnum
< gdbarch_num_cooked_regs (gdbarch
); regnum
++)
215 struct tui_data_item_window
*data_item_win
;
218 /* Must be in the group. */
219 if (!gdbarch_register_reggroup_p (gdbarch
, regnum
, group
))
222 /* If the register name is empty, it is undefined for this
223 processor, so don't display anything. */
224 name
= gdbarch_register_name (gdbarch
, regnum
);
225 if (name
== 0 || *name
== '\0')
228 data_item_win
= ®s_content
[pos
];
231 if (!refresh_values_only
)
233 data_item_win
->item_no
= regnum
;
234 data_item_win
->name
= name
;
235 data_item_win
->highlight
= false;
237 tui_get_register (frame
, data_item_win
, regnum
, 0);
243 /* See tui-regs.h. */
246 tui_data_window::display_registers_from (int start_element_no
)
248 if (!regs_content
.empty ())
250 int j
, item_win_width
, cur_y
;
253 for (auto &&data_item_win
: regs_content
)
259 p
= data_item_win
.content
.get ();
266 item_win_width
= max_len
+ 1;
267 int i
= start_element_no
;
269 regs_column_count
= (width
- 2) / item_win_width
;
270 if (regs_column_count
== 0)
271 regs_column_count
= 1;
272 item_win_width
= (width
- 2) / regs_column_count
;
274 /* Now create each data "sub" window, and write the display into
277 while (i
< regs_content
.size ()
278 && cur_y
<= viewport_height
)
281 j
< regs_column_count
&& i
< regs_content
.size ();
284 struct tui_data_item_window
*data_item_win
;
286 /* Create the window if necessary. */
287 data_item_win
= ®s_content
[i
];
288 if (data_item_win
->handle
!= NULL
289 && (data_item_win
->height
!= 1
290 || data_item_win
->width
!= item_win_width
291 || data_item_win
->origin
.x
!= (item_win_width
* j
) + 1
292 || data_item_win
->origin
.y
!= cur_y
))
294 tui_delete_win (data_item_win
->handle
);
295 data_item_win
->handle
= 0;
298 if (data_item_win
->handle
== NULL
)
300 data_item_win
->height
= 1;
301 data_item_win
->width
= item_win_width
;
302 data_item_win
->origin
.x
= (item_win_width
* j
) + 1;
303 data_item_win
->origin
.y
= cur_y
;
304 data_item_win
->make_visible (true);
305 scrollok (data_item_win
->handle
, FALSE
);
307 touchwin (data_item_win
->handle
);
309 /* Get the printable representation of the register
311 tui_display_register (data_item_win
);
312 i
++; /* Next register. */
314 cur_y
++; /* Next row. */
319 /* See tui-regs.h. */
322 tui_data_window::display_reg_element_at_line (int start_element_no
,
325 if (!regs_content
.empty ())
327 int element_no
= start_element_no
;
329 if (start_element_no
!= 0 && start_line_no
!= 0)
331 int last_line_no
, first_line_on_last_page
;
333 last_line_no
= last_regs_line_no ();
334 first_line_on_last_page
= last_line_no
- (height
- 2);
335 if (first_line_on_last_page
< 0)
336 first_line_on_last_page
= 0;
338 /* If the element_no causes us to scroll past the end of the
339 registers, adjust what element to really start the
341 if (start_line_no
> first_line_on_last_page
)
342 element_no
= first_reg_element_no_inline (first_line_on_last_page
);
344 display_registers_from (element_no
);
348 /* See tui-regs.h. */
351 tui_data_window::display_registers_from_line (int line_no
)
353 check_and_display_highlight_if_needed ();
354 if (!regs_content
.empty ())
362 /* Make sure that we don't display off the end of the
364 if (line_no
>= last_regs_line_no ())
366 line_no
= line_from_reg_element_no (regs_content
.size () - 1);
372 element_no
= first_reg_element_no_inline (line_no
);
373 if (element_no
< regs_content
.size ())
374 display_reg_element_at_line (element_no
, line_no
);
381 return (-1); /* Nothing was displayed. */
385 /* Answer the index first element displayed. If none are displayed,
388 tui_data_window::first_data_item_displayed ()
390 for (int i
= 0; i
< regs_content
.size (); i
++)
392 struct tui_gen_win_info
*data_item_win
;
394 data_item_win
= ®s_content
[i
];
395 if (data_item_win
->is_visible ())
402 /* See tui-regs.h. */
405 tui_data_window::delete_data_content_windows ()
407 for (auto &&win
: regs_content
)
409 tui_delete_win (win
.handle
);
416 tui_data_window::erase_data_content (const char *prompt
)
419 check_and_display_highlight_if_needed ();
422 int half_width
= (width
- 2) / 2;
425 if (strlen (prompt
) >= half_width
)
428 x_pos
= half_width
- strlen (prompt
);
429 mvwaddstr (handle
, (height
/ 2), x_pos
, (char *) prompt
);
434 /* See tui-regs.h. */
437 tui_data_window::display_all_data ()
439 if (regs_content
.empty ())
440 erase_data_content (NO_DATA_STRING
);
443 erase_data_content (NULL
);
444 delete_data_content_windows ();
445 check_and_display_highlight_if_needed ();
446 display_registers_from (0);
451 /* Function to redisplay the contents of the data window. */
453 tui_data_window::refresh_all ()
455 erase_data_content (NULL
);
456 if (!regs_content
.empty ())
458 int first_element
= first_data_item_displayed ();
460 if (first_element
>= 0) /* Re-use existing windows. */
462 int first_line
= (-1);
464 if (first_element
< regs_content
.size ())
465 first_line
= line_from_reg_element_no (first_element
);
469 erase_data_content (NULL
);
470 display_registers_from_line (first_line
);
477 /* Scroll the data window vertically forward or backward. */
479 tui_data_window::do_scroll_vertical (int num_to_scroll
)
481 int first_element_no
;
482 int first_line
= (-1);
484 first_element_no
= first_data_item_displayed ();
485 if (first_element_no
< regs_content
.size ())
486 first_line
= line_from_reg_element_no (first_element_no
);
488 { /* Calculate the first line from the element number which is in
489 the general data content. */
494 first_line
+= num_to_scroll
;
495 erase_data_content (NULL
);
496 delete_data_content_windows ();
497 display_registers_from_line (first_line
);
501 /* See tui-regs.h. */
504 tui_data_window::rerender ()
506 /* Delete all data item windows. */
507 for (auto &&win
: regs_content
)
509 tui_delete_win (win
.handle
);
515 /* See tui-regs.h. */
518 tui_data_window::refresh_window ()
520 tui_gen_win_info::refresh_window ();
521 for (auto &&win
: regs_content
)
522 win
.refresh_window ();
525 /* This function check all displayed registers for changes in values,
526 given a particular frame. If the values have changed, they are
527 updated with the new value and highlighted. */
529 tui_data_window::check_register_values (struct frame_info
*frame
)
531 if (regs_content
.empty ())
532 show_registers (current_group
);
535 for (auto &&data_item_win
: regs_content
)
539 was_hilighted
= data_item_win
.highlight
;
541 tui_get_register (frame
, &data_item_win
,
542 data_item_win
.item_no
,
543 &data_item_win
.highlight
);
545 if (data_item_win
.highlight
|| was_hilighted
)
546 tui_display_register (&data_item_win
);
551 /* Display a register in a window. If hilite is TRUE, then the value
552 will be displayed in reverse video. */
554 tui_display_register (struct tui_data_item_window
*data
)
556 if (data
->handle
!= NULL
)
561 /* We ignore the return value, casting it to void in order to avoid
562 a compiler warning. The warning itself was introduced by a patch
563 to ncurses 5.7 dated 2009-08-29, changing this macro to expand
564 to code that causes the compiler to generate an unused-value
566 (void) wstandout (data
->handle
);
568 wmove (data
->handle
, 0, 0);
569 for (i
= 1; i
< data
->width
; i
++)
570 waddch (data
->handle
, ' ');
571 wmove (data
->handle
, 0, 0);
573 waddstr (data
->handle
, data
->content
.get ());
576 /* We ignore the return value, casting it to void in order to avoid
577 a compiler warning. The warning itself was introduced by a patch
578 to ncurses 5.7 dated 2009-08-29, changing this macro to expand
579 to code that causes the compiler to generate an unused-value
581 (void) wstandend (data
->handle
);
582 data
->refresh_window ();
586 /* Helper for "tui reg next", wraps a call to REGGROUP_NEXT, but adds wrap
587 around behaviour. Returns the next register group, or NULL if the
588 register window is not currently being displayed. */
590 static struct reggroup
*
591 tui_reg_next (struct reggroup
*current_group
, struct gdbarch
*gdbarch
)
593 struct reggroup
*group
= NULL
;
595 if (current_group
!= NULL
)
597 group
= reggroup_next (gdbarch
, current_group
);
599 group
= reggroup_next (gdbarch
, NULL
);
604 /* Helper for "tui reg prev", wraps a call to REGGROUP_PREV, but adds wrap
605 around behaviour. Returns the previous register group, or NULL if the
606 register window is not currently being displayed. */
608 static struct reggroup
*
609 tui_reg_prev (struct reggroup
*current_group
, struct gdbarch
*gdbarch
)
611 struct reggroup
*group
= NULL
;
613 if (current_group
!= NULL
)
615 group
= reggroup_prev (gdbarch
, current_group
);
617 group
= reggroup_prev (gdbarch
, NULL
);
622 /* A helper function to display the register window in the appropriate
628 enum tui_layout_type cur_layout
= tui_current_layout ();
629 enum tui_layout_type new_layout
;
630 if (cur_layout
== SRC_COMMAND
|| cur_layout
== SRC_DATA_COMMAND
)
631 new_layout
= SRC_DATA_COMMAND
;
633 new_layout
= DISASSEM_DATA_COMMAND
;
634 tui_set_layout (new_layout
);
637 /* Implement the 'tui reg' command. Changes the register group displayed
638 in the tui register window. Displays the tui register window if it is
639 not already on display. */
642 tui_reg_command (const char *args
, int from_tty
)
644 struct gdbarch
*gdbarch
= get_current_arch ();
648 struct reggroup
*group
, *match
= NULL
;
649 size_t len
= strlen (args
);
651 /* Make sure the curses mode is enabled. */
654 /* Make sure the register window is visible. If not, select an
655 appropriate layout. We need to do this before trying to run the
656 'next' or 'prev' commands. */
657 if (TUI_DATA_WIN
== NULL
|| !TUI_DATA_WIN
->is_visible ())
660 struct reggroup
*current_group
= TUI_DATA_WIN
->current_group
;
661 if (strncmp (args
, "next", len
) == 0)
662 match
= tui_reg_next (current_group
, gdbarch
);
663 else if (strncmp (args
, "prev", len
) == 0)
664 match
= tui_reg_prev (current_group
, gdbarch
);
666 /* This loop matches on the initial part of a register group
667 name. If this initial part in ARGS matches only one register
668 group then the switch is made. */
669 for (group
= reggroup_next (gdbarch
, NULL
);
671 group
= reggroup_next (gdbarch
, group
))
673 if (strncmp (reggroup_name (group
), args
, len
) == 0)
676 error (_("ambiguous register group name '%s'"), args
);
682 error (_("unknown register group '%s'"), args
);
684 TUI_DATA_WIN
->show_registers (match
);
688 struct reggroup
*group
;
691 printf_unfiltered (_("\"tui reg\" must be followed by the name of "
692 "either a register group,\nor one of 'next' "
693 "or 'prev'. Known register groups are:\n"));
695 for (first
= 1, group
= reggroup_next (gdbarch
, NULL
);
697 first
= 0, group
= reggroup_next (gdbarch
, group
))
700 printf_unfiltered (", ");
701 printf_unfiltered ("%s", reggroup_name (group
));
704 printf_unfiltered ("\n");
708 /* Complete names of register groups, and add the special "prev" and "next"
712 tui_reggroup_completer (struct cmd_list_element
*ignore
,
713 completion_tracker
&tracker
,
714 const char *text
, const char *word
)
716 static const char *extra
[] = { "next", "prev", NULL
};
717 size_t len
= strlen (word
);
720 reggroup_completer (ignore
, tracker
, text
, word
);
722 /* XXXX use complete_on_enum instead? */
723 for (tmp
= extra
; *tmp
!= NULL
; ++tmp
)
725 if (strncmp (word
, *tmp
, len
) == 0)
726 tracker
.add_completion (make_unique_xstrdup (*tmp
));
731 _initialize_tui_regs (void)
733 struct cmd_list_element
**tuicmd
, *cmd
;
735 tuicmd
= tui_get_cmd_list ();
737 cmd
= add_cmd ("reg", class_tui
, tui_reg_command
, _("\
738 TUI command to control the register window."), tuicmd
);
739 set_cmd_completer (cmd
, tui_reggroup_completer
);