1/* TUI display source/assembly window.
2
3   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006, 2007, 2008,
4   2009, 2010, 2011 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 3 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, see <http://www.gnu.org/licenses/>.  */
22
23#include "defs.h"
24#include <ctype.h>
25#include "symtab.h"
26#include "frame.h"
27#include "breakpoint.h"
28#include "value.h"
29#include "source.h"
30#include "objfiles.h"
31#include "filenames.h"
32
33#include "tui/tui.h"
34#include "tui/tui-data.h"
35#include "tui/tui-stack.h"
36#include "tui/tui-win.h"
37#include "tui/tui-wingeneral.h"
38#include "tui/tui-winsource.h"
39#include "tui/tui-source.h"
40#include "tui/tui-disasm.h"
41
42#include "gdb_string.h"
43#include "gdb_curses.h"
44#include "gdb_assert.h"
45
46/* Function to display the "main" routine.  */
47void
48tui_display_main (void)
49{
50  if ((tui_source_windows ())->count > 0)
51    {
52      struct gdbarch *gdbarch;
53      CORE_ADDR addr;
54
55      tui_get_begin_asm_address (&gdbarch, &addr);
56      if (addr != (CORE_ADDR) 0)
57	{
58	  struct symtab_and_line sal;
59
60	  tui_update_source_windows_with_addr (gdbarch, addr);
61	  sal = find_pc_line (addr, 0);
62          if (sal.symtab)
63             tui_update_locator_filename (sal.symtab->filename);
64          else
65             tui_update_locator_filename ("??");
66	}
67    }
68}
69
70
71
72/* Function to display source in the source window.  This function
73   initializes the horizontal scroll to 0.  */
74void
75tui_update_source_window (struct tui_win_info *win_info,
76			  struct gdbarch *gdbarch,
77			  struct symtab *s,
78			  struct tui_line_or_address line_or_addr,
79			  int noerror)
80{
81  win_info->detail.source_info.horizontal_offset = 0;
82  tui_update_source_window_as_is (win_info, gdbarch, s, line_or_addr, noerror);
83
84  return;
85}
86
87
88/* Function to display source in the source/asm window.  This function
89   shows the source as specified by the horizontal offset.  */
90void
91tui_update_source_window_as_is (struct tui_win_info *win_info,
92				struct gdbarch *gdbarch,
93				struct symtab *s,
94				struct tui_line_or_address line_or_addr,
95				int noerror)
96{
97  enum tui_status ret;
98
99  if (win_info->generic.type == SRC_WIN)
100    ret = tui_set_source_content (s, line_or_addr.u.line_no, noerror);
101  else
102    ret = tui_set_disassem_content (gdbarch, line_or_addr.u.addr);
103
104  if (ret == TUI_FAILURE)
105    {
106      tui_clear_source_content (win_info, EMPTY_SOURCE_PROMPT);
107      tui_clear_exec_info_content (win_info);
108    }
109  else
110    {
111      tui_update_breakpoint_info (win_info, 0);
112      tui_show_source_content (win_info);
113      tui_update_exec_info (win_info);
114      if (win_info->generic.type == SRC_WIN)
115	{
116	  struct symtab_and_line sal;
117
118	  init_sal (&sal);
119	  sal.line = line_or_addr.u.line_no +
120	    (win_info->generic.content_size - 2);
121	  sal.symtab = s;
122	  sal.pspace = s->objfile->pspace;
123	  set_current_source_symtab_and_line (&sal);
124	  /* If the focus was in the asm win, put it in the src win if
125	     we don't have a split layout.  */
126	  if (tui_win_with_focus () == TUI_DISASM_WIN
127	      && tui_current_layout () != SRC_DISASSEM_COMMAND)
128	    tui_set_win_focus_to (TUI_SRC_WIN);
129	}
130    }
131
132
133  return;
134}
135
136
137/* Function to ensure that the source and/or disassemly windows
138   reflect the input address.  */
139void
140tui_update_source_windows_with_addr (struct gdbarch *gdbarch, CORE_ADDR addr)
141{
142  if (addr != 0)
143    {
144      struct symtab_and_line sal;
145      struct tui_line_or_address l;
146
147      switch (tui_current_layout ())
148	{
149	case DISASSEM_COMMAND:
150	case DISASSEM_DATA_COMMAND:
151	  tui_show_disassem (gdbarch, addr);
152	  break;
153	case SRC_DISASSEM_COMMAND:
154	  tui_show_disassem_and_update_source (gdbarch, addr);
155	  break;
156	default:
157	  sal = find_pc_line (addr, 0);
158	  l.loa = LOA_LINE;
159	  l.u.line_no = sal.line;
160	  tui_show_symtab_source (gdbarch, sal.symtab, l, FALSE);
161	  break;
162	}
163    }
164  else
165    {
166      int i;
167
168      for (i = 0; i < (tui_source_windows ())->count; i++)
169	{
170	  struct tui_win_info *win_info = (tui_source_windows ())->list[i];
171
172	  tui_clear_source_content (win_info, EMPTY_SOURCE_PROMPT);
173	  tui_clear_exec_info_content (win_info);
174	}
175    }
176}
177
178/* Function to ensure that the source and/or disassemly windows
179   reflect the input address.  */
180void
181tui_update_source_windows_with_line (struct symtab *s, int line)
182{
183  struct gdbarch *gdbarch;
184  CORE_ADDR pc;
185  struct tui_line_or_address l;
186
187  if (!s)
188    return;
189
190  gdbarch = get_objfile_arch (s->objfile);
191
192  switch (tui_current_layout ())
193    {
194    case DISASSEM_COMMAND:
195    case DISASSEM_DATA_COMMAND:
196      find_line_pc (s, line, &pc);
197      tui_update_source_windows_with_addr (gdbarch, pc);
198      break;
199    default:
200      l.loa = LOA_LINE;
201      l.u.line_no = line;
202      tui_show_symtab_source (gdbarch, s, l, FALSE);
203      if (tui_current_layout () == SRC_DISASSEM_COMMAND)
204	{
205	  find_line_pc (s, line, &pc);
206	  tui_show_disassem (gdbarch, pc);
207	}
208      break;
209    }
210
211  return;
212}
213
214void
215tui_clear_source_content (struct tui_win_info *win_info,
216			  int display_prompt)
217{
218  if (win_info != NULL)
219    {
220      int i;
221
222      win_info->generic.content_in_use = FALSE;
223      tui_erase_source_content (win_info, display_prompt);
224      for (i = 0; i < win_info->generic.content_size; i++)
225	{
226	  struct tui_win_element *element =
227	    (struct tui_win_element *) win_info->generic.content[i];
228
229	  element->which_element.source.has_break = FALSE;
230	  element->which_element.source.is_exec_point = FALSE;
231	}
232    }
233}
234
235
236void
237tui_erase_source_content (struct tui_win_info *win_info,
238			  int display_prompt)
239{
240  int x_pos;
241  int half_width = (win_info->generic.width - 2) / 2;
242
243  if (win_info->generic.handle != (WINDOW *) NULL)
244    {
245      werase (win_info->generic.handle);
246      tui_check_and_display_highlight_if_needed (win_info);
247      if (display_prompt == EMPTY_SOURCE_PROMPT)
248	{
249	  char *no_src_str;
250
251	  if (win_info->generic.type == SRC_WIN)
252	    no_src_str = NO_SRC_STRING;
253	  else
254	    no_src_str = NO_DISASSEM_STRING;
255	  if (strlen (no_src_str) >= half_width)
256	    x_pos = 1;
257	  else
258	    x_pos = half_width - strlen (no_src_str);
259	  mvwaddstr (win_info->generic.handle,
260		     (win_info->generic.height / 2),
261		     x_pos,
262		     no_src_str);
263
264	  /* elz: Added this function call to set the real contents of
265	     the window to what is on the screen, so that later calls
266	     to refresh, do display the correct stuff, and not the old
267	     image.  */
268
269	  tui_set_source_content_nil (win_info, no_src_str);
270	}
271      tui_refresh_win (&win_info->generic);
272    }
273}
274
275
276/* Redraw the complete line of a source or disassembly window.  */
277static void
278tui_show_source_line (struct tui_win_info *win_info, int lineno)
279{
280  struct tui_win_element *line;
281  int x, y;
282
283  line = (struct tui_win_element *) win_info->generic.content[lineno - 1];
284  if (line->which_element.source.is_exec_point)
285    wattron (win_info->generic.handle, A_STANDOUT);
286
287  mvwaddstr (win_info->generic.handle, lineno, 1,
288             line->which_element.source.line);
289  if (line->which_element.source.is_exec_point)
290    wattroff (win_info->generic.handle, A_STANDOUT);
291
292  /* Clear to end of line but stop before the border.  */
293  getyx (win_info->generic.handle, y, x);
294  while (x + 1 < win_info->generic.width)
295    {
296      waddch (win_info->generic.handle, ' ');
297      getyx (win_info->generic.handle, y, x);
298    }
299}
300
301void
302tui_show_source_content (struct tui_win_info *win_info)
303{
304  if (win_info->generic.content_size > 0)
305    {
306      int lineno;
307
308      for (lineno = 1; lineno <= win_info->generic.content_size; lineno++)
309        tui_show_source_line (win_info, lineno);
310    }
311  else
312    tui_erase_source_content (win_info, TRUE);
313
314  tui_check_and_display_highlight_if_needed (win_info);
315  tui_refresh_win (&win_info->generic);
316  win_info->generic.content_in_use = TRUE;
317}
318
319
320/* Scroll the source forward or backward horizontally.  */
321void
322tui_horizontal_source_scroll (struct tui_win_info *win_info,
323			      enum tui_scroll_direction direction,
324			      int num_to_scroll)
325{
326  if (win_info->generic.content != NULL)
327    {
328      struct gdbarch *gdbarch = win_info->detail.source_info.gdbarch;
329      int offset;
330      struct symtab *s = NULL;
331
332      if (win_info->generic.type == SRC_WIN)
333	{
334	  struct symtab_and_line cursal
335	    = get_current_source_symtab_and_line ();
336
337	  if (cursal.symtab == NULL)
338	    s = find_pc_symtab (get_frame_pc (get_selected_frame (NULL)));
339	  else
340	    s = cursal.symtab;
341	}
342
343      if (direction == LEFT_SCROLL)
344	offset = win_info->detail.source_info.horizontal_offset
345	  + num_to_scroll;
346      else
347	{
348	  offset = win_info->detail.source_info.horizontal_offset
349	    - num_to_scroll;
350	  if (offset < 0)
351	    offset = 0;
352	}
353      win_info->detail.source_info.horizontal_offset = offset;
354      tui_update_source_window_as_is (win_info, gdbarch, s,
355				      ((struct tui_win_element *)
356				       win_info->generic.content[0])->which_element.source.line_or_addr,
357				      FALSE);
358    }
359
360  return;
361}
362
363
364/* Set or clear the has_break flag in the line whose line is
365   line_no.  */
366
367void
368tui_set_is_exec_point_at (struct tui_line_or_address l,
369			  struct tui_win_info *win_info)
370{
371  int changed = 0;
372  int i;
373  tui_win_content content = (tui_win_content) win_info->generic.content;
374
375  i = 0;
376  while (i < win_info->generic.content_size)
377    {
378      int new_state;
379      struct tui_line_or_address content_loa =
380	content[i]->which_element.source.line_or_addr;
381
382      gdb_assert (l.loa == LOA_ADDRESS || l.loa == LOA_LINE);
383      gdb_assert (content_loa.loa == LOA_LINE
384		  || content_loa.loa == LOA_ADDRESS);
385      if (content_loa.loa == l.loa
386	  && ((l.loa == LOA_LINE && content_loa.u.line_no == l.u.line_no)
387              || (content_loa.u.addr == l.u.addr)))
388        new_state = TRUE;
389      else
390	new_state = FALSE;
391      if (new_state != content[i]->which_element.source.is_exec_point)
392        {
393          changed++;
394          content[i]->which_element.source.is_exec_point = new_state;
395          tui_show_source_line (win_info, i + 1);
396        }
397      i++;
398    }
399  if (changed)
400    tui_refresh_win (&win_info->generic);
401}
402
403/* Update the execution windows to show the active breakpoints.
404   This is called whenever a breakpoint is inserted, removed or
405   has its state changed.  */
406void
407tui_update_all_breakpoint_info (void)
408{
409  struct tui_list *list = tui_source_windows ();
410  int i;
411
412  for (i = 0; i < list->count; i++)
413    {
414      struct tui_win_info *win = list->list[i];
415
416      if (tui_update_breakpoint_info (win, FALSE))
417        {
418          tui_update_exec_info (win);
419        }
420    }
421}
422
423
424/* Scan the source window and the breakpoints to update the has_break
425   information for each line.
426
427   Returns 1 if something changed and the execution window must be
428   refreshed.  */
429
430int
431tui_update_breakpoint_info (struct tui_win_info *win,
432			    int current_only)
433{
434  int i;
435  int need_refresh = 0;
436  struct tui_source_info *src = &win->detail.source_info;
437
438  for (i = 0; i < win->generic.content_size; i++)
439    {
440      struct breakpoint *bp;
441      extern struct breakpoint *breakpoint_chain;
442      int mode;
443      struct tui_source_element *line;
444
445      line = &((struct tui_win_element *)
446	       win->generic.content[i])->which_element.source;
447      if (current_only && !line->is_exec_point)
448         continue;
449
450      /* Scan each breakpoint to see if the current line has something to
451         do with it.  Identify enable/disabled breakpoints as well as
452         those that we already hit.  */
453      mode = 0;
454      for (bp = breakpoint_chain;
455           bp != (struct breakpoint *) NULL;
456           bp = bp->next)
457        {
458	  gdb_assert (line->line_or_addr.loa == LOA_LINE
459		      || line->line_or_addr.loa == LOA_ADDRESS);
460          if ((win == TUI_SRC_WIN
461               && bp->source_file
462               && (filename_cmp (src->filename, bp->source_file) == 0)
463	       && line->line_or_addr.loa == LOA_LINE
464               && bp->line_number == line->line_or_addr.u.line_no)
465              || (win == TUI_DISASM_WIN
466		  && line->line_or_addr.loa == LOA_ADDRESS
467		  && bp->loc != NULL
468                  && bp->loc->address == line->line_or_addr.u.addr))
469            {
470              if (bp->enable_state == bp_disabled)
471                mode |= TUI_BP_DISABLED;
472              else
473                mode |= TUI_BP_ENABLED;
474              if (bp->hit_count)
475                mode |= TUI_BP_HIT;
476              if (bp->loc->cond)
477                mode |= TUI_BP_CONDITIONAL;
478              if (bp->type == bp_hardware_breakpoint)
479                mode |= TUI_BP_HARDWARE;
480            }
481        }
482      if (line->has_break != mode)
483        {
484          line->has_break = mode;
485          need_refresh = 1;
486        }
487    }
488  return need_refresh;
489}
490
491
492/* Function to initialize the content of the execution info window,
493   based upon the input window which is either the source or
494   disassembly window.  */
495enum tui_status
496tui_set_exec_info_content (struct tui_win_info *win_info)
497{
498  enum tui_status ret = TUI_SUCCESS;
499
500  if (win_info->detail.source_info.execution_info
501      != (struct tui_gen_win_info *) NULL)
502    {
503      struct tui_gen_win_info *exec_info_ptr
504	= win_info->detail.source_info.execution_info;
505
506      if (exec_info_ptr->content == NULL)
507	exec_info_ptr->content =
508	  (void **) tui_alloc_content (win_info->generic.height,
509					 exec_info_ptr->type);
510      if (exec_info_ptr->content != NULL)
511	{
512	  int i;
513
514          tui_update_breakpoint_info (win_info, 1);
515	  for (i = 0; i < win_info->generic.content_size; i++)
516	    {
517	      struct tui_win_element *element;
518	      struct tui_win_element *src_element;
519              int mode;
520
521	      element = (struct tui_win_element *) exec_info_ptr->content[i];
522	      src_element = (struct tui_win_element *)
523		win_info->generic.content[i];
524
525              memset(element->which_element.simple_string, ' ',
526                     sizeof(element->which_element.simple_string));
527              element->which_element.simple_string[TUI_EXECINFO_SIZE - 1] = 0;
528
529	      /* Now update the exec info content based upon the state
530                 of each line as indicated by the source content.  */
531              mode = src_element->which_element.source.has_break;
532              if (mode & TUI_BP_HIT)
533                element->which_element.simple_string[TUI_BP_HIT_POS] =
534                  (mode & TUI_BP_HARDWARE) ? 'H' : 'B';
535              else if (mode & (TUI_BP_ENABLED | TUI_BP_DISABLED))
536                element->which_element.simple_string[TUI_BP_HIT_POS] =
537                  (mode & TUI_BP_HARDWARE) ? 'h' : 'b';
538
539              if (mode & TUI_BP_ENABLED)
540                element->which_element.simple_string[TUI_BP_BREAK_POS] = '+';
541              else if (mode & TUI_BP_DISABLED)
542                element->which_element.simple_string[TUI_BP_BREAK_POS] = '-';
543
544              if (src_element->which_element.source.is_exec_point)
545                element->which_element.simple_string[TUI_EXEC_POS] = '>';
546	    }
547	  exec_info_ptr->content_size = win_info->generic.content_size;
548	}
549      else
550	ret = TUI_FAILURE;
551    }
552
553  return ret;
554}
555
556
557void
558tui_show_exec_info_content (struct tui_win_info *win_info)
559{
560  struct tui_gen_win_info *exec_info
561    = win_info->detail.source_info.execution_info;
562  int cur_line;
563
564  werase (exec_info->handle);
565  tui_refresh_win (exec_info);
566  for (cur_line = 1; (cur_line <= exec_info->content_size); cur_line++)
567    mvwaddstr (exec_info->handle,
568	       cur_line,
569	       0,
570	       ((struct tui_win_element *)
571		exec_info->content[cur_line - 1])->which_element.simple_string);
572  tui_refresh_win (exec_info);
573  exec_info->content_in_use = TRUE;
574}
575
576
577void
578tui_erase_exec_info_content (struct tui_win_info *win_info)
579{
580  struct tui_gen_win_info *exec_info
581    = win_info->detail.source_info.execution_info;
582
583  werase (exec_info->handle);
584  tui_refresh_win (exec_info);
585}
586
587void
588tui_clear_exec_info_content (struct tui_win_info *win_info)
589{
590  win_info->detail.source_info.execution_info->content_in_use = FALSE;
591  tui_erase_exec_info_content (win_info);
592
593  return;
594}
595
596/* Function to update the execution info window.  */
597void
598tui_update_exec_info (struct tui_win_info *win_info)
599{
600  tui_set_exec_info_content (win_info);
601  tui_show_exec_info_content (win_info);
602}
603
604enum tui_status
605tui_alloc_source_buffer (struct tui_win_info *win_info)
606{
607  char *src_line_buf;
608  int i, line_width, max_lines;
609
610  max_lines = win_info->generic.height;	/* Less the highlight box.  */
611  line_width = win_info->generic.width - 1;
612  /*
613   * Allocate the buffer for the source lines.  Do this only once
614   * since they will be re-used for all source displays.  The only
615   * other time this will be done is when a window's size changes.
616   */
617  if (win_info->generic.content == NULL)
618    {
619      src_line_buf = (char *)
620	xmalloc ((max_lines * line_width) * sizeof (char));
621      if (src_line_buf == (char *) NULL)
622	{
623	  fputs_unfiltered ("Unable to Allocate Memory for "
624			    "Source or Disassembly Display.\n",
625			    gdb_stderr);
626	  return TUI_FAILURE;
627	}
628      /* Allocate the content list.  */
629      if ((win_info->generic.content =
630	   (void **) tui_alloc_content (max_lines, SRC_WIN)) == NULL)
631	{
632	  xfree (src_line_buf);
633	  fputs_unfiltered ("Unable to Allocate Memory for "
634			    "Source or Disassembly Display.\n",
635			    gdb_stderr);
636	  return TUI_FAILURE;
637	}
638      for (i = 0; i < max_lines; i++)
639	((struct tui_win_element *)
640	 win_info->generic.content[i])->which_element.source.line =
641	  src_line_buf + (line_width * i);
642    }
643
644  return TUI_SUCCESS;
645}
646
647
648/* Answer whether a particular line number or address is displayed
649   in the current source window.  */
650int
651tui_line_is_displayed (int line,
652		       struct tui_win_info *win_info,
653		       int check_threshold)
654{
655  int is_displayed = FALSE;
656  int i, threshold;
657
658  if (check_threshold)
659    threshold = SCROLL_THRESHOLD;
660  else
661    threshold = 0;
662  i = 0;
663  while (i < win_info->generic.content_size - threshold
664	 && !is_displayed)
665    {
666      is_displayed = (((struct tui_win_element *)
667		       win_info->generic.content[i])->which_element.source.line_or_addr.loa
668		      == LOA_LINE)
669	&& (((struct tui_win_element *)
670	     win_info->generic.content[i])->which_element.source.line_or_addr.u.line_no
671	    == (int) line);
672      i++;
673    }
674
675  return is_displayed;
676}
677
678
679/* Answer whether a particular line number or address is displayed
680   in the current source window.  */
681int
682tui_addr_is_displayed (CORE_ADDR addr,
683		       struct tui_win_info *win_info,
684		       int check_threshold)
685{
686  int is_displayed = FALSE;
687  int i, threshold;
688
689  if (check_threshold)
690    threshold = SCROLL_THRESHOLD;
691  else
692    threshold = 0;
693  i = 0;
694  while (i < win_info->generic.content_size - threshold
695	 && !is_displayed)
696    {
697      is_displayed = (((struct tui_win_element *)
698		       win_info->generic.content[i])->which_element.source.line_or_addr.loa
699		      == LOA_ADDRESS)
700	&& (((struct tui_win_element *)
701	     win_info->generic.content[i])->which_element.source.line_or_addr.u.addr
702	    == addr);
703      i++;
704    }
705
706  return is_displayed;
707}
708
709
710/*****************************************
711** STATIC LOCAL FUNCTIONS               **
712******************************************/
713