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