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