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 gdbarch_print_registers_info (gdbarch, &stream, frame, regnum, 1);
95
96 /* Remove the possible \n. */
97 std::string str = stream.release ();
98 if (!str.empty () && str.back () == '\n')
99 str.resize (str.size () - 1);
100
101 return str;
102}
103
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. */
107static void
109 struct tui_data_item_window *data,
110 int regnum, bool *changedp)
111{
112 if (changedp)
113 *changedp = false;
115 {
116 std::string new_content = tui_register_format (frame, regnum);
117
118 if (changedp != NULL && data->content != new_content)
119 *changedp = true;
120
121 data->content = std::move (new_content);
122 }
123}
124
125/* See tui-regs.h. */
126
127int
129{
130 int num_lines = m_regs_content.size () / m_regs_column_count;
132 num_lines++;
133 return num_lines;
134}
135
136/* See tui-regs.h. */
137
138int
140{
141 if (element_no < m_regs_content.size ())
142 {
143 int i, line = (-1);
144
145 i = 1;
146 while (line == (-1))
147 {
148 if (element_no < m_regs_column_count * i)
149 line = i - 1;
150 else
151 i++;
152 }
153
154 return line;
155 }
156 else
157 return (-1);
158}
159
160/* See tui-regs.h. */
161
162int
164{
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;
167 else
168 return (-1);
169}
170
171/* Show the registers of the given group in the data window
172 and refresh the window. */
173void
175{
176 if (group == 0)
177 group = general_reggroup;
178
180 {
182 group == m_current_group);
183
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;
188 }
189 else
190 {
191 m_current_group = 0;
192 m_regs_content.clear ();
193 }
194
195 rerender ();
196}
197
198
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. */
202
203void
205 frame_info_ptr frame,
206 bool refresh_values_only)
207{
208 struct gdbarch *gdbarch = get_frame_arch (frame);
209 int nr_regs;
210 int regnum, pos;
211
212 /* Make a new title showing which group we display. */
213 this->set_title (string_printf ("Register group: %s", group->name ()));
214
215 /* See how many registers must be displayed. */
216 nr_regs = 0;
218 {
219 const char *name;
220
221 /* Must be in the group. */
223 continue;
224
225 /* If the register name is empty, it is undefined for this
226 processor, so don't display anything. */
228 if (*name == '\0')
229 continue;
230
231 nr_regs++;
232 }
233
234 m_regs_content.resize (nr_regs);
235
236 /* Now set the register names and values. */
237 pos = 0;
239 {
240 struct tui_data_item_window *data_item_win;
241 const char *name;
242
243 /* Must be in the group. */
245 continue;
246
247 /* If the register name is empty, it is undefined for this
248 processor, so don't display anything. */
250 if (*name == '\0')
251 continue;
252
253 data_item_win = &m_regs_content[pos];
254 if (!refresh_values_only)
255 {
256 data_item_win->regno = regnum;
257 data_item_win->highlight = false;
258 }
259 tui_get_register (frame, data_item_win, regnum, 0);
260 pos++;
261 }
262}
263
264/* See tui-regs.h. */
265
266void
268{
269 int max_len = 0;
270 for (auto &&data_item_win : m_regs_content)
271 {
272 int len = data_item_win.content.size ();
273
274 if (len > max_len)
275 max_len = len;
276 }
277 m_item_width = max_len + 1;
278
279 int i;
280 /* Mark register windows above the visible area. */
281 for (i = 0; i < start_element_no; i++)
282 m_regs_content[i].y = 0;
283
285 if (m_regs_column_count == 0)
288
289 /* Now create each data "sub" window, and write the display into
290 it. */
291 int cur_y = 1;
292 while (i < m_regs_content.size () && cur_y <= height - 2)
293 {
294 for (int j = 0;
295 j < m_regs_column_count && i < m_regs_content.size ();
296 j++)
297 {
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. */
304 }
305 cur_y++; /* Next row. */
306 }
307
308 /* Mark register windows below the visible area. */
309 for (; i < m_regs_content.size (); i++)
310 m_regs_content[i].y = 0;
311
313}
314
315/* See tui-regs.h. */
316
317void
319 int start_line_no)
320{
321 int element_no = start_element_no;
322
323 if (start_element_no != 0 && start_line_no != 0)
324 {
325 int last_line_no, first_line_on_last_page;
326
327 last_line_no = last_regs_line_no ();
328 first_line_on_last_page = last_line_no - (height - 2);
329 if (first_line_on_last_page < 0)
330 first_line_on_last_page = 0;
331
332 /* If the element_no causes us to scroll past the end of the
333 registers, adjust what element to really start the
334 display at. */
335 if (start_line_no > first_line_on_last_page)
336 element_no = first_reg_element_no_inline (first_line_on_last_page);
337 }
338 display_registers_from (element_no);
339}
340
341/* See tui-regs.h. */
342
343int
345{
346 int element_no;
347
348 if (line_no < 0)
349 line_no = 0;
350 else
351 {
352 /* Make sure that we don't display off the end of the
353 registers. */
354 if (line_no >= last_regs_line_no ())
355 {
356 line_no = line_from_reg_element_no (m_regs_content.size () - 1);
357 if (line_no < 0)
358 line_no = 0;
359 }
360 }
361
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);
365 else
366 line_no = (-1);
367
368 return line_no;
369}
370
371
372/* Answer the index first element displayed. If none are displayed,
373 then return (-1). */
374int
376{
377 for (int i = 0; i < m_regs_content.size (); i++)
378 {
379 if (m_regs_content[i].visible)
380 return i;
381 }
382
383 return -1;
384}
385
386/* See tui-regs.h. */
387
388void
390{
391 for (auto &win : m_regs_content)
392 win.visible = false;
393}
394
395
396void
398{
399 werase (handle.get ());
401 if (prompt != NULL)
402 {
403 int half_width = (width - 2) / 2;
404 int x_pos;
405
406 if (strlen (prompt) >= half_width)
407 x_pos = 1;
408 else
409 x_pos = half_width - strlen (prompt);
410 mvwaddstr (handle.get (), (height / 2), x_pos, (char *) prompt);
411 }
412 tui_wrefresh (handle.get ());
413}
414
415/* See tui-regs.h. */
416
417void
419{
420 if (m_regs_content.empty ())
421 erase_data_content (_("[ Register Values Unavailable ]"));
422 else
423 {
424 erase_data_content (NULL);
427 }
428}
429
430
431/* Scroll the data window vertically forward or backward. */
432void
434{
435 int first_element_no;
436 int first_line = (-1);
437
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);
441 else
442 { /* Calculate the first line from the element number which is in
443 the general data content. */
444 }
445
446 if (first_line >= 0)
447 {
448 first_line += num_to_scroll;
449 erase_data_content (NULL);
451 display_registers_from_line (first_line);
452 }
453}
454
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. */
458void
460{
461 if (m_regs_content.empty ())
463 else
464 {
465 for (auto &&data_item_win : m_regs_content)
466 {
467 int was_hilighted;
468
469 was_hilighted = data_item_win.highlight;
470
471 tui_get_register (frame, &data_item_win,
472 data_item_win.regno,
473 &data_item_win.highlight);
474
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);
479 }
480 }
481
482 tui_wrefresh (handle.get ());
483}
484
485/* Display a register in a window. If hilite is TRUE, then the value
486 will be displayed in reverse video. */
487void
488tui_data_item_window::rerender (WINDOW *handle, int field_width)
489{
490 if (highlight)
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
495 warning. */
496 (void) wstandout (handle);
497
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 ()));
501
502 if (highlight)
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
507 warning. */
508 (void) wstandend (handle);
509}
510
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
513 behaviour.
514
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. */
520
521static const reggroup *
522tui_reg_next (const reggroup *current_group, struct gdbarch *gdbarch)
523{
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 ())
527 it++;
528 if (it == groups.end ())
529 return groups.front ();
530 return *it;
531}
532
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
535 behaviour.
536
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. */
542
543static const reggroup *
544tui_reg_prev (const reggroup *current_group, struct gdbarch *gdbarch)
545{
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 ())
549 it++;
550 if (it == groups.rend ())
551 return groups.back ();
552 return *it;
553}
554
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. */
558
559static void
560tui_reg_command (const char *args, int from_tty)
561{
562 struct gdbarch *gdbarch = get_current_arch ();
563
564 if (args != NULL)
565 {
566 size_t len = strlen (args);
567
568 /* Make sure the curses mode is enabled. */
569 tui_enable ();
570
572
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 ())
578
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);
585 else
586 {
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))
591 {
592 if (strncmp (group->name (), args, len) == 0)
593 {
594 if (match != NULL)
595 error (_("ambiguous register group name '%s'"), args);
596 match = group;
597 }
598 }
599 }
600
601 if (match == NULL)
602 error (_("unknown register group '%s'"), args);
603
604 TUI_DATA_WIN->show_registers (match);
605 }
606 else
607 {
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"));
611
612 bool first = true;
613 for (const struct reggroup *group : gdbarch_reggroups (gdbarch))
614 {
615 if (!first)
616 gdb_printf (", ");
617 first = false;
618 gdb_printf ("%s", group->name ());
619 }
620
621 gdb_printf ("\n");
622 }
623}
624
625/* Complete names of register groups, and add the special "prev" and "next"
626 names. */
627
628static void
630 completion_tracker &tracker,
631 const char *text, const char *word)
632{
633 static const char * const extra[] = { "next", "prev", NULL };
634
635 reggroup_completer (ignore, tracker, text, word);
636
637 complete_on_enum (tracker, extra, text, word);
638}
639
641void
643{
644 struct cmd_list_element **tuicmd, *cmd;
645
646 tuicmd = tui_get_cmd_list ();
647
648 cmd = add_cmd ("reg", class_tui, tui_reg_command, _("\
649TUI command to control the register window.\n\
650Usage: tui reg NAME\n\
651NAME is the name of the register group to display"), tuicmd);
653}
int regnum
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:204
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)
@ 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:3027
frame_info_ptr get_selected_frame(const char *message)
Definition frame.c:1888
const char * gdbarch_register_name(struct gdbarch *gdbarch, int regnr)
Definition gdbarch.c:2173
void gdbarch_print_registers_info(struct gdbarch *gdbarch, struct ui_file *file, frame_info_ptr frame, int regnum, int all)
Definition gdbarch.c:2327
int gdbarch_register_reggroup_p(struct gdbarch *gdbarch, int regnum, const struct reggroup *reggroup)
Definition gdbarch.c:3670
static int gdbarch_num_cooked_regs(gdbarch *arch)
Definition gdbarch.h:390
else inf wait suppress
Definition gnu-nat.c:1836
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:488
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:204
void erase_data_content(const char *prompt)
Definition tui-regs.c:397
int last_regs_line_no() const
Definition tui-regs.c:128
int line_from_reg_element_no(int element_no) const
Definition tui-regs.c:139
void do_scroll_vertical(int num_to_scroll) override
Definition tui-regs.c:433
void check_register_values(frame_info_ptr frame)
Definition tui-regs.c:459
void show_registers(const reggroup *group)
Definition tui-regs.c:174
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:389
void display_registers_from(int start_element_no)
Definition tui-regs.c:267
void rerender() override
Definition tui-regs.c:418
int display_registers_from_line(int line_no)
Definition tui-regs.c:344
int first_reg_element_no_inline(int line_no) const
Definition tui-regs.c:163
const reggroup * m_current_group
Definition tui-regs.h:129
int first_data_item_displayed()
Definition tui-regs.c:375
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:318
void check_and_display_highlight_if_needed()
void set_title(std::string &&new_title)
Definition tui-data.c:158
std::unique_ptr< WINDOW, curses_deleter > handle
Definition tui-data.h:158
virtual void refresh_window()
int target_has_stack()
Definition target.c:177
int target_has_registers()
Definition target.c:189
int target_has_memory()
Definition target.c:165
#define TUI_DATA_WIN
Definition tui-data.h:197
void tui_regs_layout()
Definition tui-layout.c:245
static void tui_get_register(frame_info_ptr frame, struct tui_data_item_window *data, int regnum, bool *changedp)
Definition tui-regs.c:108
static void tui_reggroup_completer(struct cmd_list_element *ignore, completion_tracker &tracker, const char *text, const char *word)
Definition tui-regs.c:629
static const reggroup * tui_reg_prev(const reggroup *current_group, struct gdbarch *gdbarch)
Definition tui-regs.c:544
void _initialize_tui_regs()
Definition tui-regs.c:642
static void tui_reg_command(const char *args, int from_tty)
Definition tui-regs.c:560
static const reggroup * tui_reg_next(const reggroup *current_group, struct gdbarch *gdbarch)
Definition tui-regs.c:522
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:300
void tui_wrefresh(WINDOW *win)
void tui_enable(void)
Definition tui.c:381
const char * n_spaces(int n)
Definition utils.c:1947
void gdb_printf(struct ui_file *stream, const char *format,...)
Definition utils.c:1886