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