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.  */
47 void
48 tui_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.  */
74 void
75 tui_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.  */
90 void
91 tui_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.  */
139 void
140 tui_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.  */
180 void
181 tui_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 
214 void
215 tui_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 
236 void
237 tui_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.  */
277 static void
278 tui_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 
301 void
302 tui_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.  */
321 void
322 tui_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 
367 void
368 tui_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.  */
406 void
407 tui_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 
430 int
431 tui_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.  */
495 enum tui_status
496 tui_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 
557 void
558 tui_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 
577 void
578 tui_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 
587 void
588 tui_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.  */
597 void
598 tui_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 
604 enum tui_status
605 tui_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.  */
650 int
651 tui_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.  */
681 int
682 tui_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