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