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