Refresh regs window in display_registers_from
[deliverable/binutils-gdb.git] / gdb / tui / tui-regs.c
CommitLineData
f377b406 1/* TUI display registers in window.
f33c6cbf 2
3666a048 3 Copyright (C) 1998-2021 Free Software Foundation, Inc.
f33c6cbf 4
f377b406 5 Contributed by Hewlett-Packard Company.
c906108c 6
f377b406 7 This file is part of GDB.
c906108c 8
f377b406
SC
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
a9762ec7 11 the Free Software Foundation; either version 3 of the License, or
f377b406
SC
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
a9762ec7 20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
c906108c
SS
21
22#include "defs.h"
e17c207e 23#include "arch-utils.h"
d7b2e967
AC
24#include "tui/tui.h"
25#include "tui/tui-data.h"
c906108c
SS
26#include "symtab.h"
27#include "gdbtypes.h"
28#include "gdbcmd.h"
29#include "frame.h"
bc77de56 30#include "regcache.h"
c906108c
SS
31#include "inferior.h"
32#include "target.h"
d7b2e967
AC
33#include "tui/tui-layout.h"
34#include "tui/tui-win.h"
d7b2e967
AC
35#include "tui/tui-wingeneral.h"
36#include "tui/tui-file.h"
2c0b251b 37#include "tui/tui-regs.h"
312809f8 38#include "tui/tui-io.h"
10f59415 39#include "reggroups.h"
79a45b7d 40#include "valprint.h"
51f0e40d 41#include "completer.h"
c906108c 42
6a83354a 43#include "gdb_curses.h"
96ec9981 44
7a02bab7
TT
45/* A subclass of string_file that expands tab characters. */
46class tab_expansion_file : public string_file
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
1a4f81dd
TT
84/* Get the register from the frame and return a printable
85 representation of it. */
86
7a02bab7 87static std::string
1a4f81dd
TT
88tui_register_format (struct frame_info *frame, int regnum)
89{
90 struct gdbarch *gdbarch = get_frame_arch (frame);
5eccfcc2 91
7a02bab7
TT
92 /* Expand tabs into spaces, since ncurses on MS-Windows doesn't. */
93 tab_expansion_file stream;
1a4f81dd
TT
94
95 scoped_restore save_pagination
96 = make_scoped_restore (&pagination_enabled, 0);
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.string ();
104 if (!str.empty () && str.back () == '\n')
105 str.resize (str.size () - 1);
106
7a02bab7 107 return str;
1a4f81dd
TT
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
114tui_get_register (struct frame_info *frame,
dda83cd7 115 struct tui_data_item_window *data,
1a4f81dd
TT
116 int regnum, bool *changedp)
117{
118 if (changedp)
119 *changedp = false;
9dccd06e 120 if (target_has_registers ())
1a4f81dd 121 {
7a02bab7 122 std::string new_content = tui_register_format (frame, regnum);
1a4f81dd 123
7a02bab7 124 if (changedp != NULL && data->content != new_content)
1a4f81dd
TT
125 *changedp = true;
126
b9ad3686 127 data->content = std::move (new_content);
1a4f81dd
TT
128 }
129}
96bd6233
TT
130
131/* See tui-regs.h. */
132
c906108c 133int
0b5ec218 134tui_data_window::last_regs_line_no () const
c906108c 135{
80df3337
TT
136 int num_lines = m_regs_content.size () / m_regs_column_count;
137 if (m_regs_content.size () % m_regs_column_count)
0670413d 138 num_lines++;
6ba8e26f 139 return num_lines;
55fb0713 140}
c906108c 141
18ab23af 142/* See tui-regs.h. */
c906108c 143
c906108c 144int
3b23c5f2 145tui_data_window::line_from_reg_element_no (int element_no) const
c906108c 146{
80df3337 147 if (element_no < m_regs_content.size ())
c906108c
SS
148 {
149 int i, line = (-1);
150
151 i = 1;
152 while (line == (-1))
153 {
80df3337 154 if (element_no < m_regs_column_count * i)
c906108c
SS
155 line = i - 1;
156 else
157 i++;
158 }
159
160 return line;
161 }
162 else
163 return (-1);
55fb0713 164}
c906108c 165
18ab23af 166/* See tui-regs.h. */
c906108c 167
c906108c 168int
baff0c28 169tui_data_window::first_reg_element_no_inline (int line_no) const
c906108c 170{
80df3337
TT
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;
c906108c
SS
173 else
174 return (-1);
55fb0713 175}
c906108c 176
10f59415
SC
177/* Show the registers of the given group in the data window
178 and refresh the window. */
c906108c 179void
ca02d7c8 180tui_data_window::show_registers (struct reggroup *group)
c906108c 181{
10f59415
SC
182 if (group == 0)
183 group = general_reggroup;
c906108c 184
9dccd06e 185 if (target_has_registers () && target_has_stack () && target_has_memory ())
c906108c 186 {
ca02d7c8 187 show_register_group (group, get_selected_frame (NULL),
80df3337 188 group == m_current_group);
368c1354 189
1cc6d956 190 /* Clear all notation of changed values. */
80df3337 191 for (auto &&data_item_win : m_regs_content)
fa4dc567 192 data_item_win.highlight = false;
80df3337 193 m_current_group = group;
c906108c 194 }
368c1354
TT
195 else
196 {
80df3337 197 m_current_group = 0;
a31bff9d 198 m_regs_content.clear ();
368c1354 199 }
a31bff9d
TT
200
201 rerender ();
55fb0713 202}
c906108c
SS
203
204
10f59415 205/* Set the data window to display the registers of the register group
1cc6d956 206 using the given frame. Values are refreshed only when
b5457826 207 refresh_values_only is true. */
10f59415 208
ca02d7c8
TT
209void
210tui_data_window::show_register_group (struct reggroup *group,
211 struct frame_info *frame,
b5457826 212 bool refresh_values_only)
10f59415 213{
5eccfcc2 214 struct gdbarch *gdbarch = get_frame_arch (frame);
10f59415 215 int nr_regs;
10f59415 216 int regnum, pos;
10f59415
SC
217
218 /* Make a new title showing which group we display. */
ab0e1f1a 219 title = string_printf ("Register group: %s", reggroup_name (group));
10f59415
SC
220
221 /* See how many registers must be displayed. */
222 nr_regs = 0;
f6efe3f8 223 for (regnum = 0; regnum < gdbarch_num_cooked_regs (gdbarch); regnum++)
10f59415 224 {
d20c1c3f
PA
225 const char *name;
226
227 /* Must be in the group. */
228 if (!gdbarch_register_reggroup_p (gdbarch, regnum, group))
229 continue;
230
231 /* If the register name is empty, it is undefined for this
232 processor, so don't display anything. */
233 name = gdbarch_register_name (gdbarch, regnum);
234 if (name == 0 || *name == '\0')
235 continue;
236
237 nr_regs++;
10f59415
SC
238 }
239
80df3337 240 m_regs_content.resize (nr_regs);
10f59415 241
21e1c91e
TT
242 /* Now set the register names and values. */
243 pos = 0;
244 for (regnum = 0; regnum < gdbarch_num_cooked_regs (gdbarch); regnum++)
10f59415 245 {
21e1c91e
TT
246 struct tui_data_item_window *data_item_win;
247 const char *name;
10f59415 248
21e1c91e
TT
249 /* Must be in the group. */
250 if (!gdbarch_register_reggroup_p (gdbarch, regnum, group))
251 continue;
10f59415 252
21e1c91e
TT
253 /* If the register name is empty, it is undefined for this
254 processor, so don't display anything. */
255 name = gdbarch_register_name (gdbarch, regnum);
256 if (name == 0 || *name == '\0')
257 continue;
10f59415 258
80df3337 259 data_item_win = &m_regs_content[pos];
c9753adb 260 if (!refresh_values_only)
21e1c91e 261 {
22b7b041 262 data_item_win->regno = regnum;
c9753adb 263 data_item_win->highlight = false;
21e1c91e 264 }
c9753adb 265 tui_get_register (frame, data_item_win, regnum, 0);
21e1c91e
TT
266 pos++;
267 }
10f59415
SC
268}
269
18ab23af 270/* See tui-regs.h. */
517e9505 271
c906108c 272void
517e9505 273tui_data_window::display_registers_from (int start_element_no)
c906108c 274{
0670413d 275 int max_len = 0;
80df3337 276 for (auto &&data_item_win : m_regs_content)
c906108c 277 {
7a02bab7 278 int len = data_item_win.content.size ();
0670413d
TT
279
280 if (len > max_len)
281 max_len = len;
282 }
7134f2eb 283 m_item_width = max_len + 1;
0670413d
TT
284 int i = start_element_no;
285
7134f2eb 286 m_regs_column_count = (width - 2) / m_item_width;
80df3337
TT
287 if (m_regs_column_count == 0)
288 m_regs_column_count = 1;
7134f2eb 289 m_item_width = (width - 2) / m_regs_column_count;
0670413d
TT
290
291 /* Now create each data "sub" window, and write the display into
292 it. */
7134f2eb 293 int cur_y = 1;
1630140d 294 while (i < m_regs_content.size () && cur_y <= height - 2)
0670413d 295 {
7134f2eb 296 for (int j = 0;
80df3337 297 j < m_regs_column_count && i < m_regs_content.size ();
0670413d 298 j++)
c906108c 299 {
0670413d 300 /* Create the window if necessary. */
7134f2eb
TT
301 m_regs_content[i].x = (m_item_width * j) + 1;
302 m_regs_content[i].y = cur_y;
303 m_regs_content[i].visible = true;
304 m_regs_content[i].rerender (handle.get (), m_item_width);
0670413d 305 i++; /* Next register. */
c906108c 306 }
0670413d 307 cur_y++; /* Next row. */
c906108c 308 }
5fc2d6aa
HD
309
310 refresh_window ();
55fb0713 311}
c906108c 312
18ab23af 313/* See tui-regs.h. */
c906108c 314
aca2dd16
TT
315void
316tui_data_window::display_reg_element_at_line (int start_element_no,
317 int start_line_no)
c906108c 318{
0670413d 319 int element_no = start_element_no;
c906108c 320
0670413d
TT
321 if (start_element_no != 0 && start_line_no != 0)
322 {
323 int last_line_no, first_line_on_last_page;
324
325 last_line_no = last_regs_line_no ();
326 first_line_on_last_page = last_line_no - (height - 2);
327 if (first_line_on_last_page < 0)
328 first_line_on_last_page = 0;
329
330 /* If the element_no causes us to scroll past the end of the
331 registers, adjust what element to really start the
332 display at. */
333 if (start_line_no > first_line_on_last_page)
334 element_no = first_reg_element_no_inline (first_line_on_last_page);
c906108c 335 }
0670413d 336 display_registers_from (element_no);
6ba8e26f 337}
c906108c 338
18ab23af 339/* See tui-regs.h. */
c906108c 340
c906108c 341int
517e9505 342tui_data_window::display_registers_from_line (int line_no)
c906108c 343{
0670413d
TT
344 int element_no;
345
346 if (line_no < 0)
347 line_no = 0;
348 else
349 {
350 /* Make sure that we don't display off the end of the
351 registers. */
352 if (line_no >= last_regs_line_no ())
80cb6c27 353 {
80df3337 354 line_no = line_from_reg_element_no (m_regs_content.size () - 1);
0670413d
TT
355 if (line_no < 0)
356 line_no = 0;
c906108c 357 }
c906108c
SS
358 }
359
0670413d 360 element_no = first_reg_element_no_inline (line_no);
80df3337 361 if (element_no < m_regs_content.size ())
0670413d
TT
362 display_reg_element_at_line (element_no, line_no);
363 else
364 line_no = (-1);
365
366 return line_no;
55fb0713 367}
c906108c
SS
368
369
18ab23af
TT
370/* Answer the index first element displayed. If none are displayed,
371 then return (-1). */
372int
373tui_data_window::first_data_item_displayed ()
374{
80df3337 375 for (int i = 0; i < m_regs_content.size (); i++)
18ab23af 376 {
7134f2eb 377 if (m_regs_content[i].visible)
18ab23af
TT
378 return i;
379 }
380
381 return -1;
382}
383
384/* See tui-regs.h. */
385
386void
387tui_data_window::delete_data_content_windows ()
388{
7134f2eb
TT
389 for (auto &win : m_regs_content)
390 win.visible = false;
18ab23af
TT
391}
392
393
394void
395tui_data_window::erase_data_content (const char *prompt)
396{
7523da63 397 werase (handle.get ());
b4ef5aeb 398 check_and_display_highlight_if_needed ();
18ab23af
TT
399 if (prompt != NULL)
400 {
401 int half_width = (width - 2) / 2;
402 int x_pos;
403
404 if (strlen (prompt) >= half_width)
405 x_pos = 1;
406 else
407 x_pos = half_width - strlen (prompt);
7523da63 408 mvwaddstr (handle.get (), (height / 2), x_pos, (char *) prompt);
18ab23af 409 }
45bbae5c 410 tui_wrefresh (handle.get ());
18ab23af
TT
411}
412
413/* See tui-regs.h. */
414
415void
18bb55c7 416tui_data_window::rerender ()
18ab23af 417{
80df3337 418 if (m_regs_content.empty ())
1f6d2f10 419 erase_data_content (_("[ Register Values Unavailable ]"));
18ab23af
TT
420 else
421 {
422 erase_data_content (NULL);
423 delete_data_content_windows ();
18ab23af
TT
424 display_registers_from (0);
425 }
426}
427
428
18ab23af
TT
429/* Scroll the data window vertically forward or backward. */
430void
431tui_data_window::do_scroll_vertical (int num_to_scroll)
432{
433 int first_element_no;
434 int first_line = (-1);
435
436 first_element_no = first_data_item_displayed ();
80df3337 437 if (first_element_no < m_regs_content.size ())
18ab23af
TT
438 first_line = line_from_reg_element_no (first_element_no);
439 else
440 { /* Calculate the first line from the element number which is in
dda83cd7 441 the general data content. */
18ab23af
TT
442 }
443
444 if (first_line >= 0)
445 {
446 first_line += num_to_scroll;
447 erase_data_content (NULL);
448 delete_data_content_windows ();
449 display_registers_from_line (first_line);
450 }
451}
452
55fb0713
AC
453/* This function check all displayed registers for changes in values,
454 given a particular frame. If the values have changed, they are
455 updated with the new value and highlighted. */
c906108c 456void
63356bfd 457tui_data_window::check_register_values (struct frame_info *frame)
c906108c 458{
80df3337
TT
459 if (m_regs_content.empty ())
460 show_registers (m_current_group);
63356bfd 461 else
c906108c 462 {
80df3337 463 for (auto &&data_item_win : m_regs_content)
c906108c 464 {
63356bfd 465 int was_hilighted;
c906108c 466
fa4dc567 467 was_hilighted = data_item_win.highlight;
10f59415 468
fa4dc567 469 tui_get_register (frame, &data_item_win,
22b7b041 470 data_item_win.regno,
fa4dc567 471 &data_item_win.highlight);
10f59415 472
fa4dc567 473 if (data_item_win.highlight || was_hilighted)
7134f2eb 474 data_item_win.rerender (handle.get (), m_item_width);
c906108c
SS
475 }
476 }
7134f2eb
TT
477
478 tui_wrefresh (handle.get ());
55fb0713 479}
c906108c 480
1cc6d956
MS
481/* Display a register in a window. If hilite is TRUE, then the value
482 will be displayed in reverse video. */
cdaa6eb4 483void
7134f2eb 484tui_data_item_window::rerender (WINDOW *handle, int field_width)
10f59415 485{
cdaa6eb4
TT
486 if (highlight)
487 /* We ignore the return value, casting it to void in order to avoid
488 a compiler warning. The warning itself was introduced by a patch
489 to ncurses 5.7 dated 2009-08-29, changing this macro to expand
490 to code that causes the compiler to generate an unused-value
491 warning. */
7134f2eb 492 (void) wstandout (handle);
10f59415 493
7134f2eb
TT
494 mvwaddnstr (handle, y, x, content.c_str (), field_width - 1);
495 waddstr (handle, n_spaces (field_width - content.size ()));
cdaa6eb4
TT
496
497 if (highlight)
498 /* We ignore the return value, casting it to void in order to avoid
499 a compiler warning. The warning itself was introduced by a patch
500 to ncurses 5.7 dated 2009-08-29, changing this macro to expand
501 to code that causes the compiler to generate an unused-value
502 warning. */
7134f2eb 503 (void) wstandend (handle);
10f59415
SC
504}
505
51f0e40d
AB
506/* Helper for "tui reg next", wraps a call to REGGROUP_NEXT, but adds wrap
507 around behaviour. Returns the next register group, or NULL if the
508 register window is not currently being displayed. */
509
510static struct reggroup *
fe3eaf1c 511tui_reg_next (struct reggroup *current_group, struct gdbarch *gdbarch)
c906108c 512{
51f0e40d 513 struct reggroup *group = NULL;
e17c207e 514
fe3eaf1c 515 if (current_group != NULL)
10f59415 516 {
fe3eaf1c 517 group = reggroup_next (gdbarch, current_group);
b75c69bb 518 if (group == NULL)
dda83cd7 519 group = reggroup_next (gdbarch, NULL);
10f59415 520 }
51f0e40d 521 return group;
10f59415
SC
522}
523
51f0e40d
AB
524/* Helper for "tui reg prev", wraps a call to REGGROUP_PREV, but adds wrap
525 around behaviour. Returns the previous register group, or NULL if the
526 register window is not currently being displayed. */
55b40027 527
51f0e40d 528static struct reggroup *
fe3eaf1c 529tui_reg_prev (struct reggroup *current_group, struct gdbarch *gdbarch)
55b40027 530{
51f0e40d 531 struct reggroup *group = NULL;
55b40027 532
fe3eaf1c 533 if (current_group != NULL)
55b40027 534 {
fe3eaf1c 535 group = reggroup_prev (gdbarch, current_group);
55b40027
AB
536 if (group == NULL)
537 group = reggroup_prev (gdbarch, NULL);
55b40027 538 }
51f0e40d 539 return group;
55b40027
AB
540}
541
51f0e40d
AB
542/* Implement the 'tui reg' command. Changes the register group displayed
543 in the tui register window. Displays the tui register window if it is
544 not already on display. */
c906108c 545
10f59415 546static void
e2d8ae16 547tui_reg_command (const char *args, int from_tty)
10f59415 548{
51f0e40d 549 struct gdbarch *gdbarch = get_current_arch ();
c906108c 550
51f0e40d
AB
551 if (args != NULL)
552 {
553 struct reggroup *group, *match = NULL;
554 size_t len = strlen (args);
555
556 /* Make sure the curses mode is enabled. */
557 tui_enable ();
558
45bbae5c
TT
559 tui_suppress_output suppress;
560
51f0e40d
AB
561 /* Make sure the register window is visible. If not, select an
562 appropriate layout. We need to do this before trying to run the
563 'next' or 'prev' commands. */
2d83e710 564 if (TUI_DATA_WIN == NULL || !TUI_DATA_WIN->is_visible ())
0dbc2fc7 565 tui_regs_layout ();
51f0e40d 566
89df7f90 567 struct reggroup *current_group = TUI_DATA_WIN->get_current_group ();
51f0e40d 568 if (strncmp (args, "next", len) == 0)
fe3eaf1c 569 match = tui_reg_next (current_group, gdbarch);
51f0e40d 570 else if (strncmp (args, "prev", len) == 0)
fe3eaf1c 571 match = tui_reg_prev (current_group, gdbarch);
51f0e40d
AB
572
573 /* This loop matches on the initial part of a register group
574 name. If this initial part in ARGS matches only one register
575 group then the switch is made. */
576 for (group = reggroup_next (gdbarch, NULL);
577 group != NULL;
578 group = reggroup_next (gdbarch, group))
579 {
580 if (strncmp (reggroup_name (group), args, len) == 0)
581 {
582 if (match != NULL)
583 error (_("ambiguous register group name '%s'"), args);
584 match = group;
585 }
586 }
587
588 if (match == NULL)
589 error (_("unknown register group '%s'"), args);
590
ca02d7c8 591 TUI_DATA_WIN->show_registers (match);
51f0e40d
AB
592 }
593 else
594 {
595 struct reggroup *group;
596 int first;
597
598 printf_unfiltered (_("\"tui reg\" must be followed by the name of "
599 "either a register group,\nor one of 'next' "
600 "or 'prev'. Known register groups are:\n"));
601
602 for (first = 1, group = reggroup_next (gdbarch, NULL);
603 group != NULL;
604 first = 0, group = reggroup_next (gdbarch, group))
605 {
606 if (!first)
607 printf_unfiltered (", ");
608 printf_unfiltered ("%s", reggroup_name (group));
609 }
610
611 printf_unfiltered ("\n");
612 }
10f59415
SC
613}
614
51f0e40d
AB
615/* Complete names of register groups, and add the special "prev" and "next"
616 names. */
c906108c 617
eb3ff9a5 618static void
51f0e40d 619tui_reggroup_completer (struct cmd_list_element *ignore,
eb3ff9a5 620 completion_tracker &tracker,
51f0e40d 621 const char *text, const char *word)
10f59415 622{
ea68593b 623 static const char * const extra[] = { "next", "prev", NULL };
51f0e40d 624
eb3ff9a5 625 reggroup_completer (ignore, tracker, text, word);
51f0e40d 626
ea68593b 627 complete_on_enum (tracker, extra, text, word);
10f59415 628}
c906108c 629
6c265988 630void _initialize_tui_regs ();
18ab23af 631void
6c265988 632_initialize_tui_regs ()
18ab23af
TT
633{
634 struct cmd_list_element **tuicmd, *cmd;
635
636 tuicmd = tui_get_cmd_list ();
637
638 cmd = add_cmd ("reg", class_tui, tui_reg_command, _("\
283be8bf
TT
639TUI command to control the register window.\n\
640Usage: tui reg NAME\n\
641NAME is the name of the register group to display"), tuicmd);
18ab23af
TT
642 set_cmd_completer (cmd, tui_reggroup_completer);
643}
This page took 4.013473 seconds and 4 git commands to generate.