1 /* TUI display source/assembly window.
2 
3    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006, 2007, 2008,
4    2009 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 	  element->which_element.source.has_break = FALSE;
226 	  element->which_element.source.is_exec_point = FALSE;
227 	}
228     }
229 }
230 
231 
232 void
233 tui_erase_source_content (struct tui_win_info *win_info,
234 			  int display_prompt)
235 {
236   int x_pos;
237   int half_width = (win_info->generic.width - 2) / 2;
238 
239   if (win_info->generic.handle != (WINDOW *) NULL)
240     {
241       werase (win_info->generic.handle);
242       tui_check_and_display_highlight_if_needed (win_info);
243       if (display_prompt == EMPTY_SOURCE_PROMPT)
244 	{
245 	  char *no_src_str;
246 
247 	  if (win_info->generic.type == SRC_WIN)
248 	    no_src_str = NO_SRC_STRING;
249 	  else
250 	    no_src_str = NO_DISASSEM_STRING;
251 	  if (strlen (no_src_str) >= half_width)
252 	    x_pos = 1;
253 	  else
254 	    x_pos = half_width - strlen (no_src_str);
255 	  mvwaddstr (win_info->generic.handle,
256 		     (win_info->generic.height / 2),
257 		     x_pos,
258 		     no_src_str);
259 
260 	  /* elz: Added this function call to set the real contents of
261 	     the window to what is on the screen, so that later calls
262 	     to refresh, do display the correct stuff, and not the old
263 	     image.  */
264 
265 	  tui_set_source_content_nil (win_info, no_src_str);
266 	}
267       tui_refresh_win (&win_info->generic);
268     }
269 }
270 
271 
272 /* Redraw the complete line of a source or disassembly window.  */
273 static void
274 tui_show_source_line (struct tui_win_info *win_info, int lineno)
275 {
276   struct tui_win_element *line;
277   int x, y;
278 
279   line = (struct tui_win_element *) win_info->generic.content[lineno - 1];
280   if (line->which_element.source.is_exec_point)
281     wattron (win_info->generic.handle, A_STANDOUT);
282 
283   mvwaddstr (win_info->generic.handle, lineno, 1,
284              line->which_element.source.line);
285   if (line->which_element.source.is_exec_point)
286     wattroff (win_info->generic.handle, A_STANDOUT);
287 
288   /* Clear to end of line but stop before the border.  */
289   getyx (win_info->generic.handle, y, x);
290   while (x + 1 < win_info->generic.width)
291     {
292       waddch (win_info->generic.handle, ' ');
293       getyx (win_info->generic.handle, y, x);
294     }
295 }
296 
297 void
298 tui_show_source_content (struct tui_win_info *win_info)
299 {
300   if (win_info->generic.content_size > 0)
301     {
302       int lineno;
303 
304       for (lineno = 1; lineno <= win_info->generic.content_size; lineno++)
305         tui_show_source_line (win_info, lineno);
306     }
307   else
308     tui_erase_source_content (win_info, TRUE);
309 
310   tui_check_and_display_highlight_if_needed (win_info);
311   tui_refresh_win (&win_info->generic);
312   win_info->generic.content_in_use = TRUE;
313 }
314 
315 
316 /* Scroll the source forward or backward horizontally.  */
317 void
318 tui_horizontal_source_scroll (struct tui_win_info *win_info,
319 			      enum tui_scroll_direction direction,
320 			      int num_to_scroll)
321 {
322   if (win_info->generic.content != NULL)
323     {
324       struct gdbarch *gdbarch = win_info->detail.source_info.gdbarch;
325       int offset;
326       struct symtab *s = NULL;
327 
328       if (win_info->generic.type == SRC_WIN)
329 	{
330 	  struct symtab_and_line cursal = get_current_source_symtab_and_line ();
331 	  if (cursal.symtab == NULL)
332 	    s = find_pc_symtab (get_frame_pc (get_selected_frame (NULL)));
333 	  else
334 	    s = cursal.symtab;
335 	}
336 
337       if (direction == LEFT_SCROLL)
338 	offset = win_info->detail.source_info.horizontal_offset + num_to_scroll;
339       else
340 	{
341 	  if ((offset =
342 	     win_info->detail.source_info.horizontal_offset - num_to_scroll) < 0)
343 	    offset = 0;
344 	}
345       win_info->detail.source_info.horizontal_offset = offset;
346       tui_update_source_window_as_is (win_info, gdbarch, s,
347 				      ((struct tui_win_element *)
348 				       win_info->generic.content[0])->which_element.source.line_or_addr,
349 				      FALSE);
350     }
351 
352   return;
353 }
354 
355 
356 /* Set or clear the has_break flag in the line whose line is
357    line_no.  */
358 
359 void
360 tui_set_is_exec_point_at (struct tui_line_or_address l,
361 			  struct tui_win_info *win_info)
362 {
363   int changed = 0;
364   int i;
365   tui_win_content content = (tui_win_content) win_info->generic.content;
366 
367   i = 0;
368   while (i < win_info->generic.content_size)
369     {
370       int new_state;
371       struct tui_line_or_address content_loa =
372 	content[i]->which_element.source.line_or_addr;
373 
374       gdb_assert (l.loa == LOA_ADDRESS || l.loa == LOA_LINE);
375       gdb_assert (content_loa.loa == LOA_LINE
376 		  || content_loa.loa == LOA_ADDRESS);
377       if (content_loa.loa == l.loa
378 	  && ((l.loa == LOA_LINE && content_loa.u.line_no == l.u.line_no)
379               || (content_loa.u.addr == l.u.addr)))
380         new_state = TRUE;
381       else
382 	new_state = FALSE;
383       if (new_state != content[i]->which_element.source.is_exec_point)
384         {
385           changed++;
386           content[i]->which_element.source.is_exec_point = new_state;
387           tui_show_source_line (win_info, i + 1);
388         }
389       i++;
390     }
391   if (changed)
392     tui_refresh_win (&win_info->generic);
393 }
394 
395 /* Update the execution windows to show the active breakpoints.
396    This is called whenever a breakpoint is inserted, removed or
397    has its state changed.  */
398 void
399 tui_update_all_breakpoint_info (void)
400 {
401   struct tui_list *list = tui_source_windows ();
402   int i;
403 
404   for (i = 0; i < list->count; i++)
405     {
406       struct tui_win_info *win = list->list[i];
407 
408       if (tui_update_breakpoint_info (win, FALSE))
409         {
410           tui_update_exec_info (win);
411         }
412     }
413 }
414 
415 
416 /* Scan the source window and the breakpoints to update the has_break
417    information for each line.
418 
419    Returns 1 if something changed and the execution window must be
420    refreshed.  */
421 
422 int
423 tui_update_breakpoint_info (struct tui_win_info *win,
424 			    int current_only)
425 {
426   int i;
427   int need_refresh = 0;
428   struct tui_source_info *src = &win->detail.source_info;
429 
430   for (i = 0; i < win->generic.content_size; i++)
431     {
432       struct breakpoint *bp;
433       extern struct breakpoint *breakpoint_chain;
434       int mode;
435       struct tui_source_element *line;
436 
437       line = &((struct tui_win_element *) win->generic.content[i])->which_element.source;
438       if (current_only && !line->is_exec_point)
439          continue;
440 
441       /* Scan each breakpoint to see if the current line has something to
442          do with it.  Identify enable/disabled breakpoints as well as
443          those that we already hit.  */
444       mode = 0;
445       for (bp = breakpoint_chain;
446            bp != (struct breakpoint *) NULL;
447            bp = bp->next)
448         {
449 	  gdb_assert (line->line_or_addr.loa == LOA_LINE
450 		      || line->line_or_addr.loa == LOA_ADDRESS);
451           if ((win == TUI_SRC_WIN
452                && bp->source_file
453                && (strcmp (src->filename, bp->source_file) == 0)
454 	       && line->line_or_addr.loa == LOA_LINE
455                && bp->line_number == line->line_or_addr.u.line_no)
456               || (win == TUI_DISASM_WIN
457 		  && line->line_or_addr.loa == LOA_ADDRESS
458 		  && bp->loc != NULL
459                   && bp->loc->address == line->line_or_addr.u.addr))
460             {
461               if (bp->enable_state == bp_disabled)
462                 mode |= TUI_BP_DISABLED;
463               else
464                 mode |= TUI_BP_ENABLED;
465               if (bp->hit_count)
466                 mode |= TUI_BP_HIT;
467               if (bp->loc->cond)
468                 mode |= TUI_BP_CONDITIONAL;
469               if (bp->type == bp_hardware_breakpoint)
470                 mode |= TUI_BP_HARDWARE;
471             }
472         }
473       if (line->has_break != mode)
474         {
475           line->has_break = mode;
476           need_refresh = 1;
477         }
478     }
479   return need_refresh;
480 }
481 
482 
483 /* Function to initialize the content of the execution info window,
484    based upon the input window which is either the source or
485    disassembly window.  */
486 enum tui_status
487 tui_set_exec_info_content (struct tui_win_info *win_info)
488 {
489   enum tui_status ret = TUI_SUCCESS;
490 
491   if (win_info->detail.source_info.execution_info != (struct tui_gen_win_info *) NULL)
492     {
493       struct tui_gen_win_info *exec_info_ptr = win_info->detail.source_info.execution_info;
494 
495       if (exec_info_ptr->content == NULL)
496 	exec_info_ptr->content =
497 	  (void **) tui_alloc_content (win_info->generic.height,
498 					 exec_info_ptr->type);
499       if (exec_info_ptr->content != NULL)
500 	{
501 	  int i;
502 
503           tui_update_breakpoint_info (win_info, 1);
504 	  for (i = 0; i < win_info->generic.content_size; i++)
505 	    {
506 	      struct tui_win_element *element;
507 	      struct tui_win_element *src_element;
508               int mode;
509 
510 	      element = (struct tui_win_element *) exec_info_ptr->content[i];
511 	      src_element = (struct tui_win_element *) win_info->generic.content[i];
512 
513               memset(element->which_element.simple_string, ' ',
514                      sizeof(element->which_element.simple_string));
515               element->which_element.simple_string[TUI_EXECINFO_SIZE - 1] = 0;
516 
517 	      /* Now update the exec info content based upon the state
518                  of each line as indicated by the source content.  */
519               mode = src_element->which_element.source.has_break;
520               if (mode & TUI_BP_HIT)
521                 element->which_element.simple_string[TUI_BP_HIT_POS] =
522                   (mode & TUI_BP_HARDWARE) ? 'H' : 'B';
523               else if (mode & (TUI_BP_ENABLED | TUI_BP_DISABLED))
524                 element->which_element.simple_string[TUI_BP_HIT_POS] =
525                   (mode & TUI_BP_HARDWARE) ? 'h' : 'b';
526 
527               if (mode & TUI_BP_ENABLED)
528                 element->which_element.simple_string[TUI_BP_BREAK_POS] = '+';
529               else if (mode & TUI_BP_DISABLED)
530                 element->which_element.simple_string[TUI_BP_BREAK_POS] = '-';
531 
532               if (src_element->which_element.source.is_exec_point)
533                 element->which_element.simple_string[TUI_EXEC_POS] = '>';
534 	    }
535 	  exec_info_ptr->content_size = win_info->generic.content_size;
536 	}
537       else
538 	ret = TUI_FAILURE;
539     }
540 
541   return ret;
542 }
543 
544 
545 void
546 tui_show_exec_info_content (struct tui_win_info *win_info)
547 {
548   struct tui_gen_win_info *exec_info = win_info->detail.source_info.execution_info;
549   int cur_line;
550 
551   werase (exec_info->handle);
552   tui_refresh_win (exec_info);
553   for (cur_line = 1; (cur_line <= exec_info->content_size); cur_line++)
554     mvwaddstr (exec_info->handle,
555 	       cur_line,
556 	       0,
557 	       ((struct tui_win_element *)
558 		exec_info->content[cur_line - 1])->which_element.simple_string);
559   tui_refresh_win (exec_info);
560   exec_info->content_in_use = TRUE;
561 }
562 
563 
564 void
565 tui_erase_exec_info_content (struct tui_win_info *win_info)
566 {
567   struct tui_gen_win_info *exec_info = win_info->detail.source_info.execution_info;
568 
569   werase (exec_info->handle);
570   tui_refresh_win (exec_info);
571 }
572 
573 void
574 tui_clear_exec_info_content (struct tui_win_info *win_info)
575 {
576   win_info->detail.source_info.execution_info->content_in_use = FALSE;
577   tui_erase_exec_info_content (win_info);
578 
579   return;
580 }
581 
582 /* Function to update the execution info window.  */
583 void
584 tui_update_exec_info (struct tui_win_info *win_info)
585 {
586   tui_set_exec_info_content (win_info);
587   tui_show_exec_info_content (win_info);
588 }
589 
590 enum tui_status
591 tui_alloc_source_buffer (struct tui_win_info *win_info)
592 {
593   char *src_line_buf;
594   int i, line_width, max_lines;
595 
596   max_lines = win_info->generic.height;	/* Less the highlight box.  */
597   line_width = win_info->generic.width - 1;
598   /*
599    * Allocate the buffer for the source lines.  Do this only once
600    * since they will be re-used for all source displays.  The only
601    * other time this will be done is when a window's size changes.
602    */
603   if (win_info->generic.content == NULL)
604     {
605       src_line_buf = (char *)
606 	xmalloc ((max_lines * line_width) * sizeof (char));
607       if (src_line_buf == (char *) NULL)
608 	{
609 	  fputs_unfiltered ("Unable to Allocate Memory for Source or Disassembly Display.\n",
610 			    gdb_stderr);
611 	  return TUI_FAILURE;
612 	}
613       /* Allocate the content list.  */
614       if ((win_info->generic.content =
615 	   (void **) tui_alloc_content (max_lines, SRC_WIN)) == NULL)
616 	{
617 	  xfree (src_line_buf);
618 	  fputs_unfiltered ("Unable to Allocate Memory for Source or Disassembly Display.\n",
619 			    gdb_stderr);
620 	  return TUI_FAILURE;
621 	}
622       for (i = 0; i < max_lines; i++)
623 	((struct tui_win_element *)
624 	 win_info->generic.content[i])->which_element.source.line =
625 	  src_line_buf + (line_width * i);
626     }
627 
628   return TUI_SUCCESS;
629 }
630 
631 
632 /* Answer whether the a particular line number or address is displayed
633    in the current source window.  */
634 int
635 tui_line_is_displayed (int line,
636 		       struct tui_win_info *win_info,
637 		       int check_threshold)
638 {
639   int is_displayed = FALSE;
640   int i, threshold;
641 
642   if (check_threshold)
643     threshold = SCROLL_THRESHOLD;
644   else
645     threshold = 0;
646   i = 0;
647   while (i < win_info->generic.content_size - threshold
648 	 && !is_displayed)
649     {
650       is_displayed = (((struct tui_win_element *)
651 		       win_info->generic.content[i])->which_element.source.line_or_addr.loa
652 		      == LOA_LINE)
653 	&& (((struct tui_win_element *)
654 	     win_info->generic.content[i])->which_element.source.line_or_addr.u.line_no
655 	    == (int) line);
656       i++;
657     }
658 
659   return is_displayed;
660 }
661 
662 
663 /* Answer whether the a particular line number or address is displayed
664    in the current source window.  */
665 int
666 tui_addr_is_displayed (CORE_ADDR addr,
667 		       struct tui_win_info *win_info,
668 		       int check_threshold)
669 {
670   int is_displayed = FALSE;
671   int i, threshold;
672 
673   if (check_threshold)
674     threshold = SCROLL_THRESHOLD;
675   else
676     threshold = 0;
677   i = 0;
678   while (i < win_info->generic.content_size - threshold
679 	 && !is_displayed)
680     {
681       is_displayed = (((struct tui_win_element *)
682 		       win_info->generic.content[i])->which_element.source.line_or_addr.loa
683 		      == LOA_ADDRESS)
684 	&& (((struct tui_win_element *)
685 	     win_info->generic.content[i])->which_element.source.line_or_addr.u.addr
686 	    == addr);
687       i++;
688     }
689 
690   return is_displayed;
691 }
692 
693 
694 /*****************************************
695 ** STATIC LOCAL FUNCTIONS               **
696 ******************************************/
697