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