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