]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/tui/tui-regs.c
gdb, gdbserver, gdbsupport: fix leading space vs tabs issues
[thirdparty/binutils-gdb.git] / gdb / tui / tui-regs.c
CommitLineData
f377b406 1/* TUI display registers in window.
f33c6cbf 2
b811d2c2 3 Copyright (C) 1998-2020 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 }
55fb0713 309}
c906108c 310
18ab23af 311/* See tui-regs.h. */
c906108c 312
aca2dd16
TT
313void
314tui_data_window::display_reg_element_at_line (int start_element_no,
315 int start_line_no)
c906108c 316{
0670413d 317 int element_no = start_element_no;
c906108c 318
0670413d
TT
319 if (start_element_no != 0 && start_line_no != 0)
320 {
321 int last_line_no, first_line_on_last_page;
322
323 last_line_no = last_regs_line_no ();
324 first_line_on_last_page = last_line_no - (height - 2);
325 if (first_line_on_last_page < 0)
326 first_line_on_last_page = 0;
327
328 /* If the element_no causes us to scroll past the end of the
329 registers, adjust what element to really start the
330 display at. */
331 if (start_line_no > first_line_on_last_page)
332 element_no = first_reg_element_no_inline (first_line_on_last_page);
c906108c 333 }
0670413d 334 display_registers_from (element_no);
6ba8e26f 335}
c906108c 336
18ab23af 337/* See tui-regs.h. */
c906108c 338
c906108c 339int
517e9505 340tui_data_window::display_registers_from_line (int line_no)
c906108c 341{
0670413d
TT
342 int element_no;
343
344 if (line_no < 0)
345 line_no = 0;
346 else
347 {
348 /* Make sure that we don't display off the end of the
349 registers. */
350 if (line_no >= last_regs_line_no ())
80cb6c27 351 {
80df3337 352 line_no = line_from_reg_element_no (m_regs_content.size () - 1);
0670413d
TT
353 if (line_no < 0)
354 line_no = 0;
c906108c 355 }
c906108c
SS
356 }
357
0670413d 358 element_no = first_reg_element_no_inline (line_no);
80df3337 359 if (element_no < m_regs_content.size ())
0670413d
TT
360 display_reg_element_at_line (element_no, line_no);
361 else
362 line_no = (-1);
363
364 return line_no;
55fb0713 365}
c906108c
SS
366
367
18ab23af
TT
368/* Answer the index first element displayed. If none are displayed,
369 then return (-1). */
370int
371tui_data_window::first_data_item_displayed ()
372{
80df3337 373 for (int i = 0; i < m_regs_content.size (); i++)
18ab23af 374 {
7134f2eb 375 if (m_regs_content[i].visible)
18ab23af
TT
376 return i;
377 }
378
379 return -1;
380}
381
382/* See tui-regs.h. */
383
384void
385tui_data_window::delete_data_content_windows ()
386{
7134f2eb
TT
387 for (auto &win : m_regs_content)
388 win.visible = false;
18ab23af
TT
389}
390
391
392void
393tui_data_window::erase_data_content (const char *prompt)
394{
7523da63 395 werase (handle.get ());
b4ef5aeb 396 check_and_display_highlight_if_needed ();
18ab23af
TT
397 if (prompt != NULL)
398 {
399 int half_width = (width - 2) / 2;
400 int x_pos;
401
402 if (strlen (prompt) >= half_width)
403 x_pos = 1;
404 else
405 x_pos = half_width - strlen (prompt);
7523da63 406 mvwaddstr (handle.get (), (height / 2), x_pos, (char *) prompt);
18ab23af 407 }
45bbae5c 408 tui_wrefresh (handle.get ());
18ab23af
TT
409}
410
411/* See tui-regs.h. */
412
413void
18bb55c7 414tui_data_window::rerender ()
18ab23af 415{
80df3337 416 if (m_regs_content.empty ())
1f6d2f10 417 erase_data_content (_("[ Register Values Unavailable ]"));
18ab23af
TT
418 else
419 {
420 erase_data_content (NULL);
421 delete_data_content_windows ();
18ab23af
TT
422 display_registers_from (0);
423 }
424}
425
426
18ab23af
TT
427/* Scroll the data window vertically forward or backward. */
428void
429tui_data_window::do_scroll_vertical (int num_to_scroll)
430{
431 int first_element_no;
432 int first_line = (-1);
433
434 first_element_no = first_data_item_displayed ();
80df3337 435 if (first_element_no < m_regs_content.size ())
18ab23af
TT
436 first_line = line_from_reg_element_no (first_element_no);
437 else
438 { /* Calculate the first line from the element number which is in
dda83cd7 439 the general data content. */
18ab23af
TT
440 }
441
442 if (first_line >= 0)
443 {
444 first_line += num_to_scroll;
445 erase_data_content (NULL);
446 delete_data_content_windows ();
447 display_registers_from_line (first_line);
448 }
449}
450
55fb0713
AC
451/* This function check all displayed registers for changes in values,
452 given a particular frame. If the values have changed, they are
453 updated with the new value and highlighted. */
c906108c 454void
63356bfd 455tui_data_window::check_register_values (struct frame_info *frame)
c906108c 456{
80df3337
TT
457 if (m_regs_content.empty ())
458 show_registers (m_current_group);
63356bfd 459 else
c906108c 460 {
80df3337 461 for (auto &&data_item_win : m_regs_content)
c906108c 462 {
63356bfd 463 int was_hilighted;
c906108c 464
fa4dc567 465 was_hilighted = data_item_win.highlight;
10f59415 466
fa4dc567 467 tui_get_register (frame, &data_item_win,
22b7b041 468 data_item_win.regno,
fa4dc567 469 &data_item_win.highlight);
10f59415 470
fa4dc567 471 if (data_item_win.highlight || was_hilighted)
7134f2eb 472 data_item_win.rerender (handle.get (), m_item_width);
c906108c
SS
473 }
474 }
7134f2eb
TT
475
476 tui_wrefresh (handle.get ());
55fb0713 477}
c906108c 478
1cc6d956
MS
479/* Display a register in a window. If hilite is TRUE, then the value
480 will be displayed in reverse video. */
cdaa6eb4 481void
7134f2eb 482tui_data_item_window::rerender (WINDOW *handle, int field_width)
10f59415 483{
cdaa6eb4
TT
484 if (highlight)
485 /* We ignore the return value, casting it to void in order to avoid
486 a compiler warning. The warning itself was introduced by a patch
487 to ncurses 5.7 dated 2009-08-29, changing this macro to expand
488 to code that causes the compiler to generate an unused-value
489 warning. */
7134f2eb 490 (void) wstandout (handle);
10f59415 491
7134f2eb
TT
492 mvwaddnstr (handle, y, x, content.c_str (), field_width - 1);
493 waddstr (handle, n_spaces (field_width - content.size ()));
cdaa6eb4
TT
494
495 if (highlight)
496 /* We ignore the return value, casting it to void in order to avoid
497 a compiler warning. The warning itself was introduced by a patch
498 to ncurses 5.7 dated 2009-08-29, changing this macro to expand
499 to code that causes the compiler to generate an unused-value
500 warning. */
7134f2eb 501 (void) wstandend (handle);
10f59415
SC
502}
503
51f0e40d
AB
504/* Helper for "tui reg next", wraps a call to REGGROUP_NEXT, but adds wrap
505 around behaviour. Returns the next register group, or NULL if the
506 register window is not currently being displayed. */
507
508static struct reggroup *
fe3eaf1c 509tui_reg_next (struct reggroup *current_group, struct gdbarch *gdbarch)
c906108c 510{
51f0e40d 511 struct reggroup *group = NULL;
e17c207e 512
fe3eaf1c 513 if (current_group != NULL)
10f59415 514 {
fe3eaf1c 515 group = reggroup_next (gdbarch, current_group);
b75c69bb 516 if (group == NULL)
dda83cd7 517 group = reggroup_next (gdbarch, NULL);
10f59415 518 }
51f0e40d 519 return group;
10f59415
SC
520}
521
51f0e40d
AB
522/* Helper for "tui reg prev", wraps a call to REGGROUP_PREV, but adds wrap
523 around behaviour. Returns the previous register group, or NULL if the
524 register window is not currently being displayed. */
55b40027 525
51f0e40d 526static struct reggroup *
fe3eaf1c 527tui_reg_prev (struct reggroup *current_group, struct gdbarch *gdbarch)
55b40027 528{
51f0e40d 529 struct reggroup *group = NULL;
55b40027 530
fe3eaf1c 531 if (current_group != NULL)
55b40027 532 {
fe3eaf1c 533 group = reggroup_prev (gdbarch, current_group);
55b40027
AB
534 if (group == NULL)
535 group = reggroup_prev (gdbarch, NULL);
55b40027 536 }
51f0e40d 537 return group;
55b40027
AB
538}
539
51f0e40d
AB
540/* Implement the 'tui reg' command. Changes the register group displayed
541 in the tui register window. Displays the tui register window if it is
542 not already on display. */
c906108c 543
10f59415 544static void
e2d8ae16 545tui_reg_command (const char *args, int from_tty)
10f59415 546{
51f0e40d 547 struct gdbarch *gdbarch = get_current_arch ();
c906108c 548
51f0e40d
AB
549 if (args != NULL)
550 {
551 struct reggroup *group, *match = NULL;
552 size_t len = strlen (args);
553
554 /* Make sure the curses mode is enabled. */
555 tui_enable ();
556
45bbae5c
TT
557 tui_suppress_output suppress;
558
51f0e40d
AB
559 /* Make sure the register window is visible. If not, select an
560 appropriate layout. We need to do this before trying to run the
561 'next' or 'prev' commands. */
2d83e710 562 if (TUI_DATA_WIN == NULL || !TUI_DATA_WIN->is_visible ())
0dbc2fc7 563 tui_regs_layout ();
51f0e40d 564
89df7f90 565 struct reggroup *current_group = TUI_DATA_WIN->get_current_group ();
51f0e40d 566 if (strncmp (args, "next", len) == 0)
fe3eaf1c 567 match = tui_reg_next (current_group, gdbarch);
51f0e40d 568 else if (strncmp (args, "prev", len) == 0)
fe3eaf1c 569 match = tui_reg_prev (current_group, gdbarch);
51f0e40d
AB
570
571 /* This loop matches on the initial part of a register group
572 name. If this initial part in ARGS matches only one register
573 group then the switch is made. */
574 for (group = reggroup_next (gdbarch, NULL);
575 group != NULL;
576 group = reggroup_next (gdbarch, group))
577 {
578 if (strncmp (reggroup_name (group), args, len) == 0)
579 {
580 if (match != NULL)
581 error (_("ambiguous register group name '%s'"), args);
582 match = group;
583 }
584 }
585
586 if (match == NULL)
587 error (_("unknown register group '%s'"), args);
588
ca02d7c8 589 TUI_DATA_WIN->show_registers (match);
51f0e40d
AB
590 }
591 else
592 {
593 struct reggroup *group;
594 int first;
595
596 printf_unfiltered (_("\"tui reg\" must be followed by the name of "
597 "either a register group,\nor one of 'next' "
598 "or 'prev'. Known register groups are:\n"));
599
600 for (first = 1, group = reggroup_next (gdbarch, NULL);
601 group != NULL;
602 first = 0, group = reggroup_next (gdbarch, group))
603 {
604 if (!first)
605 printf_unfiltered (", ");
606 printf_unfiltered ("%s", reggroup_name (group));
607 }
608
609 printf_unfiltered ("\n");
610 }
10f59415
SC
611}
612
51f0e40d
AB
613/* Complete names of register groups, and add the special "prev" and "next"
614 names. */
c906108c 615
eb3ff9a5 616static void
51f0e40d 617tui_reggroup_completer (struct cmd_list_element *ignore,
eb3ff9a5 618 completion_tracker &tracker,
51f0e40d 619 const char *text, const char *word)
10f59415 620{
ea68593b 621 static const char * const extra[] = { "next", "prev", NULL };
51f0e40d 622
eb3ff9a5 623 reggroup_completer (ignore, tracker, text, word);
51f0e40d 624
ea68593b 625 complete_on_enum (tracker, extra, text, word);
10f59415 626}
c906108c 627
6c265988 628void _initialize_tui_regs ();
18ab23af 629void
6c265988 630_initialize_tui_regs ()
18ab23af
TT
631{
632 struct cmd_list_element **tuicmd, *cmd;
633
634 tuicmd = tui_get_cmd_list ();
635
636 cmd = add_cmd ("reg", class_tui, tui_reg_command, _("\
283be8bf
TT
637TUI command to control the register window.\n\
638Usage: tui reg NAME\n\
639NAME is the name of the register group to display"), tuicmd);
18ab23af
TT
640 set_cmd_completer (cmd, tui_reggroup_completer);
641}