1d936f712b6e95406cfca45e60d0f93b0ddd6676
[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 ()
270 && cur_y <= viewport_height)
271 {
272 for (j = 0;
273 j < m_regs_column_count && i < m_regs_content.size ();
274 j++)
275 {
276 /* Create the window if necessary. */
277 m_regs_content[i].resize (1, item_win_width,
278 (item_win_width * j) + 1, cur_y);
279 i++; /* Next register. */
280 }
281 cur_y++; /* Next row. */
282 }
283 }
284
285 /* See tui-regs.h. */
286
287 void
288 tui_data_window::display_reg_element_at_line (int start_element_no,
289 int start_line_no)
290 {
291 int element_no = start_element_no;
292
293 if (start_element_no != 0 && start_line_no != 0)
294 {
295 int last_line_no, first_line_on_last_page;
296
297 last_line_no = last_regs_line_no ();
298 first_line_on_last_page = last_line_no - (height - 2);
299 if (first_line_on_last_page < 0)
300 first_line_on_last_page = 0;
301
302 /* If the element_no causes us to scroll past the end of the
303 registers, adjust what element to really start the
304 display at. */
305 if (start_line_no > first_line_on_last_page)
306 element_no = first_reg_element_no_inline (first_line_on_last_page);
307 }
308 display_registers_from (element_no);
309 }
310
311 /* See tui-regs.h. */
312
313 int
314 tui_data_window::display_registers_from_line (int line_no)
315 {
316 int element_no;
317
318 if (line_no < 0)
319 line_no = 0;
320 else
321 {
322 /* Make sure that we don't display off the end of the
323 registers. */
324 if (line_no >= last_regs_line_no ())
325 {
326 line_no = line_from_reg_element_no (m_regs_content.size () - 1);
327 if (line_no < 0)
328 line_no = 0;
329 }
330 }
331
332 element_no = first_reg_element_no_inline (line_no);
333 if (element_no < m_regs_content.size ())
334 display_reg_element_at_line (element_no, line_no);
335 else
336 line_no = (-1);
337
338 return line_no;
339 }
340
341
342 /* Answer the index first element displayed. If none are displayed,
343 then return (-1). */
344 int
345 tui_data_window::first_data_item_displayed ()
346 {
347 for (int i = 0; i < m_regs_content.size (); i++)
348 {
349 struct tui_gen_win_info *data_item_win;
350
351 data_item_win = &m_regs_content[i];
352 if (data_item_win->is_visible ())
353 return i;
354 }
355
356 return -1;
357 }
358
359 /* See tui-regs.h. */
360
361 void
362 tui_data_window::delete_data_content_windows ()
363 {
364 for (auto &&win : m_regs_content)
365 win.handle.reset (nullptr);
366 }
367
368
369 void
370 tui_data_window::erase_data_content (const char *prompt)
371 {
372 werase (handle.get ());
373 check_and_display_highlight_if_needed ();
374 if (prompt != NULL)
375 {
376 int half_width = (width - 2) / 2;
377 int x_pos;
378
379 if (strlen (prompt) >= half_width)
380 x_pos = 1;
381 else
382 x_pos = half_width - strlen (prompt);
383 mvwaddstr (handle.get (), (height / 2), x_pos, (char *) prompt);
384 }
385 wrefresh (handle.get ());
386 }
387
388 /* See tui-regs.h. */
389
390 void
391 tui_data_window::rerender ()
392 {
393 if (m_regs_content.empty ())
394 erase_data_content (_("[ Register Values Unavailable ]"));
395 else
396 {
397 erase_data_content (NULL);
398 delete_data_content_windows ();
399 display_registers_from (0);
400 }
401 }
402
403
404 /* Scroll the data window vertically forward or backward. */
405 void
406 tui_data_window::do_scroll_vertical (int num_to_scroll)
407 {
408 int first_element_no;
409 int first_line = (-1);
410
411 first_element_no = first_data_item_displayed ();
412 if (first_element_no < m_regs_content.size ())
413 first_line = line_from_reg_element_no (first_element_no);
414 else
415 { /* Calculate the first line from the element number which is in
416 the general data content. */
417 }
418
419 if (first_line >= 0)
420 {
421 first_line += num_to_scroll;
422 erase_data_content (NULL);
423 delete_data_content_windows ();
424 display_registers_from_line (first_line);
425 }
426 }
427
428 /* See tui-regs.h. */
429
430 void
431 tui_data_window::refresh_window ()
432 {
433 tui_gen_win_info::refresh_window ();
434 for (auto &&win : m_regs_content)
435 win.refresh_window ();
436 }
437
438 /* This function check all displayed registers for changes in values,
439 given a particular frame. If the values have changed, they are
440 updated with the new value and highlighted. */
441 void
442 tui_data_window::check_register_values (struct frame_info *frame)
443 {
444 if (m_regs_content.empty ())
445 show_registers (m_current_group);
446 else
447 {
448 for (auto &&data_item_win : m_regs_content)
449 {
450 int was_hilighted;
451
452 was_hilighted = data_item_win.highlight;
453
454 tui_get_register (frame, &data_item_win,
455 data_item_win.item_no,
456 &data_item_win.highlight);
457
458 if (data_item_win.highlight || was_hilighted)
459 data_item_win.rerender ();
460 }
461 }
462 }
463
464 /* Display a register in a window. If hilite is TRUE, then the value
465 will be displayed in reverse video. */
466 void
467 tui_data_item_window::rerender ()
468 {
469 int i;
470
471 scrollok (handle.get (), FALSE);
472 if (highlight)
473 /* We ignore the return value, casting it to void in order to avoid
474 a compiler warning. The warning itself was introduced by a patch
475 to ncurses 5.7 dated 2009-08-29, changing this macro to expand
476 to code that causes the compiler to generate an unused-value
477 warning. */
478 (void) wstandout (handle.get ());
479
480 wmove (handle.get (), 0, 0);
481 for (i = 1; i < width; i++)
482 waddch (handle.get (), ' ');
483 wmove (handle.get (), 0, 0);
484 if (content)
485 waddstr (handle.get (), content.get ());
486
487 if (highlight)
488 /* We ignore the return value, casting it to void in order to avoid
489 a compiler warning. The warning itself was introduced by a patch
490 to ncurses 5.7 dated 2009-08-29, changing this macro to expand
491 to code that causes the compiler to generate an unused-value
492 warning. */
493 (void) wstandend (handle.get ());
494 refresh_window ();
495 }
496
497 void
498 tui_data_item_window::refresh_window ()
499 {
500 if (handle != nullptr)
501 {
502 /* This seems to be needed because the data items are nested
503 windows, which according to the ncurses man pages aren't well
504 supported. */
505 touchwin (handle.get ());
506 wrefresh (handle.get ());
507 }
508 }
509
510 /* Helper for "tui reg next", wraps a call to REGGROUP_NEXT, but adds wrap
511 around behaviour. Returns the next register group, or NULL if the
512 register window is not currently being displayed. */
513
514 static struct reggroup *
515 tui_reg_next (struct reggroup *current_group, struct gdbarch *gdbarch)
516 {
517 struct reggroup *group = NULL;
518
519 if (current_group != NULL)
520 {
521 group = reggroup_next (gdbarch, current_group);
522 if (group == NULL)
523 group = reggroup_next (gdbarch, NULL);
524 }
525 return group;
526 }
527
528 /* Helper for "tui reg prev", wraps a call to REGGROUP_PREV, but adds wrap
529 around behaviour. Returns the previous register group, or NULL if the
530 register window is not currently being displayed. */
531
532 static struct reggroup *
533 tui_reg_prev (struct reggroup *current_group, struct gdbarch *gdbarch)
534 {
535 struct reggroup *group = NULL;
536
537 if (current_group != NULL)
538 {
539 group = reggroup_prev (gdbarch, current_group);
540 if (group == NULL)
541 group = reggroup_prev (gdbarch, NULL);
542 }
543 return group;
544 }
545
546 /* A helper function to display the register window in the appropriate
547 way. */
548
549 static void
550 tui_reg_layout ()
551 {
552 enum tui_layout_type cur_layout = tui_current_layout ();
553 enum tui_layout_type new_layout;
554 if (cur_layout == SRC_COMMAND || cur_layout == SRC_DATA_COMMAND)
555 new_layout = SRC_DATA_COMMAND;
556 else
557 new_layout = DISASSEM_DATA_COMMAND;
558 tui_set_layout (new_layout);
559 }
560
561 /* Implement the 'tui reg' command. Changes the register group displayed
562 in the tui register window. Displays the tui register window if it is
563 not already on display. */
564
565 static void
566 tui_reg_command (const char *args, int from_tty)
567 {
568 struct gdbarch *gdbarch = get_current_arch ();
569
570 if (args != NULL)
571 {
572 struct reggroup *group, *match = NULL;
573 size_t len = strlen (args);
574
575 /* Make sure the curses mode is enabled. */
576 tui_enable ();
577
578 /* Make sure the register window is visible. If not, select an
579 appropriate layout. We need to do this before trying to run the
580 'next' or 'prev' commands. */
581 if (TUI_DATA_WIN == NULL || !TUI_DATA_WIN->is_visible ())
582 tui_reg_layout ();
583
584 struct reggroup *current_group = TUI_DATA_WIN->get_current_group ();
585 if (strncmp (args, "next", len) == 0)
586 match = tui_reg_next (current_group, gdbarch);
587 else if (strncmp (args, "prev", len) == 0)
588 match = tui_reg_prev (current_group, gdbarch);
589
590 /* This loop matches on the initial part of a register group
591 name. If this initial part in ARGS matches only one register
592 group then the switch is made. */
593 for (group = reggroup_next (gdbarch, NULL);
594 group != NULL;
595 group = reggroup_next (gdbarch, group))
596 {
597 if (strncmp (reggroup_name (group), args, len) == 0)
598 {
599 if (match != NULL)
600 error (_("ambiguous register group name '%s'"), args);
601 match = group;
602 }
603 }
604
605 if (match == NULL)
606 error (_("unknown register group '%s'"), args);
607
608 TUI_DATA_WIN->show_registers (match);
609 }
610 else
611 {
612 struct reggroup *group;
613 int first;
614
615 printf_unfiltered (_("\"tui reg\" must be followed by the name of "
616 "either a register group,\nor one of 'next' "
617 "or 'prev'. Known register groups are:\n"));
618
619 for (first = 1, group = reggroup_next (gdbarch, NULL);
620 group != NULL;
621 first = 0, group = reggroup_next (gdbarch, group))
622 {
623 if (!first)
624 printf_unfiltered (", ");
625 printf_unfiltered ("%s", reggroup_name (group));
626 }
627
628 printf_unfiltered ("\n");
629 }
630 }
631
632 /* Complete names of register groups, and add the special "prev" and "next"
633 names. */
634
635 static void
636 tui_reggroup_completer (struct cmd_list_element *ignore,
637 completion_tracker &tracker,
638 const char *text, const char *word)
639 {
640 static const char *extra[] = { "next", "prev", NULL };
641 size_t len = strlen (word);
642 const char **tmp;
643
644 reggroup_completer (ignore, tracker, text, word);
645
646 /* XXXX use complete_on_enum instead? */
647 for (tmp = extra; *tmp != NULL; ++tmp)
648 {
649 if (strncmp (word, *tmp, len) == 0)
650 tracker.add_completion (make_unique_xstrdup (*tmp));
651 }
652 }
653
654 void
655 _initialize_tui_regs (void)
656 {
657 struct cmd_list_element **tuicmd, *cmd;
658
659 tuicmd = tui_get_cmd_list ();
660
661 cmd = add_cmd ("reg", class_tui, tui_reg_command, _("\
662 TUI command to control the register window."), tuicmd);
663 set_cmd_completer (cmd, tui_reggroup_completer);
664 }
This page took 0.044561 seconds and 3 git commands to generate.