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