Remove tui_gen_win_info::viewport_height
[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 = m_regs_content.size () / m_regs_column_count;
100 if (m_regs_content.size () % m_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 < m_regs_content.size ())
111 {
112 int i, line = (-1);
113
114 i = 1;
115 while (line == (-1))
116 {
117 if (element_no < m_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 * m_regs_column_count <= m_regs_content.size ())
135 return ((line_no + 1) * m_regs_column_count) - m_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 == m_current_group);
152
153 /* Clear all notation of changed values. */
154 for (auto &&data_item_win : m_regs_content)
155 data_item_win.highlight = false;
156 m_current_group = group;
157 }
158 else
159 {
160 m_current_group = 0;
161 m_regs_content.clear ();
162 }
163
164 rerender ();
165 }
166
167
168 /* Set the data window to display the registers of the register group
169 using the given frame. Values are refreshed only when
170 refresh_values_only is true. */
171
172 void
173 tui_data_window::show_register_group (struct reggroup *group,
174 struct frame_info *frame,
175 bool refresh_values_only)
176 {
177 struct gdbarch *gdbarch = get_frame_arch (frame);
178 int nr_regs;
179 int regnum, pos;
180
181 /* Make a new title showing which group we display. */
182 title = string_printf ("Register group: %s", reggroup_name (group));
183
184 /* See how many registers must be displayed. */
185 nr_regs = 0;
186 for (regnum = 0; regnum < gdbarch_num_cooked_regs (gdbarch); regnum++)
187 {
188 const char *name;
189
190 /* Must be in the group. */
191 if (!gdbarch_register_reggroup_p (gdbarch, regnum, group))
192 continue;
193
194 /* If the register name is empty, it is undefined for this
195 processor, so don't display anything. */
196 name = gdbarch_register_name (gdbarch, regnum);
197 if (name == 0 || *name == '\0')
198 continue;
199
200 nr_regs++;
201 }
202
203 m_regs_content.resize (nr_regs);
204
205 /* Now set the register names and values. */
206 pos = 0;
207 for (regnum = 0; regnum < gdbarch_num_cooked_regs (gdbarch); regnum++)
208 {
209 struct tui_data_item_window *data_item_win;
210 const char *name;
211
212 /* Must be in the group. */
213 if (!gdbarch_register_reggroup_p (gdbarch, regnum, group))
214 continue;
215
216 /* If the register name is empty, it is undefined for this
217 processor, so don't display anything. */
218 name = gdbarch_register_name (gdbarch, regnum);
219 if (name == 0 || *name == '\0')
220 continue;
221
222 data_item_win = &m_regs_content[pos];
223 if (data_item_win)
224 {
225 if (!refresh_values_only)
226 {
227 data_item_win->item_no = regnum;
228 data_item_win->name = name;
229 data_item_win->highlight = false;
230 }
231 tui_get_register (frame, data_item_win, regnum, 0);
232 }
233 pos++;
234 }
235 }
236
237 /* See tui-regs.h. */
238
239 void
240 tui_data_window::display_registers_from (int start_element_no)
241 {
242 int j, item_win_width, cur_y;
243
244 int max_len = 0;
245 for (auto &&data_item_win : m_regs_content)
246 {
247 const char *p;
248 int len;
249
250 len = 0;
251 p = data_item_win.content.get ();
252 if (p != 0)
253 len = strlen (p);
254
255 if (len > max_len)
256 max_len = len;
257 }
258 item_win_width = max_len + 1;
259 int i = start_element_no;
260
261 m_regs_column_count = (width - 2) / item_win_width;
262 if (m_regs_column_count == 0)
263 m_regs_column_count = 1;
264 item_win_width = (width - 2) / m_regs_column_count;
265
266 /* Now create each data "sub" window, and write the display into
267 it. */
268 cur_y = 1;
269 while (i < m_regs_content.size () && cur_y <= height - 2)
270 {
271 for (j = 0;
272 j < m_regs_column_count && i < m_regs_content.size ();
273 j++)
274 {
275 /* Create the window if necessary. */
276 m_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 (m_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 < m_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 < m_regs_content.size (); i++)
347 {
348 struct tui_gen_win_info *data_item_win;
349
350 data_item_win = &m_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 : m_regs_content)
364 win.handle.reset (nullptr);
365 }
366
367
368 void
369 tui_data_window::erase_data_content (const char *prompt)
370 {
371 werase (handle.get ());
372 check_and_display_highlight_if_needed ();
373 if (prompt != NULL)
374 {
375 int half_width = (width - 2) / 2;
376 int x_pos;
377
378 if (strlen (prompt) >= half_width)
379 x_pos = 1;
380 else
381 x_pos = half_width - strlen (prompt);
382 mvwaddstr (handle.get (), (height / 2), x_pos, (char *) prompt);
383 }
384 wrefresh (handle.get ());
385 }
386
387 /* See tui-regs.h. */
388
389 void
390 tui_data_window::rerender ()
391 {
392 if (m_regs_content.empty ())
393 erase_data_content (_("[ Register Values Unavailable ]"));
394 else
395 {
396 erase_data_content (NULL);
397 delete_data_content_windows ();
398 display_registers_from (0);
399 }
400 }
401
402
403 /* Scroll the data window vertically forward or backward. */
404 void
405 tui_data_window::do_scroll_vertical (int num_to_scroll)
406 {
407 int first_element_no;
408 int first_line = (-1);
409
410 first_element_no = first_data_item_displayed ();
411 if (first_element_no < m_regs_content.size ())
412 first_line = line_from_reg_element_no (first_element_no);
413 else
414 { /* Calculate the first line from the element number which is in
415 the general data content. */
416 }
417
418 if (first_line >= 0)
419 {
420 first_line += num_to_scroll;
421 erase_data_content (NULL);
422 delete_data_content_windows ();
423 display_registers_from_line (first_line);
424 }
425 }
426
427 /* See tui-regs.h. */
428
429 void
430 tui_data_window::refresh_window ()
431 {
432 tui_gen_win_info::refresh_window ();
433 for (auto &&win : m_regs_content)
434 win.refresh_window ();
435 }
436
437 /* This function check all displayed registers for changes in values,
438 given a particular frame. If the values have changed, they are
439 updated with the new value and highlighted. */
440 void
441 tui_data_window::check_register_values (struct frame_info *frame)
442 {
443 if (m_regs_content.empty ())
444 show_registers (m_current_group);
445 else
446 {
447 for (auto &&data_item_win : m_regs_content)
448 {
449 int was_hilighted;
450
451 was_hilighted = data_item_win.highlight;
452
453 tui_get_register (frame, &data_item_win,
454 data_item_win.item_no,
455 &data_item_win.highlight);
456
457 if (data_item_win.highlight || was_hilighted)
458 data_item_win.rerender ();
459 }
460 }
461 }
462
463 /* Display a register in a window. If hilite is TRUE, then the value
464 will be displayed in reverse video. */
465 void
466 tui_data_item_window::rerender ()
467 {
468 int i;
469
470 scrollok (handle.get (), FALSE);
471 if (highlight)
472 /* We ignore the return value, casting it to void in order to avoid
473 a compiler warning. The warning itself was introduced by a patch
474 to ncurses 5.7 dated 2009-08-29, changing this macro to expand
475 to code that causes the compiler to generate an unused-value
476 warning. */
477 (void) wstandout (handle.get ());
478
479 wmove (handle.get (), 0, 0);
480 for (i = 1; i < width; i++)
481 waddch (handle.get (), ' ');
482 wmove (handle.get (), 0, 0);
483 if (content)
484 waddstr (handle.get (), content.get ());
485
486 if (highlight)
487 /* We ignore the return value, casting it to void in order to avoid
488 a compiler warning. The warning itself was introduced by a patch
489 to ncurses 5.7 dated 2009-08-29, changing this macro to expand
490 to code that causes the compiler to generate an unused-value
491 warning. */
492 (void) wstandend (handle.get ());
493 refresh_window ();
494 }
495
496 void
497 tui_data_item_window::refresh_window ()
498 {
499 if (handle != nullptr)
500 {
501 /* This seems to be needed because the data items are nested
502 windows, which according to the ncurses man pages aren't well
503 supported. */
504 touchwin (handle.get ());
505 wrefresh (handle.get ());
506 }
507 }
508
509 /* Helper for "tui reg next", wraps a call to REGGROUP_NEXT, but adds wrap
510 around behaviour. Returns the next register group, or NULL if the
511 register window is not currently being displayed. */
512
513 static struct reggroup *
514 tui_reg_next (struct reggroup *current_group, struct gdbarch *gdbarch)
515 {
516 struct reggroup *group = NULL;
517
518 if (current_group != NULL)
519 {
520 group = reggroup_next (gdbarch, current_group);
521 if (group == NULL)
522 group = reggroup_next (gdbarch, NULL);
523 }
524 return group;
525 }
526
527 /* Helper for "tui reg prev", wraps a call to REGGROUP_PREV, but adds wrap
528 around behaviour. Returns the previous register group, or NULL if the
529 register window is not currently being displayed. */
530
531 static struct reggroup *
532 tui_reg_prev (struct reggroup *current_group, struct gdbarch *gdbarch)
533 {
534 struct reggroup *group = NULL;
535
536 if (current_group != NULL)
537 {
538 group = reggroup_prev (gdbarch, current_group);
539 if (group == NULL)
540 group = reggroup_prev (gdbarch, NULL);
541 }
542 return group;
543 }
544
545 /* A helper function to display the register window in the appropriate
546 way. */
547
548 static void
549 tui_reg_layout ()
550 {
551 enum tui_layout_type cur_layout = tui_current_layout ();
552 enum tui_layout_type new_layout;
553 if (cur_layout == SRC_COMMAND || cur_layout == SRC_DATA_COMMAND)
554 new_layout = SRC_DATA_COMMAND;
555 else
556 new_layout = DISASSEM_DATA_COMMAND;
557 tui_set_layout (new_layout);
558 }
559
560 /* Implement the 'tui reg' command. Changes the register group displayed
561 in the tui register window. Displays the tui register window if it is
562 not already on display. */
563
564 static void
565 tui_reg_command (const char *args, int from_tty)
566 {
567 struct gdbarch *gdbarch = get_current_arch ();
568
569 if (args != NULL)
570 {
571 struct reggroup *group, *match = NULL;
572 size_t len = strlen (args);
573
574 /* Make sure the curses mode is enabled. */
575 tui_enable ();
576
577 /* Make sure the register window is visible. If not, select an
578 appropriate layout. We need to do this before trying to run the
579 'next' or 'prev' commands. */
580 if (TUI_DATA_WIN == NULL || !TUI_DATA_WIN->is_visible ())
581 tui_reg_layout ();
582
583 struct reggroup *current_group = TUI_DATA_WIN->get_current_group ();
584 if (strncmp (args, "next", len) == 0)
585 match = tui_reg_next (current_group, gdbarch);
586 else if (strncmp (args, "prev", len) == 0)
587 match = tui_reg_prev (current_group, gdbarch);
588
589 /* This loop matches on the initial part of a register group
590 name. If this initial part in ARGS matches only one register
591 group then the switch is made. */
592 for (group = reggroup_next (gdbarch, NULL);
593 group != NULL;
594 group = reggroup_next (gdbarch, group))
595 {
596 if (strncmp (reggroup_name (group), args, len) == 0)
597 {
598 if (match != NULL)
599 error (_("ambiguous register group name '%s'"), args);
600 match = group;
601 }
602 }
603
604 if (match == NULL)
605 error (_("unknown register group '%s'"), args);
606
607 TUI_DATA_WIN->show_registers (match);
608 }
609 else
610 {
611 struct reggroup *group;
612 int first;
613
614 printf_unfiltered (_("\"tui reg\" must be followed by the name of "
615 "either a register group,\nor one of 'next' "
616 "or 'prev'. Known register groups are:\n"));
617
618 for (first = 1, group = reggroup_next (gdbarch, NULL);
619 group != NULL;
620 first = 0, group = reggroup_next (gdbarch, group))
621 {
622 if (!first)
623 printf_unfiltered (", ");
624 printf_unfiltered ("%s", reggroup_name (group));
625 }
626
627 printf_unfiltered ("\n");
628 }
629 }
630
631 /* Complete names of register groups, and add the special "prev" and "next"
632 names. */
633
634 static void
635 tui_reggroup_completer (struct cmd_list_element *ignore,
636 completion_tracker &tracker,
637 const char *text, const char *word)
638 {
639 static const char *extra[] = { "next", "prev", NULL };
640 size_t len = strlen (word);
641 const char **tmp;
642
643 reggroup_completer (ignore, tracker, text, word);
644
645 /* XXXX use complete_on_enum instead? */
646 for (tmp = extra; *tmp != NULL; ++tmp)
647 {
648 if (strncmp (word, *tmp, len) == 0)
649 tracker.add_completion (make_unique_xstrdup (*tmp));
650 }
651 }
652
653 void
654 _initialize_tui_regs (void)
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."), tuicmd);
662 set_cmd_completer (cmd, tui_reggroup_completer);
663 }
This page took 0.069191 seconds and 4 git commands to generate.