1/* TUI display registers in window.
2
3   Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
4   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., 59 Temple Place - Suite 330,
23   Boston, MA 02111-1307, 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******************************************/
49static void
50tui_display_register (struct tui_data_element *data,
51                      struct tui_gen_win_info *win_info);
52
53static enum tui_status
54tui_show_register_group (struct gdbarch *gdbarch, struct reggroup *group,
55                         struct frame_info *frame, int refresh_values_only);
56
57static enum tui_status
58tui_get_register (struct gdbarch *gdbarch, struct frame_info *frame,
59                  struct tui_data_element *data, int regnum, int *changedp);
60static void tui_register_format
61  (struct gdbarch *, struct frame_info *, struct tui_data_element*, int);
62static void tui_scroll_regs_forward_command (char *, int);
63static 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.  */
73int
74tui_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.  */
93int
94tui_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 past
118   the register area (-1) is returned.  */
119int
120tui_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.  */
134int
135tui_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.  */
147void
148tui_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 problem.  */
166  display_info->display_regs = TRUE;
167
168  if (target_has_registers && target_has_stack && target_has_memory)
169    {
170      ret = tui_show_register_group (current_gdbarch, group,
171                                     get_current_frame (),
172                                     group == display_info->current_group);
173    }
174  if (ret == TUI_FAILURE)
175    {
176      display_info->current_group = 0;
177      tui_erase_data_content (NO_REGS_STRING);
178    }
179  else
180    {
181      int i;
182
183      /* Clear all notation of changed values */
184      for (i = 0; i < display_info->regs_content_count; i++)
185	{
186	  struct tui_gen_win_info *data_item_win;
187          struct tui_win_element *win;
188
189	  data_item_win = &display_info->regs_content[i]
190            ->which_element.data_window;
191          win = (struct tui_win_element *) data_item_win->content[0];
192          win->which_element.data.highlight = FALSE;
193	}
194      display_info->current_group = group;
195      tui_display_all_data ();
196    }
197}
198
199
200/* Set the data window to display the registers of the register group
201   using the given frame.  Values are refreshed only when refresh_values_only
202   is TRUE.  */
203
204static enum tui_status
205tui_show_register_group (struct gdbarch *gdbarch, struct reggroup *group,
206                         struct frame_info *frame, int refresh_values_only)
207{
208  enum tui_status ret = TUI_FAILURE;
209  int nr_regs;
210  int allocated_here = FALSE;
211  int regnum, pos;
212  char title[80];
213  struct tui_data_info *display_info = &TUI_DATA_WIN->detail.data_display_info;
214
215  /* Make a new title showing which group we display.  */
216  snprintf (title, sizeof (title) - 1, "Register group: %s",
217            reggroup_name (group));
218  xfree (TUI_DATA_WIN->generic.title);
219  TUI_DATA_WIN->generic.title = xstrdup (title);
220
221  /* See how many registers must be displayed.  */
222  nr_regs = 0;
223  for (regnum = 0; regnum < NUM_REGS + NUM_PSEUDO_REGS; regnum++)
224    {
225      /* Must be in the group and have a name.  */
226      if (gdbarch_register_reggroup_p (gdbarch, regnum, group)
227          && gdbarch_register_name (gdbarch, regnum) != 0)
228        nr_regs++;
229    }
230
231  if (display_info->regs_content_count > 0 && !refresh_values_only)
232    {
233      tui_free_data_content (display_info->regs_content,
234                             display_info->regs_content_count);
235      display_info->regs_content_count = 0;
236    }
237
238  if (display_info->regs_content_count <= 0)
239    {
240      display_info->regs_content = tui_alloc_content (nr_regs, DATA_WIN);
241      allocated_here = TRUE;
242      refresh_values_only = FALSE;
243    }
244
245  if (display_info->regs_content != (tui_win_content) NULL)
246    {
247      if (!refresh_values_only || allocated_here)
248	{
249	  TUI_DATA_WIN->generic.content = (void*) NULL;
250	  TUI_DATA_WIN->generic.content_size = 0;
251	  tui_add_content_elements (&TUI_DATA_WIN->generic, nr_regs);
252	  display_info->regs_content
253            = (tui_win_content) TUI_DATA_WIN->generic.content;
254	  display_info->regs_content_count = nr_regs;
255	}
256
257      /* Now set the register names and values */
258      pos = 0;
259      for (regnum = 0; regnum < NUM_REGS + NUM_PSEUDO_REGS; regnum++)
260        {
261	  struct tui_gen_win_info *data_item_win;
262          struct tui_data_element *data;
263          const char *name;
264
265          if (!gdbarch_register_reggroup_p (gdbarch, regnum, group))
266            continue;
267
268          name = gdbarch_register_name (gdbarch, regnum);
269          if (name == 0)
270            continue;
271
272	  data_item_win =
273            &display_info->regs_content[pos]->which_element.data_window;
274          data =
275            &((struct tui_win_element *) data_item_win->content[0])->which_element.data;
276          if (data)
277            {
278              if (!refresh_values_only)
279                {
280                  data->item_no = regnum;
281                  data->name = name;
282                  data->highlight = FALSE;
283                }
284              if (data->value == (void*) NULL)
285                data->value = (void*) xmalloc (MAX_REGISTER_SIZE);
286
287              tui_get_register (gdbarch, frame, data, regnum, 0);
288            }
289          pos++;
290	}
291
292      TUI_DATA_WIN->generic.content_size =
293	display_info->regs_content_count + display_info->data_content_count;
294      ret = TUI_SUCCESS;
295    }
296
297  return ret;
298}
299
300/* Function to display the registers in the content from
301   'start_element_no' until the end of the register content or the end
302   of the display height.  No checking for displaying past the end of
303   the registers is done here.  */
304void
305tui_display_registers_from (int start_element_no)
306{
307  struct tui_data_info *display_info = &TUI_DATA_WIN->detail.data_display_info;
308
309  if (display_info->regs_content != (tui_win_content) NULL &&
310      display_info->regs_content_count > 0)
311    {
312      int i = start_element_no;
313      int j, value_chars_wide, item_win_width, cur_y;
314
315      int max_len = 0;
316      for (i = 0; i < display_info->regs_content_count; i++)
317        {
318          struct tui_data_element *data;
319          struct tui_gen_win_info *data_item_win;
320          char *p;
321          int len;
322
323          data_item_win = &display_info->regs_content[i]->which_element.data_window;
324          data = &((struct tui_win_element *)
325                   data_item_win->content[0])->which_element.data;
326          len = 0;
327          p = data->content;
328          if (p != 0)
329            while (*p)
330              {
331                if (*p++ == '\t')
332                  len = 8 * ((len / 8) + 1);
333                else
334                  len++;
335              }
336
337          if (len > max_len)
338            max_len = len;
339        }
340      item_win_width = max_len + 1;
341      i = start_element_no;
342
343      display_info->regs_column_count =
344        (TUI_DATA_WIN->generic.width - 2) / item_win_width;
345      if (display_info->regs_column_count == 0)
346        display_info->regs_column_count = 1;
347      item_win_width =
348        (TUI_DATA_WIN->generic.width - 2) / display_info->regs_column_count;
349
350      /*
351         ** Now create each data "sub" window, and write the display into it.
352       */
353      cur_y = 1;
354      while (i < display_info->regs_content_count &&
355	     cur_y <= TUI_DATA_WIN->generic.viewport_height)
356	{
357	  for (j = 0;
358	       (j < display_info->regs_column_count &&
359		i < display_info->regs_content_count); j++)
360	    {
361	      struct tui_gen_win_info * data_item_win;
362	      struct tui_data_element * data_element_ptr;
363
364	      /* create the window if necessary */
365	      data_item_win = &display_info->regs_content[i]
366                ->which_element.data_window;
367	      data_element_ptr = &((struct tui_win_element *)
368				 data_item_win->content[0])->which_element.data;
369              if (data_item_win->handle != (WINDOW*) NULL
370                  && (data_item_win->height != 1
371                      || data_item_win->width != item_win_width
372                      || data_item_win->origin.x != (item_win_width * j) + 1
373                      || data_item_win->origin.y != cur_y))
374                {
375                  tui_delete_win (data_item_win->handle);
376                  data_item_win->handle = 0;
377                }
378
379	      if (data_item_win->handle == (WINDOW *) NULL)
380		{
381		  data_item_win->height = 1;
382		  data_item_win->width = item_win_width;
383		  data_item_win->origin.x = (item_win_width * j) + 1;
384		  data_item_win->origin.y = cur_y;
385		  tui_make_window (data_item_win, DONT_BOX_WINDOW);
386                  scrollok (data_item_win->handle, FALSE);
387		}
388              touchwin (data_item_win->handle);
389
390	      /* Get the printable representation of the register
391                 and display it.  */
392              tui_display_register (data_element_ptr, data_item_win);
393	      i++;		/* next register */
394	    }
395	  cur_y++;		/* next row; */
396	}
397    }
398}
399
400
401/* Function to display the registers in the content from
402   'start_element_no' on 'start_line_no' until the end of the register
403   content or the end of the display height.  This function checks
404   that we won't display off the end of the register display.  */
405void
406tui_display_reg_element_at_line (int start_element_no, int start_line_no)
407{
408  if (TUI_DATA_WIN->detail.data_display_info.regs_content != (tui_win_content) NULL &&
409      TUI_DATA_WIN->detail.data_display_info.regs_content_count > 0)
410    {
411      int element_no = start_element_no;
412
413      if (start_element_no != 0 && start_line_no != 0)
414	{
415	  int last_line_no, first_line_on_last_page;
416
417	  last_line_no = tui_last_regs_line_no ();
418	  first_line_on_last_page = last_line_no - (TUI_DATA_WIN->generic.height - 2);
419	  if (first_line_on_last_page < 0)
420	    first_line_on_last_page = 0;
421	  /*
422	     ** If there is no other data displayed except registers,
423	     ** and the element_no causes us to scroll past the end of the
424	     ** registers, adjust what element to really start the display at.
425	   */
426	  if (TUI_DATA_WIN->detail.data_display_info.data_content_count <= 0 &&
427	      start_line_no > first_line_on_last_page)
428	    element_no = tui_first_reg_element_no_inline (first_line_on_last_page);
429	}
430      tui_display_registers_from (element_no);
431    }
432}
433
434
435
436/* Function to display the registers starting at line line_no in the
437   data window.  Answers the line number that the display actually
438   started from.  If nothing is displayed (-1) is returned.  */
439int
440tui_display_registers_from_line (int line_no, int force_display)
441{
442  if (TUI_DATA_WIN->detail.data_display_info.regs_content_count > 0)
443    {
444      int line, element_no;
445
446      if (line_no < 0)
447	line = 0;
448      else if (force_display)
449	{			/*
450				   ** If we must display regs (force_display is true), then make
451				   ** sure that we don't display off the end of the registers.
452				 */
453	  if (line_no >= tui_last_regs_line_no ())
454	    {
455	      if ((line = tui_line_from_reg_element_no (
456		 TUI_DATA_WIN->detail.data_display_info.regs_content_count - 1)) < 0)
457		line = 0;
458	    }
459	  else
460	    line = line_no;
461	}
462      else
463	line = line_no;
464
465      element_no = tui_first_reg_element_no_inline (line);
466      if (element_no < TUI_DATA_WIN->detail.data_display_info.regs_content_count)
467	tui_display_reg_element_at_line (element_no, line);
468      else
469	line = (-1);
470
471      return line;
472    }
473
474  return (-1);			/* nothing was displayed */
475}
476
477
478/* This function check all displayed registers for changes in values,
479   given a particular frame.  If the values have changed, they are
480   updated with the new value and highlighted.  */
481void
482tui_check_register_values (struct frame_info *frame)
483{
484  if (TUI_DATA_WIN != NULL && TUI_DATA_WIN->generic.is_visible)
485    {
486      struct tui_data_info *display_info
487        = &TUI_DATA_WIN->detail.data_display_info;
488
489      if (display_info->regs_content_count <= 0 && display_info->display_regs)
490	tui_show_registers (display_info->current_group);
491      else
492	{
493	  int i, j;
494
495	  for (i = 0; (i < display_info->regs_content_count); i++)
496	    {
497	      struct tui_data_element *data;
498	      struct tui_gen_win_info *data_item_win_ptr;
499	      int was_hilighted;
500
501	      data_item_win_ptr = &display_info->regs_content[i]->
502                which_element.data_window;
503	      data = &((struct tui_win_element *)
504                       data_item_win_ptr->content[0])->which_element.data;
505	      was_hilighted = data->highlight;
506
507              tui_get_register (current_gdbarch, frame, data,
508                                data->item_no, &data->highlight);
509
510	      if (data->highlight || was_hilighted)
511		{
512                  tui_display_register (data, data_item_win_ptr);
513		}
514	    }
515	}
516    }
517}
518
519/* Display a register in a window.  If hilite is TRUE,
520   then the value will be displayed in reverse video  */
521static void
522tui_display_register (struct tui_data_element *data,
523                      struct tui_gen_win_info *win_info)
524{
525  if (win_info->handle != (WINDOW *) NULL)
526    {
527      int i;
528
529      if (data->highlight)
530	wstandout (win_info->handle);
531
532      wmove (win_info->handle, 0, 0);
533      for (i = 1; i < win_info->width; i++)
534        waddch (win_info->handle, ' ');
535      wmove (win_info->handle, 0, 0);
536      if (data->content)
537        waddstr (win_info->handle, data->content);
538
539      if (data->highlight)
540	wstandend (win_info->handle);
541      tui_refresh_win (win_info);
542    }
543}
544
545static void
546tui_reg_next_command (char *arg, int from_tty)
547{
548  if (TUI_DATA_WIN != 0)
549    {
550      struct reggroup *group
551        = TUI_DATA_WIN->detail.data_display_info.current_group;
552
553      group = reggroup_next (current_gdbarch, group);
554      if (group == 0)
555        group = reggroup_next (current_gdbarch, 0);
556
557      if (group)
558        tui_show_registers (group);
559    }
560}
561
562static void
563tui_reg_float_command (char *arg, int from_tty)
564{
565  tui_show_registers (float_reggroup);
566}
567
568static void
569tui_reg_general_command (char *arg, int from_tty)
570{
571  tui_show_registers (general_reggroup);
572}
573
574static void
575tui_reg_system_command (char *arg, int from_tty)
576{
577  tui_show_registers (system_reggroup);
578}
579
580static struct cmd_list_element *tuireglist;
581
582static void
583tui_reg_command (char *args, int from_tty)
584{
585  printf_unfiltered ("\"tui reg\" must be followed by the name of a "
586                     "tui reg command.\n");
587  help_list (tuireglist, "tui reg ", -1, gdb_stdout);
588}
589
590void
591_initialize_tui_regs (void)
592{
593  struct cmd_list_element **tuicmd;
594
595  tuicmd = tui_get_cmd_list ();
596
597  add_prefix_cmd ("reg", class_tui, tui_reg_command,
598                  "TUI commands to control the register window.",
599                  &tuireglist, "tui reg ", 0,
600                  tuicmd);
601
602  add_cmd ("float", class_tui, tui_reg_float_command,
603           "Display only floating point registers\n",
604           &tuireglist);
605  add_cmd ("general", class_tui, tui_reg_general_command,
606           "Display only general registers\n",
607           &tuireglist);
608  add_cmd ("system", class_tui, tui_reg_system_command,
609           "Display only system registers\n",
610           &tuireglist);
611  add_cmd ("next", class_tui, tui_reg_next_command,
612           "Display next register group\n",
613           &tuireglist);
614
615  if (xdb_commands)
616    {
617      add_com ("fr", class_tui, tui_reg_float_command,
618	       "Display only floating point registers\n");
619      add_com ("gr", class_tui, tui_reg_general_command,
620	       "Display only general registers\n");
621      add_com ("sr", class_tui, tui_reg_system_command,
622	       "Display only special registers\n");
623      add_com ("+r", class_tui, tui_scroll_regs_forward_command,
624	       "Scroll the registers window forward\n");
625      add_com ("-r", class_tui, tui_scroll_regs_backward_command,
626	       "Scroll the register window backward\n");
627    }
628}
629
630
631/*****************************************
632** STATIC LOCAL FUNCTIONS                 **
633******************************************/
634
635extern int pagination_enabled;
636
637static void
638tui_restore_gdbout (void *ui)
639{
640  ui_file_delete (gdb_stdout);
641  gdb_stdout = (struct ui_file*) ui;
642  pagination_enabled = 1;
643}
644
645/* Get the register from the frame and make a printable representation
646   of it in the data element.  */
647static void
648tui_register_format (struct gdbarch *gdbarch, struct frame_info *frame,
649                     struct tui_data_element *data_element, int regnum)
650{
651  struct ui_file *stream;
652  struct ui_file *old_stdout;
653  const char *name;
654  struct cleanup *cleanups;
655  char *p, *s;
656  int pos;
657  struct type *type = gdbarch_register_type (gdbarch, regnum);
658
659  name = gdbarch_register_name (gdbarch, regnum);
660  if (name == 0)
661    {
662      return;
663    }
664
665  pagination_enabled = 0;
666  old_stdout = gdb_stdout;
667  stream = tui_sfileopen (256);
668  gdb_stdout = stream;
669  cleanups = make_cleanup (tui_restore_gdbout, (void*) old_stdout);
670  if (TYPE_VECTOR (type) != 0 && 0)
671    {
672      char buf[MAX_REGISTER_SIZE];
673      int len;
674
675      len = register_size (current_gdbarch, regnum);
676      fprintf_filtered (stream, "%-14s ", name);
677      get_frame_register (frame, regnum, buf);
678      print_scalar_formatted (buf, type, 'f', len, stream);
679    }
680  else
681    {
682      gdbarch_print_registers_info (current_gdbarch, stream,
683                                    frame, regnum, 1);
684    }
685
686  /* Save formatted output in the buffer.  */
687  p = tui_file_get_strbuf (stream);
688
689  /* Remove the possible \n.  */
690  s = strrchr (p, '\n');
691  if (s && s[1] == 0)
692    *s = 0;
693
694  xfree (data_element->content);
695  data_element->content = xstrdup (p);
696  do_cleanups (cleanups);
697}
698
699/* Get the register value from the given frame and format it for
700   the display.  When changep is set, check if the new register value
701   has changed with respect to the previous call.  */
702static enum tui_status
703tui_get_register (struct gdbarch *gdbarch, struct frame_info *frame,
704                  struct tui_data_element *data, int regnum, int *changedp)
705{
706  enum tui_status ret = TUI_FAILURE;
707
708  if (changedp)
709    *changedp = FALSE;
710  if (target_has_registers)
711    {
712      char buf[MAX_REGISTER_SIZE];
713
714      get_frame_register (frame, regnum, buf);
715      /* NOTE: cagney/2003-03-13: This is bogus.  It is refering to
716         the register cache and not the frame which could have pulled
717         the register value off the stack.  */
718      if (register_cached (regnum) >= 0)
719        {
720          if (changedp)
721            {
722              int size = register_size (gdbarch, regnum);
723              char *old = (char*) data->value;
724              int i;
725
726              for (i = 0; i < size; i++)
727                if (buf[i] != old[i])
728                  {
729                    *changedp = TRUE;
730                    old[i] = buf[i];
731                  }
732            }
733
734          /* Reformat the data content if the value changed.  */
735          if (changedp == 0 || *changedp == TRUE)
736            tui_register_format (gdbarch, frame, data, regnum);
737          ret = TUI_SUCCESS;
738        }
739    }
740  return ret;
741}
742
743static void
744tui_scroll_regs_forward_command (char *arg, int from_tty)
745{
746  tui_scroll (FORWARD_SCROLL, TUI_DATA_WIN, 1);
747}
748
749
750static void
751tui_scroll_regs_backward_command (char *arg, int from_tty)
752{
753  tui_scroll (BACKWARD_SCROLL, TUI_DATA_WIN, 1);
754}
755