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-windata.h"
36 #include "tui/tui-wingeneral.h"
37 #include "tui/tui-file.h"
38 #include "tui/tui-regs.h"
39 #include "tui/tui-io.h"
40 #include "reggroups.h"
42 #include "completer.h"
44 #include "gdb_curses.h"
47 /*****************************************
48 ** STATIC LOCAL FUNCTIONS FORWARD DECLS **
49 ******************************************/
50 static void tui_display_register (struct tui_data_item_window
*data
);
52 static void tui_show_register_group (struct reggroup
*group
,
53 struct frame_info
*frame
,
54 int refresh_values_only
);
56 static enum tui_status
tui_get_register (struct frame_info
*frame
,
57 struct tui_data_item_window
*data
,
58 int regnum
, bool *changedp
);
62 /*****************************************
63 ** PUBLIC FUNCTIONS **
64 ******************************************/
69 tui_data_window::last_regs_line_no () const
73 if (!regs_content
.empty ())
75 num_lines
= regs_content
.size () / regs_column_count
;
76 if (regs_content
.size () % regs_column_count
)
85 tui_data_window::line_from_reg_element_no (int element_no
) const
87 if (element_no
< regs_content
.size ())
94 if (element_no
< regs_column_count
* i
)
107 /* Answer the index of the first element in line_no. If line_no is
108 past the register area (-1) is returned. */
110 tui_first_reg_element_no_inline (int line_no
)
112 if ((line_no
* TUI_DATA_WIN
->regs_column_count
)
113 <= TUI_DATA_WIN
->regs_content
.size ())
114 return (((line_no
+ 1) * TUI_DATA_WIN
->regs_column_count
)
115 - TUI_DATA_WIN
->regs_column_count
);
121 /* Show the registers of the given group in the data window
122 and refresh the window. */
124 tui_show_registers (struct reggroup
*group
)
126 enum tui_status ret
= TUI_FAILURE
;
128 /* Make sure the curses mode is enabled. */
131 /* Make sure the register window is visible. If not, select an
132 appropriate layout. */
133 if (TUI_DATA_WIN
== NULL
|| !TUI_DATA_WIN
->is_visible
)
134 tui_set_layout_by_name (DATA_NAME
);
137 group
= general_reggroup
;
139 /* Say that registers should be displayed, even if there is a
141 TUI_DATA_WIN
->display_regs
= true;
143 if (target_has_registers
&& target_has_stack
&& target_has_memory
)
145 tui_show_register_group (group
, get_selected_frame (NULL
),
146 group
== TUI_DATA_WIN
->current_group
);
149 if (ret
== TUI_FAILURE
)
151 TUI_DATA_WIN
->current_group
= 0;
152 tui_erase_data_content (NO_REGS_STRING
);
156 /* Clear all notation of changed values. */
157 for (auto &&data_item_win
: TUI_DATA_WIN
->regs_content
)
159 if (data_item_win
!= nullptr)
160 data_item_win
->highlight
= false;
162 TUI_DATA_WIN
->current_group
= group
;
163 tui_display_all_data ();
168 /* Set the data window to display the registers of the register group
169 using the given frame. Values are refreshed only when
170 refresh_values_only is TRUE. */
173 tui_show_register_group (struct reggroup
*group
,
174 struct frame_info
*frame
,
175 int refresh_values_only
)
177 struct gdbarch
*gdbarch
= get_frame_arch (frame
);
182 /* Make a new title showing which group we display. */
183 snprintf (title
, sizeof (title
) - 1, "Register group: %s",
184 reggroup_name (group
));
185 xfree (TUI_DATA_WIN
->title
);
186 TUI_DATA_WIN
->title
= xstrdup (title
);
188 /* See how many registers must be displayed. */
190 for (regnum
= 0; regnum
< gdbarch_num_cooked_regs (gdbarch
); regnum
++)
194 /* Must be in the group. */
195 if (!gdbarch_register_reggroup_p (gdbarch
, regnum
, group
))
198 /* If the register name is empty, it is undefined for this
199 processor, so don't display anything. */
200 name
= gdbarch_register_name (gdbarch
, regnum
);
201 if (name
== 0 || *name
== '\0')
207 if (!refresh_values_only
)
208 TUI_DATA_WIN
->regs_content
.clear ();
210 if (nr_regs
< TUI_DATA_WIN
->regs_content
.size ())
211 TUI_DATA_WIN
->regs_content
.resize (nr_regs
);
214 for (int i
= TUI_DATA_WIN
->regs_content
.size (); i
< nr_regs
; ++i
)
215 TUI_DATA_WIN
->regs_content
.emplace_back (new tui_data_item_window ());
218 /* Now set the register names and values. */
220 for (regnum
= 0; regnum
< gdbarch_num_cooked_regs (gdbarch
); regnum
++)
222 struct tui_data_item_window
*data_item_win
;
225 /* Must be in the group. */
226 if (!gdbarch_register_reggroup_p (gdbarch
, regnum
, group
))
229 /* If the register name is empty, it is undefined for this
230 processor, so don't display anything. */
231 name
= gdbarch_register_name (gdbarch
, regnum
);
232 if (name
== 0 || *name
== '\0')
235 data_item_win
= TUI_DATA_WIN
->regs_content
[pos
].get ();
238 if (!refresh_values_only
)
240 data_item_win
->item_no
= regnum
;
241 data_item_win
->name
= name
;
242 data_item_win
->highlight
= false;
244 tui_get_register (frame
, data_item_win
, regnum
, 0);
250 /* Function to display the registers in the content from
251 'start_element_no' until the end of the register content or the end
252 of the display height. No checking for displaying past the end of
253 the registers is done here. */
255 tui_display_registers_from (int start_element_no
)
257 if (!TUI_DATA_WIN
->regs_content
.empty ())
259 int j
, item_win_width
, cur_y
;
262 for (auto &&data_item_win
: TUI_DATA_WIN
->regs_content
)
268 p
= data_item_win
->content
;
273 len
= 8 * ((len
/ 8) + 1);
281 item_win_width
= max_len
+ 1;
282 int i
= start_element_no
;
284 TUI_DATA_WIN
->regs_column_count
=
285 (TUI_DATA_WIN
->width
- 2) / item_win_width
;
286 if (TUI_DATA_WIN
->regs_column_count
== 0)
287 TUI_DATA_WIN
->regs_column_count
= 1;
289 (TUI_DATA_WIN
->width
- 2) / TUI_DATA_WIN
->regs_column_count
;
291 /* Now create each data "sub" window, and write the display into
294 while (i
< TUI_DATA_WIN
->regs_content
.size ()
295 && cur_y
<= TUI_DATA_WIN
->viewport_height
)
298 j
< TUI_DATA_WIN
->regs_column_count
299 && i
< TUI_DATA_WIN
->regs_content
.size ();
302 struct tui_data_item_window
*data_item_win
;
304 /* Create the window if necessary. */
305 data_item_win
= TUI_DATA_WIN
->regs_content
[i
].get ();
306 if (data_item_win
->handle
!= NULL
307 && (data_item_win
->height
!= 1
308 || data_item_win
->width
!= item_win_width
309 || data_item_win
->origin
.x
!= (item_win_width
* j
) + 1
310 || data_item_win
->origin
.y
!= cur_y
))
312 tui_delete_win (data_item_win
->handle
);
313 data_item_win
->handle
= 0;
316 if (data_item_win
->handle
== NULL
)
318 data_item_win
->height
= 1;
319 data_item_win
->width
= item_win_width
;
320 data_item_win
->origin
.x
= (item_win_width
* j
) + 1;
321 data_item_win
->origin
.y
= cur_y
;
322 tui_make_window (data_item_win
, DONT_BOX_WINDOW
);
323 scrollok (data_item_win
->handle
, FALSE
);
325 touchwin (data_item_win
->handle
);
327 /* Get the printable representation of the register
329 tui_display_register (data_item_win
);
330 i
++; /* Next register. */
332 cur_y
++; /* Next row. */
338 /* Function to display the registers in the content from
339 'start_element_no' on 'start_line_no' until the end of the register
340 content or the end of the display height. This function checks
341 that we won't display off the end of the register display. */
343 tui_display_reg_element_at_line (int start_element_no
,
346 if (!TUI_DATA_WIN
->regs_content
.empty ())
348 int element_no
= start_element_no
;
350 if (start_element_no
!= 0 && start_line_no
!= 0)
352 int last_line_no
, first_line_on_last_page
;
354 last_line_no
= TUI_DATA_WIN
->last_regs_line_no ();
355 first_line_on_last_page
356 = last_line_no
- (TUI_DATA_WIN
->height
- 2);
357 if (first_line_on_last_page
< 0)
358 first_line_on_last_page
= 0;
360 /* If the element_no causes us to scroll past the end of the
361 registers, adjust what element to really start the
363 if (start_line_no
> first_line_on_last_page
)
365 = tui_first_reg_element_no_inline (first_line_on_last_page
);
367 tui_display_registers_from (element_no
);
373 /* Function to display the registers starting at line line_no in the
374 data window. Answers the line number that the display actually
375 started from. If nothing is displayed (-1) is returned. */
377 tui_display_registers_from_line (int line_no
,
380 if (!TUI_DATA_WIN
->regs_content
.empty ())
382 int line
, element_no
;
386 else if (force_display
)
387 { /* If we must display regs (force_display is true), then
388 make sure that we don't display off the end of the
390 if (line_no
>= TUI_DATA_WIN
->last_regs_line_no ())
392 if ((line
= TUI_DATA_WIN
->line_from_reg_element_no (
393 TUI_DATA_WIN
->regs_content
.size () - 1)) < 0)
402 element_no
= tui_first_reg_element_no_inline (line
);
403 if (element_no
< TUI_DATA_WIN
->regs_content
.size ())
404 tui_display_reg_element_at_line (element_no
, line
);
411 return (-1); /* Nothing was displayed. */
415 /* This function check all displayed registers for changes in values,
416 given a particular frame. If the values have changed, they are
417 updated with the new value and highlighted. */
419 tui_check_register_values (struct frame_info
*frame
)
421 if (TUI_DATA_WIN
!= NULL
422 && TUI_DATA_WIN
->is_visible
)
424 if (TUI_DATA_WIN
->regs_content
.empty ()
425 && TUI_DATA_WIN
->display_regs
)
426 tui_show_registers (TUI_DATA_WIN
->current_group
);
429 for (auto &&data_item_win_ptr
: TUI_DATA_WIN
->regs_content
)
433 was_hilighted
= data_item_win_ptr
->highlight
;
435 tui_get_register (frame
, data_item_win_ptr
.get (),
436 data_item_win_ptr
->item_no
,
437 &data_item_win_ptr
->highlight
);
439 if (data_item_win_ptr
->highlight
|| was_hilighted
)
440 tui_display_register (data_item_win_ptr
.get ());
446 /* Display a register in a window. If hilite is TRUE, then the value
447 will be displayed in reverse video. */
449 tui_display_register (struct tui_data_item_window
*data
)
451 if (data
->handle
!= NULL
)
456 /* We ignore the return value, casting it to void in order to avoid
457 a compiler warning. The warning itself was introduced by a patch
458 to ncurses 5.7 dated 2009-08-29, changing this macro to expand
459 to code that causes the compiler to generate an unused-value
461 (void) wstandout (data
->handle
);
463 wmove (data
->handle
, 0, 0);
464 for (i
= 1; i
< data
->width
; i
++)
465 waddch (data
->handle
, ' ');
466 wmove (data
->handle
, 0, 0);
468 waddstr (data
->handle
, data
->content
);
471 /* We ignore the return value, casting it to void in order to avoid
472 a compiler warning. The warning itself was introduced by a patch
473 to ncurses 5.7 dated 2009-08-29, changing this macro to expand
474 to code that causes the compiler to generate an unused-value
476 (void) wstandend (data
->handle
);
477 data
->refresh_window ();
481 /* Helper for "tui reg next", wraps a call to REGGROUP_NEXT, but adds wrap
482 around behaviour. Returns the next register group, or NULL if the
483 register window is not currently being displayed. */
485 static struct reggroup
*
486 tui_reg_next (struct gdbarch
*gdbarch
)
488 struct reggroup
*group
= NULL
;
490 if (TUI_DATA_WIN
!= NULL
)
492 group
= TUI_DATA_WIN
->current_group
;
493 group
= reggroup_next (gdbarch
, group
);
495 group
= reggroup_next (gdbarch
, NULL
);
500 /* Helper for "tui reg prev", wraps a call to REGGROUP_PREV, but adds wrap
501 around behaviour. Returns the previous register group, or NULL if the
502 register window is not currently being displayed. */
504 static struct reggroup
*
505 tui_reg_prev (struct gdbarch
*gdbarch
)
507 struct reggroup
*group
= NULL
;
509 if (TUI_DATA_WIN
!= NULL
)
511 group
= TUI_DATA_WIN
->current_group
;
512 group
= reggroup_prev (gdbarch
, group
);
514 group
= reggroup_prev (gdbarch
, NULL
);
519 /* Implement the 'tui reg' command. Changes the register group displayed
520 in the tui register window. Displays the tui register window if it is
521 not already on display. */
524 tui_reg_command (const char *args
, int from_tty
)
526 struct gdbarch
*gdbarch
= get_current_arch ();
530 struct reggroup
*group
, *match
= NULL
;
531 size_t len
= strlen (args
);
533 /* Make sure the curses mode is enabled. */
536 /* Make sure the register window is visible. If not, select an
537 appropriate layout. We need to do this before trying to run the
538 'next' or 'prev' commands. */
539 if (TUI_DATA_WIN
== NULL
|| !TUI_DATA_WIN
->is_visible
)
540 tui_set_layout_by_name (DATA_NAME
);
542 if (strncmp (args
, "next", len
) == 0)
543 match
= tui_reg_next (gdbarch
);
544 else if (strncmp (args
, "prev", len
) == 0)
545 match
= tui_reg_prev (gdbarch
);
547 /* This loop matches on the initial part of a register group
548 name. If this initial part in ARGS matches only one register
549 group then the switch is made. */
550 for (group
= reggroup_next (gdbarch
, NULL
);
552 group
= reggroup_next (gdbarch
, group
))
554 if (strncmp (reggroup_name (group
), args
, len
) == 0)
557 error (_("ambiguous register group name '%s'"), args
);
563 error (_("unknown register group '%s'"), args
);
565 tui_show_registers (match
);
569 struct reggroup
*group
;
572 printf_unfiltered (_("\"tui reg\" must be followed by the name of "
573 "either a register group,\nor one of 'next' "
574 "or 'prev'. Known register groups are:\n"));
576 for (first
= 1, group
= reggroup_next (gdbarch
, NULL
);
578 first
= 0, group
= reggroup_next (gdbarch
, group
))
581 printf_unfiltered (", ");
582 printf_unfiltered ("%s", reggroup_name (group
));
585 printf_unfiltered ("\n");
589 /* Complete names of register groups, and add the special "prev" and "next"
593 tui_reggroup_completer (struct cmd_list_element
*ignore
,
594 completion_tracker
&tracker
,
595 const char *text
, const char *word
)
597 static const char *extra
[] = { "next", "prev", NULL
};
598 size_t len
= strlen (word
);
601 reggroup_completer (ignore
, tracker
, text
, word
);
603 /* XXXX use complete_on_enum instead? */
604 for (tmp
= extra
; *tmp
!= NULL
; ++tmp
)
606 if (strncmp (word
, *tmp
, len
) == 0)
607 tracker
.add_completion (make_unique_xstrdup (*tmp
));
612 _initialize_tui_regs (void)
614 struct cmd_list_element
**tuicmd
, *cmd
;
616 tuicmd
= tui_get_cmd_list ();
618 cmd
= add_cmd ("reg", class_tui
, tui_reg_command
, _("\
619 TUI command to control the register window."), tuicmd
);
620 set_cmd_completer (cmd
, tui_reggroup_completer
);
624 /*****************************************
625 ** STATIC LOCAL FUNCTIONS **
626 ******************************************/
628 /* Get the register from the frame and return a printable
629 representation of it. */
632 tui_register_format (struct frame_info
*frame
, int regnum
)
634 struct gdbarch
*gdbarch
= get_frame_arch (frame
);
638 scoped_restore save_pagination
639 = make_scoped_restore (&pagination_enabled
, 0);
640 scoped_restore save_stdout
641 = make_scoped_restore (&gdb_stdout
, &stream
);
643 gdbarch_print_registers_info (gdbarch
, &stream
, frame
, regnum
, 1);
645 /* Remove the possible \n. */
646 std::string
&str
= stream
.string ();
647 if (!str
.empty () && str
.back () == '\n')
648 str
.resize (str
.size () - 1);
650 /* Expand tabs into spaces, since ncurses on MS-Windows doesn't. */
651 return tui_expand_tabs (str
.c_str (), 0);
654 /* Get the register value from the given frame and format it for the
655 display. When changep is set, check if the new register value has
656 changed with respect to the previous call. */
657 static enum tui_status
658 tui_get_register (struct frame_info
*frame
,
659 struct tui_data_item_window
*data
,
660 int regnum
, bool *changedp
)
662 enum tui_status ret
= TUI_FAILURE
;
666 if (target_has_registers
)
668 char *prev_content
= data
->content
;
670 data
->content
= tui_register_format (frame
, regnum
);
673 && strcmp (prev_content
, data
->content
) != 0)
676 xfree (prev_content
);