]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/tui/tui-regs.c
f46894075d6040639193751a478484f922ebf3a2
[thirdparty/binutils-gdb.git] / gdb / tui / tui-regs.c
1 /* TUI display registers in window.
2
3 Copyright (C) 1998-2019 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 static void tui_display_register (struct tui_data_item_window *data);
46
47 /* Get the register from the frame and return a printable
48 representation of it. */
49
50 static gdb::unique_xmalloc_ptr<char>
51 tui_register_format (struct frame_info *frame, int regnum)
52 {
53 struct gdbarch *gdbarch = get_frame_arch (frame);
54
55 string_file stream;
56
57 scoped_restore save_pagination
58 = make_scoped_restore (&pagination_enabled, 0);
59 scoped_restore save_stdout
60 = make_scoped_restore (&gdb_stdout, &stream);
61
62 gdbarch_print_registers_info (gdbarch, &stream, frame, regnum, 1);
63
64 /* Remove the possible \n. */
65 std::string &str = stream.string ();
66 if (!str.empty () && str.back () == '\n')
67 str.resize (str.size () - 1);
68
69 /* Expand tabs into spaces, since ncurses on MS-Windows doesn't. */
70 return tui_expand_tabs (str.c_str ());
71 }
72
73 /* Get the register value from the given frame and format it for the
74 display. When changep is set, check if the new register value has
75 changed with respect to the previous call. */
76 static void
77 tui_get_register (struct frame_info *frame,
78 struct tui_data_item_window *data,
79 int regnum, bool *changedp)
80 {
81 if (changedp)
82 *changedp = false;
83 if (target_has_registers)
84 {
85 gdb::unique_xmalloc_ptr<char> new_content
86 = tui_register_format (frame, regnum);
87
88 if (changedp != NULL
89 && strcmp (data->content.get (), new_content.get ()) != 0)
90 *changedp = true;
91
92 data->content = std::move (new_content);
93 }
94 }
95
96 /* See tui-regs.h. */
97
98 int
99 tui_data_window::last_regs_line_no () const
100 {
101 int num_lines = (-1);
102
103 if (!regs_content.empty ())
104 {
105 num_lines = regs_content.size () / regs_column_count;
106 if (regs_content.size () % regs_column_count)
107 num_lines++;
108 }
109 return num_lines;
110 }
111
112 /* See tui-regs.h. */
113
114 int
115 tui_data_window::line_from_reg_element_no (int element_no) const
116 {
117 if (element_no < regs_content.size ())
118 {
119 int i, line = (-1);
120
121 i = 1;
122 while (line == (-1))
123 {
124 if (element_no < regs_column_count * i)
125 line = i - 1;
126 else
127 i++;
128 }
129
130 return line;
131 }
132 else
133 return (-1);
134 }
135
136 /* See tui-regs.h. */
137
138 int
139 tui_data_window::first_reg_element_no_inline (int line_no) const
140 {
141 if (line_no * regs_column_count <= regs_content.size ())
142 return ((line_no + 1) * regs_column_count) - regs_column_count;
143 else
144 return (-1);
145 }
146
147 /* Show the registers of the given group in the data window
148 and refresh the window. */
149 void
150 tui_data_window::show_registers (struct reggroup *group)
151 {
152 if (group == 0)
153 group = general_reggroup;
154
155 if (target_has_registers && target_has_stack && target_has_memory)
156 {
157 show_register_group (group, get_selected_frame (NULL),
158 group == current_group);
159
160 /* Clear all notation of changed values. */
161 for (auto &&data_item_win : regs_content)
162 data_item_win.highlight = false;
163 current_group = group;
164 display_all_data ();
165 }
166 else
167 {
168 current_group = 0;
169 erase_data_content (_("[ Register Values Unavailable ]"));
170 }
171 }
172
173
174 /* Set the data window to display the registers of the register group
175 using the given frame. Values are refreshed only when
176 refresh_values_only is TRUE. */
177
178 void
179 tui_data_window::show_register_group (struct reggroup *group,
180 struct frame_info *frame,
181 int refresh_values_only)
182 {
183 struct gdbarch *gdbarch = get_frame_arch (frame);
184 int nr_regs;
185 int regnum, pos;
186
187 /* Make a new title showing which group we display. */
188 xfree (title);
189 title = xstrprintf ("Register group: %s", reggroup_name (group));
190
191 /* See how many registers must be displayed. */
192 nr_regs = 0;
193 for (regnum = 0; regnum < gdbarch_num_cooked_regs (gdbarch); regnum++)
194 {
195 const char *name;
196
197 /* Must be in the group. */
198 if (!gdbarch_register_reggroup_p (gdbarch, regnum, group))
199 continue;
200
201 /* If the register name is empty, it is undefined for this
202 processor, so don't display anything. */
203 name = gdbarch_register_name (gdbarch, regnum);
204 if (name == 0 || *name == '\0')
205 continue;
206
207 nr_regs++;
208 }
209
210 regs_content.resize (nr_regs);
211
212 /* Now set the register names and values. */
213 pos = 0;
214 for (regnum = 0; regnum < gdbarch_num_cooked_regs (gdbarch); regnum++)
215 {
216 struct tui_data_item_window *data_item_win;
217 const char *name;
218
219 /* Must be in the group. */
220 if (!gdbarch_register_reggroup_p (gdbarch, regnum, group))
221 continue;
222
223 /* If the register name is empty, it is undefined for this
224 processor, so don't display anything. */
225 name = gdbarch_register_name (gdbarch, regnum);
226 if (name == 0 || *name == '\0')
227 continue;
228
229 data_item_win = &regs_content[pos];
230 if (data_item_win)
231 {
232 if (!refresh_values_only)
233 {
234 data_item_win->item_no = regnum;
235 data_item_win->name = name;
236 data_item_win->highlight = false;
237 }
238 tui_get_register (frame, data_item_win, regnum, 0);
239 }
240 pos++;
241 }
242 }
243
244 /* See tui-regs.h. */
245
246 void
247 tui_data_window::display_registers_from (int start_element_no)
248 {
249 if (!regs_content.empty ())
250 {
251 int j, item_win_width, cur_y;
252
253 int max_len = 0;
254 for (auto &&data_item_win : regs_content)
255 {
256 const char *p;
257 int len;
258
259 len = 0;
260 p = data_item_win.content.get ();
261 if (p != 0)
262 len = strlen (p);
263
264 if (len > max_len)
265 max_len = len;
266 }
267 item_win_width = max_len + 1;
268 int i = start_element_no;
269
270 regs_column_count = (width - 2) / item_win_width;
271 if (regs_column_count == 0)
272 regs_column_count = 1;
273 item_win_width = (width - 2) / regs_column_count;
274
275 /* Now create each data "sub" window, and write the display into
276 it. */
277 cur_y = 1;
278 while (i < regs_content.size ()
279 && cur_y <= viewport_height)
280 {
281 for (j = 0;
282 j < regs_column_count && i < regs_content.size ();
283 j++)
284 {
285 struct tui_data_item_window *data_item_win;
286
287 /* Create the window if necessary. */
288 data_item_win = &regs_content[i];
289 if (data_item_win->handle != NULL
290 && (data_item_win->height != 1
291 || data_item_win->width != item_win_width
292 || data_item_win->origin.x != (item_win_width * j) + 1
293 || data_item_win->origin.y != cur_y))
294 {
295 tui_delete_win (data_item_win->handle);
296 data_item_win->handle = 0;
297 }
298
299 if (data_item_win->handle == NULL)
300 {
301 data_item_win->height = 1;
302 data_item_win->width = item_win_width;
303 data_item_win->origin.x = (item_win_width * j) + 1;
304 data_item_win->origin.y = cur_y;
305 tui_make_window (data_item_win);
306 scrollok (data_item_win->handle, FALSE);
307 }
308 touchwin (data_item_win->handle);
309
310 /* Get the printable representation of the register
311 and display it. */
312 tui_display_register (data_item_win);
313 i++; /* Next register. */
314 }
315 cur_y++; /* Next row. */
316 }
317 }
318 }
319
320 /* See tui-regs.h. */
321
322 void
323 tui_data_window::display_reg_element_at_line (int start_element_no,
324 int start_line_no)
325 {
326 if (!regs_content.empty ())
327 {
328 int element_no = start_element_no;
329
330 if (start_element_no != 0 && start_line_no != 0)
331 {
332 int last_line_no, first_line_on_last_page;
333
334 last_line_no = last_regs_line_no ();
335 first_line_on_last_page = last_line_no - (height - 2);
336 if (first_line_on_last_page < 0)
337 first_line_on_last_page = 0;
338
339 /* If the element_no causes us to scroll past the end of the
340 registers, adjust what element to really start the
341 display at. */
342 if (start_line_no > first_line_on_last_page)
343 element_no = first_reg_element_no_inline (first_line_on_last_page);
344 }
345 display_registers_from (element_no);
346 }
347 }
348
349 /* See tui-regs.h. */
350
351 int
352 tui_data_window::display_registers_from_line (int line_no)
353 {
354 check_and_display_highlight_if_needed ();
355 if (!regs_content.empty ())
356 {
357 int element_no;
358
359 if (line_no < 0)
360 line_no = 0;
361 else
362 {
363 /* Make sure that we don't display off the end of the
364 registers. */
365 if (line_no >= last_regs_line_no ())
366 {
367 line_no = line_from_reg_element_no (regs_content.size () - 1);
368 if (line_no < 0)
369 line_no = 0;
370 }
371 }
372
373 element_no = first_reg_element_no_inline (line_no);
374 if (element_no < regs_content.size ())
375 display_reg_element_at_line (element_no, line_no);
376 else
377 line_no = (-1);
378
379 return line_no;
380 }
381
382 return (-1); /* Nothing was displayed. */
383 }
384
385
386 /* Answer the index first element displayed. If none are displayed,
387 then return (-1). */
388 int
389 tui_data_window::first_data_item_displayed ()
390 {
391 for (int i = 0; i < regs_content.size (); i++)
392 {
393 struct tui_gen_win_info *data_item_win;
394
395 data_item_win = &regs_content[i];
396 if (data_item_win->is_visible ())
397 return i;
398 }
399
400 return -1;
401 }
402
403 /* See tui-regs.h. */
404
405 void
406 tui_data_window::delete_data_content_windows ()
407 {
408 for (auto &&win : regs_content)
409 {
410 tui_delete_win (win.handle);
411 win.handle = NULL;
412 }
413 }
414
415
416 void
417 tui_data_window::erase_data_content (const char *prompt)
418 {
419 werase (handle);
420 check_and_display_highlight_if_needed ();
421 if (prompt != NULL)
422 {
423 int half_width = (width - 2) / 2;
424 int x_pos;
425
426 if (strlen (prompt) >= half_width)
427 x_pos = 1;
428 else
429 x_pos = half_width - strlen (prompt);
430 mvwaddstr (handle, (height / 2), x_pos, (char *) prompt);
431 }
432 wrefresh (handle);
433 }
434
435 /* See tui-regs.h. */
436
437 void
438 tui_data_window::display_all_data ()
439 {
440 if (regs_content.empty ())
441 erase_data_content (NO_DATA_STRING);
442 else
443 {
444 erase_data_content (NULL);
445 delete_data_content_windows ();
446 check_and_display_highlight_if_needed ();
447 display_registers_from (0);
448 }
449 }
450
451
452 /* Function to redisplay the contents of the data window. */
453 void
454 tui_data_window::refresh_all ()
455 {
456 erase_data_content (NULL);
457 if (!regs_content.empty ())
458 {
459 int first_element = first_data_item_displayed ();
460
461 if (first_element >= 0) /* Re-use existing windows. */
462 {
463 int first_line = (-1);
464
465 if (first_element < regs_content.size ())
466 first_line = line_from_reg_element_no (first_element);
467
468 if (first_line >= 0)
469 {
470 erase_data_content (NULL);
471 display_registers_from_line (first_line);
472 }
473 }
474 }
475 }
476
477
478 /* Scroll the data window vertically forward or backward. */
479 void
480 tui_data_window::do_scroll_vertical (int num_to_scroll)
481 {
482 int first_element_no;
483 int first_line = (-1);
484
485 first_element_no = first_data_item_displayed ();
486 if (first_element_no < regs_content.size ())
487 first_line = line_from_reg_element_no (first_element_no);
488 else
489 { /* Calculate the first line from the element number which is in
490 the general data content. */
491 }
492
493 if (first_line >= 0)
494 {
495 first_line += num_to_scroll;
496 erase_data_content (NULL);
497 delete_data_content_windows ();
498 display_registers_from_line (first_line);
499 }
500 }
501
502 /* See tui-regs.h. */
503
504 void
505 tui_data_window::rerender ()
506 {
507 /* Delete all data item windows. */
508 for (auto &&win : regs_content)
509 {
510 tui_delete_win (win.handle);
511 win.handle = NULL;
512 }
513 display_all_data ();
514 }
515
516 /* See tui-regs.h. */
517
518 void
519 tui_data_window::refresh_window ()
520 {
521 tui_gen_win_info::refresh_window ();
522 for (auto &&win : regs_content)
523 win.refresh_window ();
524 }
525
526 /* This function check all displayed registers for changes in values,
527 given a particular frame. If the values have changed, they are
528 updated with the new value and highlighted. */
529 void
530 tui_data_window::check_register_values (struct frame_info *frame)
531 {
532 if (regs_content.empty ())
533 show_registers (current_group);
534 else
535 {
536 for (auto &&data_item_win : regs_content)
537 {
538 int was_hilighted;
539
540 was_hilighted = data_item_win.highlight;
541
542 tui_get_register (frame, &data_item_win,
543 data_item_win.item_no,
544 &data_item_win.highlight);
545
546 if (data_item_win.highlight || was_hilighted)
547 tui_display_register (&data_item_win);
548 }
549 }
550 }
551
552 /* Display a register in a window. If hilite is TRUE, then the value
553 will be displayed in reverse video. */
554 static void
555 tui_display_register (struct tui_data_item_window *data)
556 {
557 if (data->handle != NULL)
558 {
559 int i;
560
561 if (data->highlight)
562 /* We ignore the return value, casting it to void in order to avoid
563 a compiler warning. The warning itself was introduced by a patch
564 to ncurses 5.7 dated 2009-08-29, changing this macro to expand
565 to code that causes the compiler to generate an unused-value
566 warning. */
567 (void) wstandout (data->handle);
568
569 wmove (data->handle, 0, 0);
570 for (i = 1; i < data->width; i++)
571 waddch (data->handle, ' ');
572 wmove (data->handle, 0, 0);
573 if (data->content)
574 waddstr (data->handle, data->content.get ());
575
576 if (data->highlight)
577 /* We ignore the return value, casting it to void in order to avoid
578 a compiler warning. The warning itself was introduced by a patch
579 to ncurses 5.7 dated 2009-08-29, changing this macro to expand
580 to code that causes the compiler to generate an unused-value
581 warning. */
582 (void) wstandend (data->handle);
583 data->refresh_window ();
584 }
585 }
586
587 /* Helper for "tui reg next", wraps a call to REGGROUP_NEXT, but adds wrap
588 around behaviour. Returns the next register group, or NULL if the
589 register window is not currently being displayed. */
590
591 static struct reggroup *
592 tui_reg_next (struct reggroup *current_group, struct gdbarch *gdbarch)
593 {
594 struct reggroup *group = NULL;
595
596 if (current_group != NULL)
597 {
598 group = reggroup_next (gdbarch, current_group);
599 if (group == NULL)
600 group = reggroup_next (gdbarch, NULL);
601 }
602 return group;
603 }
604
605 /* Helper for "tui reg prev", wraps a call to REGGROUP_PREV, but adds wrap
606 around behaviour. Returns the previous register group, or NULL if the
607 register window is not currently being displayed. */
608
609 static struct reggroup *
610 tui_reg_prev (struct reggroup *current_group, struct gdbarch *gdbarch)
611 {
612 struct reggroup *group = NULL;
613
614 if (current_group != NULL)
615 {
616 group = reggroup_prev (gdbarch, current_group);
617 if (group == NULL)
618 group = reggroup_prev (gdbarch, NULL);
619 }
620 return group;
621 }
622
623 /* A helper function to display the register window in the appropriate
624 way. */
625
626 static void
627 tui_reg_layout ()
628 {
629 enum tui_layout_type cur_layout = tui_current_layout ();
630 enum tui_layout_type new_layout;
631 if (cur_layout == SRC_COMMAND || cur_layout == SRC_DATA_COMMAND)
632 new_layout = SRC_DATA_COMMAND;
633 else
634 new_layout = DISASSEM_DATA_COMMAND;
635 tui_set_layout (new_layout);
636 }
637
638 /* Implement the 'tui reg' command. Changes the register group displayed
639 in the tui register window. Displays the tui register window if it is
640 not already on display. */
641
642 static void
643 tui_reg_command (const char *args, int from_tty)
644 {
645 struct gdbarch *gdbarch = get_current_arch ();
646
647 if (args != NULL)
648 {
649 struct reggroup *group, *match = NULL;
650 size_t len = strlen (args);
651
652 /* Make sure the curses mode is enabled. */
653 tui_enable ();
654
655 /* Make sure the register window is visible. If not, select an
656 appropriate layout. We need to do this before trying to run the
657 'next' or 'prev' commands. */
658 if (TUI_DATA_WIN == NULL || !TUI_DATA_WIN->is_visible ())
659 tui_reg_layout ();
660
661 struct reggroup *current_group = TUI_DATA_WIN->current_group;
662 if (strncmp (args, "next", len) == 0)
663 match = tui_reg_next (current_group, gdbarch);
664 else if (strncmp (args, "prev", len) == 0)
665 match = tui_reg_prev (current_group, gdbarch);
666
667 /* This loop matches on the initial part of a register group
668 name. If this initial part in ARGS matches only one register
669 group then the switch is made. */
670 for (group = reggroup_next (gdbarch, NULL);
671 group != NULL;
672 group = reggroup_next (gdbarch, group))
673 {
674 if (strncmp (reggroup_name (group), args, len) == 0)
675 {
676 if (match != NULL)
677 error (_("ambiguous register group name '%s'"), args);
678 match = group;
679 }
680 }
681
682 if (match == NULL)
683 error (_("unknown register group '%s'"), args);
684
685 TUI_DATA_WIN->show_registers (match);
686 }
687 else
688 {
689 struct reggroup *group;
690 int first;
691
692 printf_unfiltered (_("\"tui reg\" must be followed by the name of "
693 "either a register group,\nor one of 'next' "
694 "or 'prev'. Known register groups are:\n"));
695
696 for (first = 1, group = reggroup_next (gdbarch, NULL);
697 group != NULL;
698 first = 0, group = reggroup_next (gdbarch, group))
699 {
700 if (!first)
701 printf_unfiltered (", ");
702 printf_unfiltered ("%s", reggroup_name (group));
703 }
704
705 printf_unfiltered ("\n");
706 }
707 }
708
709 /* Complete names of register groups, and add the special "prev" and "next"
710 names. */
711
712 static void
713 tui_reggroup_completer (struct cmd_list_element *ignore,
714 completion_tracker &tracker,
715 const char *text, const char *word)
716 {
717 static const char *extra[] = { "next", "prev", NULL };
718 size_t len = strlen (word);
719 const char **tmp;
720
721 reggroup_completer (ignore, tracker, text, word);
722
723 /* XXXX use complete_on_enum instead? */
724 for (tmp = extra; *tmp != NULL; ++tmp)
725 {
726 if (strncmp (word, *tmp, len) == 0)
727 tracker.add_completion (make_unique_xstrdup (*tmp));
728 }
729 }
730
731 void
732 _initialize_tui_regs (void)
733 {
734 struct cmd_list_element **tuicmd, *cmd;
735
736 tuicmd = tui_get_cmd_list ();
737
738 cmd = add_cmd ("reg", class_tui, tui_reg_command, _("\
739 TUI command to control the register window."), tuicmd);
740 set_cmd_completer (cmd, tui_reggroup_completer);
741 }