2007-08-14 Michael Snyder <msnyder@access-company.com>
[external/binutils.git] / gdb / tui / tui-regs.c
1 /* TUI display registers in window.
2
3    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2007
4    Free Software Foundation, Inc.
5
6    Contributed by Hewlett-Packard Company.
7
8    This file is part of GDB.
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin Street, Fifth Floor,
23    Boston, MA 02110-1301, USA.  */
24
25 #include "defs.h"
26 #include "tui/tui.h"
27 #include "tui/tui-data.h"
28 #include "symtab.h"
29 #include "gdbtypes.h"
30 #include "gdbcmd.h"
31 #include "frame.h"
32 #include "regcache.h"
33 #include "inferior.h"
34 #include "target.h"
35 #include "gdb_string.h"
36 #include "tui/tui-layout.h"
37 #include "tui/tui-win.h"
38 #include "tui/tui-windata.h"
39 #include "tui/tui-wingeneral.h"
40 #include "tui/tui-file.h"
41 #include "reggroups.h"
42
43 #include "gdb_curses.h"
44
45
46 /*****************************************
47 ** STATIC LOCAL FUNCTIONS FORWARD DECLS    **
48 ******************************************/
49 static void
50 tui_display_register (struct tui_data_element *data,
51                       struct tui_gen_win_info *win_info);
52
53 static enum tui_status
54 tui_show_register_group (struct gdbarch *gdbarch, struct reggroup *group,
55                          struct frame_info *frame, int refresh_values_only);
56
57 static enum tui_status
58 tui_get_register (struct gdbarch *gdbarch, struct frame_info *frame,
59                   struct tui_data_element *data, int regnum, int *changedp);
60 static void tui_register_format
61   (struct gdbarch *, struct frame_info *, struct tui_data_element*, int);
62 static void tui_scroll_regs_forward_command (char *, int);
63 static void tui_scroll_regs_backward_command (char *, int);
64
65
66
67 /*****************************************
68 ** PUBLIC FUNCTIONS                     **
69 ******************************************/
70
71 /* Answer the number of the last line in the regs display.  If there
72    are no registers (-1) is returned.  */
73 int
74 tui_last_regs_line_no (void)
75 {
76   int num_lines = (-1);
77
78   if (TUI_DATA_WIN->detail.data_display_info.regs_content_count > 0)
79     {
80       num_lines = (TUI_DATA_WIN->detail.data_display_info.regs_content_count /
81                   TUI_DATA_WIN->detail.data_display_info.regs_column_count);
82       if (TUI_DATA_WIN->detail.data_display_info.regs_content_count %
83           TUI_DATA_WIN->detail.data_display_info.regs_column_count)
84         num_lines++;
85     }
86   return num_lines;
87 }
88
89
90 /* Answer the line number that the register element at element_no is
91    on.  If element_no is greater than the number of register elements
92    there are, -1 is returned.  */
93 int
94 tui_line_from_reg_element_no (int element_no)
95 {
96   if (element_no < TUI_DATA_WIN->detail.data_display_info.regs_content_count)
97     {
98       int i, line = (-1);
99
100       i = 1;
101       while (line == (-1))
102         {
103           if (element_no <
104               (TUI_DATA_WIN->detail.data_display_info.regs_column_count * i))
105             line = i - 1;
106           else
107             i++;
108         }
109
110       return line;
111     }
112   else
113     return (-1);
114 }
115
116
117 /* Answer the index of the first element in line_no.  If line_no is
118    past the register area (-1) is returned.  */
119 int
120 tui_first_reg_element_no_inline (int line_no)
121 {
122   if ((line_no * TUI_DATA_WIN->detail.data_display_info.regs_column_count)
123       <= TUI_DATA_WIN->detail.data_display_info.regs_content_count)
124     return ((line_no + 1) *
125             TUI_DATA_WIN->detail.data_display_info.regs_column_count) -
126       TUI_DATA_WIN->detail.data_display_info.regs_column_count;
127   else
128     return (-1);
129 }
130
131
132 /* Answer the index of the last element in line_no.  If line_no is
133    past the register area (-1) is returned.  */
134 int
135 tui_last_reg_element_no_in_line (int line_no)
136 {
137   if ((line_no * TUI_DATA_WIN->detail.data_display_info.regs_column_count) <=
138       TUI_DATA_WIN->detail.data_display_info.regs_content_count)
139     return ((line_no + 1) *
140             TUI_DATA_WIN->detail.data_display_info.regs_column_count) - 1;
141   else
142     return (-1);
143 }
144
145 /* Show the registers of the given group in the data window
146    and refresh the window.  */
147 void
148 tui_show_registers (struct reggroup *group)
149 {
150   enum tui_status ret = TUI_FAILURE;
151   struct tui_data_info *display_info;
152
153   /* Make sure the curses mode is enabled.  */
154   tui_enable ();
155
156   /* Make sure the register window is visible.  If not, select an
157      appropriate layout.  */
158   if (TUI_DATA_WIN == NULL || !TUI_DATA_WIN->generic.is_visible)
159     tui_set_layout_for_display_command (DATA_NAME);
160
161   display_info = &TUI_DATA_WIN->detail.data_display_info;
162   if (group == 0)
163     group = general_reggroup;
164
165   /* Say that registers should be displayed, even if there is a
166      problem.  */
167   display_info->display_regs = TRUE;
168
169   if (target_has_registers && target_has_stack && target_has_memory)
170     {
171       ret = tui_show_register_group (current_gdbarch, group,
172                                      get_current_frame (),
173                                      group == display_info->current_group);
174     }
175   if (ret == TUI_FAILURE)
176     {
177       display_info->current_group = 0;
178       tui_erase_data_content (NO_REGS_STRING);
179     }
180   else
181     {
182       int i;
183
184       /* Clear all notation of changed values.  */
185       for (i = 0; i < display_info->regs_content_count; i++)
186         {
187           struct tui_gen_win_info *data_item_win;
188           struct tui_win_element *win;
189
190           data_item_win = &display_info->regs_content[i]
191             ->which_element.data_window;
192           win = (struct tui_win_element *) data_item_win->content[0];
193           win->which_element.data.highlight = FALSE;
194         }
195       display_info->current_group = group;
196       tui_display_all_data ();
197     }
198 }
199
200
201 /* Set the data window to display the registers of the register group
202    using the given frame.  Values are refreshed only when
203    refresh_values_only is TRUE.  */
204
205 static enum tui_status
206 tui_show_register_group (struct gdbarch *gdbarch, struct reggroup *group,
207                          struct frame_info *frame, int refresh_values_only)
208 {
209   enum tui_status ret = TUI_FAILURE;
210   int nr_regs;
211   int allocated_here = FALSE;
212   int regnum, pos;
213   char title[80];
214   struct tui_data_info *display_info = &TUI_DATA_WIN->detail.data_display_info;
215
216   /* Make a new title showing which group we display.  */
217   snprintf (title, sizeof (title) - 1, "Register group: %s",
218             reggroup_name (group));
219   xfree (TUI_DATA_WIN->generic.title);
220   TUI_DATA_WIN->generic.title = xstrdup (title);
221
222   /* See how many registers must be displayed.  */
223   nr_regs = 0;
224   for (regnum = 0;
225        regnum < gdbarch_num_regs (current_gdbarch)
226                 + gdbarch_num_pseudo_regs (current_gdbarch);
227        regnum++)
228     {
229       /* Must be in the group and have a name.  */
230       if (gdbarch_register_reggroup_p (gdbarch, regnum, group)
231           && gdbarch_register_name (gdbarch, regnum) != 0)
232         nr_regs++;
233     }
234
235   if (display_info->regs_content_count > 0 && !refresh_values_only)
236     {
237       tui_free_data_content (display_info->regs_content,
238                              display_info->regs_content_count);
239       display_info->regs_content_count = 0;
240     }
241
242   if (display_info->regs_content_count <= 0)
243     {
244       display_info->regs_content = tui_alloc_content (nr_regs, DATA_WIN);
245       allocated_here = TRUE;
246       refresh_values_only = FALSE;
247     }
248
249   if (display_info->regs_content != (tui_win_content) NULL)
250     {
251       if (!refresh_values_only || allocated_here)
252         {
253           TUI_DATA_WIN->generic.content = (void*) NULL;
254           TUI_DATA_WIN->generic.content_size = 0;
255           tui_add_content_elements (&TUI_DATA_WIN->generic, nr_regs);
256           display_info->regs_content
257             = (tui_win_content) TUI_DATA_WIN->generic.content;
258           display_info->regs_content_count = nr_regs;
259         }
260
261       /* Now set the register names and values.  */
262       pos = 0;
263       for (regnum = 0;
264            regnum < gdbarch_num_regs (current_gdbarch)
265                     + gdbarch_num_pseudo_regs (current_gdbarch);
266            regnum++)
267         {
268           struct tui_gen_win_info *data_item_win;
269           struct tui_data_element *data;
270           const char *name;
271
272           if (!gdbarch_register_reggroup_p (gdbarch, regnum, group))
273             continue;
274
275           name = gdbarch_register_name (gdbarch, regnum);
276           if (name == 0)
277             continue;
278
279           data_item_win =
280             &display_info->regs_content[pos]->which_element.data_window;
281           data =
282             &((struct tui_win_element *) data_item_win->content[0])->which_element.data;
283           if (data)
284             {
285               if (!refresh_values_only)
286                 {
287                   data->item_no = regnum;
288                   data->name = name;
289                   data->highlight = FALSE;
290                 }
291               if (data->value == (void*) NULL)
292                 data->value = (void*) xmalloc (MAX_REGISTER_SIZE);
293
294               tui_get_register (gdbarch, frame, data, regnum, 0);
295             }
296           pos++;
297         }
298
299       TUI_DATA_WIN->generic.content_size =
300         display_info->regs_content_count + display_info->data_content_count;
301       ret = TUI_SUCCESS;
302     }
303
304   return ret;
305 }
306
307 /* Function to display the registers in the content from
308    'start_element_no' until the end of the register content or the end
309    of the display height.  No checking for displaying past the end of
310    the registers is done here.  */
311 void
312 tui_display_registers_from (int start_element_no)
313 {
314   struct tui_data_info *display_info = &TUI_DATA_WIN->detail.data_display_info;
315
316   if (display_info->regs_content != (tui_win_content) NULL &&
317       display_info->regs_content_count > 0)
318     {
319       int i = start_element_no;
320       int j, value_chars_wide, item_win_width, cur_y;
321
322       int max_len = 0;
323       for (i = 0; i < display_info->regs_content_count; i++)
324         {
325           struct tui_data_element *data;
326           struct tui_gen_win_info *data_item_win;
327           char *p;
328           int len;
329
330           data_item_win = &display_info->regs_content[i]->which_element.data_window;
331           data = &((struct tui_win_element *)
332                    data_item_win->content[0])->which_element.data;
333           len = 0;
334           p = data->content;
335           if (p != 0)
336             while (*p)
337               {
338                 if (*p++ == '\t')
339                   len = 8 * ((len / 8) + 1);
340                 else
341                   len++;
342               }
343
344           if (len > max_len)
345             max_len = len;
346         }
347       item_win_width = max_len + 1;
348       i = start_element_no;
349
350       display_info->regs_column_count =
351         (TUI_DATA_WIN->generic.width - 2) / item_win_width;
352       if (display_info->regs_column_count == 0)
353         display_info->regs_column_count = 1;
354       item_win_width =
355         (TUI_DATA_WIN->generic.width - 2) / display_info->regs_column_count;
356
357       /*
358          ** Now create each data "sub" window, and write the display
359          ** into it.
360        */
361       cur_y = 1;
362       while (i < display_info->regs_content_count &&
363              cur_y <= TUI_DATA_WIN->generic.viewport_height)
364         {
365           for (j = 0;
366                (j < display_info->regs_column_count &&
367                 i < display_info->regs_content_count); j++)
368             {
369               struct tui_gen_win_info *data_item_win;
370               struct tui_data_element *data_element_ptr;
371
372               /* Create the window if necessary.  */
373               data_item_win = &display_info->regs_content[i]
374                 ->which_element.data_window;
375               data_element_ptr = &((struct tui_win_element *)
376                                  data_item_win->content[0])->which_element.data;
377               if (data_item_win->handle != (WINDOW*) NULL
378                   && (data_item_win->height != 1
379                       || data_item_win->width != item_win_width
380                       || data_item_win->origin.x != (item_win_width * j) + 1
381                       || data_item_win->origin.y != cur_y))
382                 {
383                   tui_delete_win (data_item_win->handle);
384                   data_item_win->handle = 0;
385                 }
386                   
387               if (data_item_win->handle == (WINDOW *) NULL)
388                 {
389                   data_item_win->height = 1;
390                   data_item_win->width = item_win_width;
391                   data_item_win->origin.x = (item_win_width * j) + 1;
392                   data_item_win->origin.y = cur_y;
393                   tui_make_window (data_item_win, DONT_BOX_WINDOW);
394                   scrollok (data_item_win->handle, FALSE);
395                 }
396               touchwin (data_item_win->handle);
397
398               /* Get the printable representation of the register
399                  and display it.  */
400               tui_display_register (data_element_ptr, data_item_win);
401               i++;              /* Next register.  */
402             }
403           cur_y++;              /* Next row.  */
404         }
405     }
406 }
407
408
409 /* Function to display the registers in the content from
410    'start_element_no' on 'start_line_no' until the end of the register
411    content or the end of the display height.  This function checks
412    that we won't display off the end of the register display.  */
413 void
414 tui_display_reg_element_at_line (int start_element_no, int start_line_no)
415 {
416   if (TUI_DATA_WIN->detail.data_display_info.regs_content != (tui_win_content) NULL &&
417       TUI_DATA_WIN->detail.data_display_info.regs_content_count > 0)
418     {
419       int element_no = start_element_no;
420
421       if (start_element_no != 0 && start_line_no != 0)
422         {
423           int last_line_no, first_line_on_last_page;
424
425           last_line_no = tui_last_regs_line_no ();
426           first_line_on_last_page = last_line_no - (TUI_DATA_WIN->generic.height - 2);
427           if (first_line_on_last_page < 0)
428             first_line_on_last_page = 0;
429           /*
430              ** If there is no other data displayed except registers,
431              ** and the element_no causes us to scroll past the end of
432              ** the registers, adjust what element to really start the
433              ** display at.
434            */
435           if (TUI_DATA_WIN->detail.data_display_info.data_content_count <= 0 &&
436               start_line_no > first_line_on_last_page)
437             element_no = tui_first_reg_element_no_inline (first_line_on_last_page);
438         }
439       tui_display_registers_from (element_no);
440     }
441 }
442
443
444
445 /* Function to display the registers starting at line line_no in the
446    data window.  Answers the line number that the display actually
447    started from.  If nothing is displayed (-1) is returned.  */
448 int
449 tui_display_registers_from_line (int line_no, int force_display)
450 {
451   if (TUI_DATA_WIN->detail.data_display_info.regs_content_count > 0)
452     {
453       int line, element_no;
454
455       if (line_no < 0)
456         line = 0;
457       else if (force_display)
458         { /*
459            ** If we must display regs (force_display is true), then make
460            ** sure that we don't display off the end of the registers.
461           */
462           if (line_no >= tui_last_regs_line_no ())
463             {
464               if ((line = tui_line_from_reg_element_no (
465                  TUI_DATA_WIN->detail.data_display_info.regs_content_count - 1)) < 0)
466                 line = 0;
467             }
468           else
469             line = line_no;
470         }
471       else
472         line = line_no;
473
474       element_no = tui_first_reg_element_no_inline (line);
475       if (element_no < TUI_DATA_WIN->detail.data_display_info.regs_content_count)
476         tui_display_reg_element_at_line (element_no, line);
477       else
478         line = (-1);
479
480       return line;
481     }
482
483   return (-1);                  /* Nothing was displayed.  */
484 }
485
486
487 /* This function check all displayed registers for changes in values,
488    given a particular frame.  If the values have changed, they are
489    updated with the new value and highlighted.  */
490 void
491 tui_check_register_values (struct frame_info *frame)
492 {
493   if (TUI_DATA_WIN != NULL && TUI_DATA_WIN->generic.is_visible)
494     {
495       struct tui_data_info *display_info
496         = &TUI_DATA_WIN->detail.data_display_info;
497
498       if (display_info->regs_content_count <= 0 && display_info->display_regs)
499         tui_show_registers (display_info->current_group);
500       else
501         {
502           int i, j;
503
504           for (i = 0; (i < display_info->regs_content_count); i++)
505             {
506               struct tui_data_element *data;
507               struct tui_gen_win_info *data_item_win_ptr;
508               int was_hilighted;
509
510               data_item_win_ptr = &display_info->regs_content[i]->
511                 which_element.data_window;
512               data = &((struct tui_win_element *)
513                        data_item_win_ptr->content[0])->which_element.data;
514               was_hilighted = data->highlight;
515
516               tui_get_register (current_gdbarch, frame, data,
517                                 data->item_no, &data->highlight);
518
519               if (data->highlight || was_hilighted)
520                 {
521                   tui_display_register (data, data_item_win_ptr);
522                 }
523             }
524         }
525     }
526 }
527
528 /* Display a register in a window.  If hilite is TRUE, then the value
529    will be displayed in reverse video.  */
530 static void
531 tui_display_register (struct tui_data_element *data,
532                       struct tui_gen_win_info *win_info)
533 {
534   if (win_info->handle != (WINDOW *) NULL)
535     {
536       int i;
537
538       if (data->highlight)
539         wstandout (win_info->handle);
540       
541       wmove (win_info->handle, 0, 0);
542       for (i = 1; i < win_info->width; i++)
543         waddch (win_info->handle, ' ');
544       wmove (win_info->handle, 0, 0);
545       if (data->content)
546         waddstr (win_info->handle, data->content);
547
548       if (data->highlight)
549         wstandend (win_info->handle);
550       tui_refresh_win (win_info);
551     }
552 }
553
554 static void
555 tui_reg_next_command (char *arg, int from_tty)
556 {
557   if (TUI_DATA_WIN != 0)
558     {
559       struct reggroup *group
560         = TUI_DATA_WIN->detail.data_display_info.current_group;
561
562       group = reggroup_next (current_gdbarch, group);
563       if (group == 0)
564         group = reggroup_next (current_gdbarch, 0);
565
566       if (group)
567         tui_show_registers (group);
568     }
569 }
570
571 static void
572 tui_reg_float_command (char *arg, int from_tty)
573 {
574   tui_show_registers (float_reggroup);
575 }
576
577 static void
578 tui_reg_general_command (char *arg, int from_tty)
579 {
580   tui_show_registers (general_reggroup);
581 }
582
583 static void
584 tui_reg_system_command (char *arg, int from_tty)
585 {
586   tui_show_registers (system_reggroup);
587 }
588
589 static struct cmd_list_element *tuireglist;
590
591 static void
592 tui_reg_command (char *args, int from_tty)
593 {
594   printf_unfiltered (_("\"tui reg\" must be followed by the name of a "
595                      "tui reg command.\n"));
596   help_list (tuireglist, "tui reg ", -1, gdb_stdout);
597 }
598
599 void
600 _initialize_tui_regs (void)
601 {
602   struct cmd_list_element **tuicmd;
603
604   tuicmd = tui_get_cmd_list ();
605
606   add_prefix_cmd ("reg", class_tui, tui_reg_command,
607                   _("TUI commands to control the register window."),
608                   &tuireglist, "tui reg ", 0,
609                   tuicmd);
610
611   add_cmd ("float", class_tui, tui_reg_float_command,
612            _("Display only floating point registers."),
613            &tuireglist);
614   add_cmd ("general", class_tui, tui_reg_general_command,
615            _("Display only general registers."),
616            &tuireglist);
617   add_cmd ("system", class_tui, tui_reg_system_command,
618            _("Display only system registers."),
619            &tuireglist);
620   add_cmd ("next", class_tui, tui_reg_next_command,
621            _("Display next register group."),
622            &tuireglist);
623
624   if (xdb_commands)
625     {
626       add_com ("fr", class_tui, tui_reg_float_command,
627                _("Display only floating point registers\n"));
628       add_com ("gr", class_tui, tui_reg_general_command,
629                _("Display only general registers\n"));
630       add_com ("sr", class_tui, tui_reg_system_command,
631                _("Display only special registers\n"));
632       add_com ("+r", class_tui, tui_scroll_regs_forward_command,
633                _("Scroll the registers window forward\n"));
634       add_com ("-r", class_tui, tui_scroll_regs_backward_command,
635                _("Scroll the register window backward\n"));
636     }
637 }
638
639
640 /*****************************************
641 ** STATIC LOCAL FUNCTIONS                 **
642 ******************************************/
643
644 extern int pagination_enabled;
645
646 static void
647 tui_restore_gdbout (void *ui)
648 {
649   ui_file_delete (gdb_stdout);
650   gdb_stdout = (struct ui_file*) ui;
651   pagination_enabled = 1;
652 }
653
654 /* Get the register from the frame and make a printable representation
655    of it in the data element.  */
656 static void
657 tui_register_format (struct gdbarch *gdbarch, struct frame_info *frame,
658                      struct tui_data_element *data_element, int regnum)
659 {
660   struct ui_file *stream;
661   struct ui_file *old_stdout;
662   const char *name;
663   struct cleanup *cleanups;
664   char *p, *s;
665   int pos;
666   struct type *type = register_type (gdbarch, regnum);
667
668   name = gdbarch_register_name (gdbarch, regnum);
669   if (name == 0)
670     {
671       return;
672     }
673   
674   pagination_enabled = 0;
675   old_stdout = gdb_stdout;
676   stream = tui_sfileopen (256);
677   gdb_stdout = stream;
678   cleanups = make_cleanup (tui_restore_gdbout, (void*) old_stdout);
679   if (TYPE_VECTOR (type) != 0 && 0)
680     {
681       gdb_byte buf[MAX_REGISTER_SIZE];
682       int len;
683
684       len = register_size (current_gdbarch, regnum);
685       fprintf_filtered (stream, "%-14s ", name);
686       get_frame_register (frame, regnum, buf);
687       print_scalar_formatted (buf, type, 'f', len, stream);
688     }
689   else
690     {
691       gdbarch_print_registers_info (current_gdbarch, stream,
692                                     frame, regnum, 1);
693     }
694
695   /* Save formatted output in the buffer.  */
696   p = tui_file_get_strbuf (stream);
697
698   /* Remove the possible \n.  */
699   s = strrchr (p, '\n');
700   if (s && s[1] == 0)
701     *s = 0;
702
703   xfree (data_element->content);
704   data_element->content = xstrdup (p);
705   do_cleanups (cleanups);
706 }
707
708 /* Get the register value from the given frame and format it for the
709    display.  When changep is set, check if the new register value has
710    changed with respect to the previous call.  */
711 static enum tui_status
712 tui_get_register (struct gdbarch *gdbarch, struct frame_info *frame,
713                   struct tui_data_element *data, int regnum, int *changedp)
714 {
715   enum tui_status ret = TUI_FAILURE;
716
717   if (changedp)
718     *changedp = FALSE;
719   if (target_has_registers)
720     {
721       gdb_byte buf[MAX_REGISTER_SIZE];
722       get_frame_register (frame, regnum, buf);
723
724       if (changedp)
725         {
726           int size = register_size (gdbarch, regnum);
727           char *old = (char*) data->value;
728           int i;
729
730           for (i = 0; i < size; i++)
731             if (buf[i] != old[i])
732               {
733                 *changedp = TRUE;
734                 old[i] = buf[i];
735               }
736         }
737
738       /* Reformat the data content if the value changed.  */
739       if (changedp == 0 || *changedp == TRUE)
740         tui_register_format (gdbarch, frame, data, regnum);
741
742       ret = TUI_SUCCESS;
743     }
744   return ret;
745 }
746
747 static void
748 tui_scroll_regs_forward_command (char *arg, int from_tty)
749 {
750   tui_scroll (FORWARD_SCROLL, TUI_DATA_WIN, 1);
751 }
752
753
754 static void
755 tui_scroll_regs_backward_command (char *arg, int from_tty)
756 {
757   tui_scroll (BACKWARD_SCROLL, TUI_DATA_WIN, 1);
758 }