]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/tui/tui-regs.c
Update copyright year range in header of all files managed by GDB
[thirdparty/binutils-gdb.git] / gdb / tui / tui-regs.c
1 /* TUI display registers in window.
2
3 Copyright (C) 1998-2024 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. */
46 class tab_expansion_file : public string_file
47 {
48 public:
49
50 tab_expansion_file () = default;
51
52 void write (const char *buf, long length_buf) override;
53
54 private:
55
56 int m_column = 0;
57 };
58
59 void
60 tab_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
87 static std::string
88 tui_register_format (frame_info_ptr frame, int regnum)
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. */
107 static void
108 tui_get_register (frame_info_ptr frame,
109 struct tui_data_item_window *data,
110 int regnum, bool *changedp)
111 {
112 if (changedp)
113 *changedp = false;
114 if (target_has_registers ())
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
127 int
128 tui_data_window::last_regs_line_no () const
129 {
130 int num_lines = m_regs_content.size () / m_regs_column_count;
131 if (m_regs_content.size () % m_regs_column_count)
132 num_lines++;
133 return num_lines;
134 }
135
136 /* See tui-regs.h. */
137
138 int
139 tui_data_window::line_from_reg_element_no (int element_no) const
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
162 int
163 tui_data_window::first_reg_element_no_inline (int line_no) const
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. */
173 void
174 tui_data_window::show_registers (const reggroup *group)
175 {
176 if (group == 0)
177 group = general_reggroup;
178
179 if (target_has_registers () && target_has_stack () && target_has_memory ())
180 {
181 show_register_group (group, get_selected_frame (NULL),
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 (false);
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
203 void
204 tui_data_window::show_register_group (const reggroup *group,
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;
217 for (regnum = 0; regnum < gdbarch_num_cooked_regs (gdbarch); regnum++)
218 {
219 const char *name;
220
221 /* Must be in the group. */
222 if (!gdbarch_register_reggroup_p (gdbarch, regnum, group))
223 continue;
224
225 /* If the register name is empty, it is undefined for this
226 processor, so don't display anything. */
227 name = gdbarch_register_name (gdbarch, regnum);
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;
238 for (regnum = 0; regnum < gdbarch_num_cooked_regs (gdbarch); regnum++)
239 {
240 struct tui_data_item_window *data_item_win;
241 const char *name;
242
243 /* Must be in the group. */
244 if (!gdbarch_register_reggroup_p (gdbarch, regnum, group))
245 continue;
246
247 /* If the register name is empty, it is undefined for this
248 processor, so don't display anything. */
249 name = gdbarch_register_name (gdbarch, regnum);
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
266 void
267 tui_data_window::display_registers_from (int start_element_no)
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
284 m_regs_column_count = (width - box_size ()) / m_item_width;
285 if (m_regs_column_count == 0)
286 m_regs_column_count = 1;
287 m_item_width = (width - box_size ()) / m_regs_column_count;
288
289 /* Now create each data "sub" window, and write the display into
290 it. */
291 int cur_y = box_width ();
292 while (i < m_regs_content.size () && cur_y <= height - box_size ())
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 = box_width () + (m_item_width * j);
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
312 refresh_window ();
313 }
314
315 /* See tui-regs.h. */
316
317 void
318 tui_data_window::display_reg_element_at_line (int start_element_no,
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 - box_size ());
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
343 int
344 tui_data_window::display_registers_from_line (int line_no)
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). */
374 int
375 tui_data_window::first_data_item_displayed ()
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
388 void
389 tui_data_window::delete_data_content_windows ()
390 {
391 for (auto &win : m_regs_content)
392 win.visible = false;
393 }
394
395
396 void
397 tui_data_window::erase_data_content (const char *prompt)
398 {
399 werase (handle.get ());
400 check_and_display_highlight_if_needed ();
401 if (prompt != NULL)
402 {
403 int half_width = (width - box_size ()) / 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 display_string (height / 2, x_pos, prompt);
411 }
412 tui_wrefresh (handle.get ());
413 }
414
415 /* See tui-regs.h. */
416
417 void
418 tui_data_window::rerender (bool toplevel)
419 {
420 if (m_regs_content.empty ())
421 {
422 if (toplevel && has_stack_frames ())
423 {
424 frame_info_ptr fi = get_selected_frame (NULL);
425 check_register_values (fi);
426 }
427 else
428 erase_data_content (_("[ Register Values Unavailable ]"));
429 }
430 else
431 {
432 erase_data_content (NULL);
433 delete_data_content_windows ();
434 display_registers_from (0);
435 }
436 }
437
438
439 /* Scroll the data window vertically forward or backward. */
440 void
441 tui_data_window::do_scroll_vertical (int num_to_scroll)
442 {
443 int first_element_no;
444 int first_line = (-1);
445
446 first_element_no = first_data_item_displayed ();
447 if (first_element_no < m_regs_content.size ())
448 first_line = line_from_reg_element_no (first_element_no);
449 else
450 { /* Calculate the first line from the element number which is in
451 the general data content. */
452 }
453
454 if (first_line >= 0)
455 {
456 first_line += num_to_scroll;
457 erase_data_content (NULL);
458 delete_data_content_windows ();
459 display_registers_from_line (first_line);
460 }
461 }
462
463 /* This function check all displayed registers for changes in values,
464 given a particular frame. If the values have changed, they are
465 updated with the new value and highlighted. */
466 void
467 tui_data_window::check_register_values (frame_info_ptr frame)
468 {
469 if (m_regs_content.empty ())
470 show_registers (m_current_group);
471 else
472 {
473 for (auto &&data_item_win : m_regs_content)
474 {
475 int was_hilighted;
476
477 was_hilighted = data_item_win.highlight;
478
479 tui_get_register (frame, &data_item_win,
480 data_item_win.regno,
481 &data_item_win.highlight);
482
483 /* Register windows whose y == 0 are outside the visible area. */
484 if ((data_item_win.highlight || was_hilighted)
485 && data_item_win.y > 0)
486 data_item_win.rerender (handle.get (), m_item_width);
487 }
488 }
489
490 tui_wrefresh (handle.get ());
491 }
492
493 /* Display a register in a window. If hilite is TRUE, then the value
494 will be displayed in reverse video. */
495 void
496 tui_data_item_window::rerender (WINDOW *handle, int field_width)
497 {
498 /* In case the regs window is not boxed, we'll write the last char in the
499 last line here, causing a scroll, so prevent that. */
500 scrollok (handle, FALSE);
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) wstandout (handle);
509
510 mvwaddnstr (handle, y, x, content.c_str (), field_width - 1);
511 if (content.size () < field_width)
512 waddstr (handle, n_spaces (field_width - content.size ()));
513
514 if (highlight)
515 /* We ignore the return value, casting it to void in order to avoid
516 a compiler warning. The warning itself was introduced by a patch
517 to ncurses 5.7 dated 2009-08-29, changing this macro to expand
518 to code that causes the compiler to generate an unused-value
519 warning. */
520 (void) wstandend (handle);
521 }
522
523 /* Helper for "tui reg next", returns the next register group after
524 CURRENT_GROUP in the register group list for GDBARCH, with wrap around
525 behaviour.
526
527 If CURRENT_GROUP is nullptr (e.g. if the tui register window has only
528 just been displayed and has no current group selected) or the currently
529 selected register group can't be found (e.g. if the architecture has
530 changed since the register window was last updated), then the first
531 register group will be returned. */
532
533 static const reggroup *
534 tui_reg_next (const reggroup *current_group, struct gdbarch *gdbarch)
535 {
536 const std::vector<const reggroup *> &groups = gdbarch_reggroups (gdbarch);
537 auto it = std::find (groups.begin (), groups.end (), current_group);
538 if (it != groups.end ())
539 it++;
540 if (it == groups.end ())
541 return groups.front ();
542 return *it;
543 }
544
545 /* Helper for "tui reg prev", returns the register group previous to
546 CURRENT_GROUP in the register group list for GDBARCH, with wrap around
547 behaviour.
548
549 If CURRENT_GROUP is nullptr (e.g. if the tui register window has only
550 just been displayed and has no current group selected) or the currently
551 selected register group can't be found (e.g. if the architecture has
552 changed since the register window was last updated), then the last
553 register group will be returned. */
554
555 static const reggroup *
556 tui_reg_prev (const reggroup *current_group, struct gdbarch *gdbarch)
557 {
558 const std::vector<const reggroup *> &groups = gdbarch_reggroups (gdbarch);
559 auto it = std::find (groups.rbegin (), groups.rend (), current_group);
560 if (it != groups.rend ())
561 it++;
562 if (it == groups.rend ())
563 return groups.back ();
564 return *it;
565 }
566
567 /* Implement the 'tui reg' command. Changes the register group displayed
568 in the tui register window. Displays the tui register window if it is
569 not already on display. */
570
571 static void
572 tui_reg_command (const char *args, int from_tty)
573 {
574 struct gdbarch *gdbarch = get_current_arch ();
575
576 if (args != NULL)
577 {
578 size_t len = strlen (args);
579
580 /* Make sure the curses mode is enabled. */
581 tui_enable ();
582
583 tui_suppress_output suppress;
584
585 /* Make sure the register window is visible. If not, select an
586 appropriate layout. We need to do this before trying to run the
587 'next' or 'prev' commands. */
588 if (TUI_DATA_WIN == NULL || !TUI_DATA_WIN->is_visible ())
589 tui_regs_layout ();
590
591 const reggroup *match = nullptr;
592 const reggroup *current_group = TUI_DATA_WIN->get_current_group ();
593 if (strncmp (args, "next", len) == 0)
594 match = tui_reg_next (current_group, gdbarch);
595 else if (strncmp (args, "prev", len) == 0)
596 match = tui_reg_prev (current_group, gdbarch);
597 else
598 {
599 /* This loop matches on the initial part of a register group
600 name. If this initial part in ARGS matches only one register
601 group then the switch is made. */
602 for (const struct reggroup *group : gdbarch_reggroups (gdbarch))
603 {
604 if (strncmp (group->name (), args, len) == 0)
605 {
606 if (match != NULL)
607 error (_("ambiguous register group name '%s'"), args);
608 match = group;
609 }
610 }
611 }
612
613 if (match == NULL)
614 error (_("unknown register group '%s'"), args);
615
616 TUI_DATA_WIN->show_registers (match);
617 }
618 else
619 {
620 gdb_printf (_("\"tui reg\" must be followed by the name of "
621 "either a register group,\nor one of 'next' "
622 "or 'prev'. Known register groups are:\n"));
623
624 bool first = true;
625 for (const struct reggroup *group : gdbarch_reggroups (gdbarch))
626 {
627 if (!first)
628 gdb_printf (", ");
629 first = false;
630 gdb_printf ("%s", group->name ());
631 }
632
633 gdb_printf ("\n");
634 }
635 }
636
637 /* Complete names of register groups, and add the special "prev" and "next"
638 names. */
639
640 static void
641 tui_reggroup_completer (struct cmd_list_element *ignore,
642 completion_tracker &tracker,
643 const char *text, const char *word)
644 {
645 static const char * const extra[] = { "next", "prev", NULL };
646
647 reggroup_completer (ignore, tracker, text, word);
648
649 complete_on_enum (tracker, extra, text, word);
650 }
651
652 void _initialize_tui_regs ();
653 void
654 _initialize_tui_regs ()
655 {
656 struct cmd_list_element **tuicmd, *cmd;
657
658 tuicmd = tui_get_cmd_list ();
659
660 cmd = add_cmd ("reg", class_tui, tui_reg_command, _("\
661 TUI command to control the register window.\n\
662 Usage: tui reg NAME\n\
663 NAME is the name of the register group to display"), tuicmd);
664 set_cmd_completer (cmd, tui_reggroup_completer);
665 }