2011-01-05 Michael Snyder <msnyder@vmware.com>
[external/binutils.git] / gdb / tui / tui-winsource.c
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
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
332             = get_current_source_symtab_and_line ();
333
334           if (cursal.symtab == NULL)
335             s = find_pc_symtab (get_frame_pc (get_selected_frame (NULL)));
336           else
337             s = cursal.symtab;
338         }
339
340       if (direction == LEFT_SCROLL)
341         offset = win_info->detail.source_info.horizontal_offset
342           + num_to_scroll;
343       else
344         {
345           if ((offset = win_info->detail.source_info.horizontal_offset
346                - num_to_scroll) < 0)
347             offset = 0;
348         }
349       win_info->detail.source_info.horizontal_offset = offset;
350       tui_update_source_window_as_is (win_info, gdbarch, s,
351                                       ((struct tui_win_element *)
352                                        win_info->generic.content[0])->which_element.source.line_or_addr,
353                                       FALSE);
354     }
355
356   return;
357 }
358
359
360 /* Set or clear the has_break flag in the line whose line is
361    line_no.  */
362
363 void
364 tui_set_is_exec_point_at (struct tui_line_or_address l, 
365                           struct tui_win_info *win_info)
366 {
367   int changed = 0;
368   int i;
369   tui_win_content content = (tui_win_content) win_info->generic.content;
370
371   i = 0;
372   while (i < win_info->generic.content_size)
373     {
374       int new_state;
375       struct tui_line_or_address content_loa =
376         content[i]->which_element.source.line_or_addr;
377
378       gdb_assert (l.loa == LOA_ADDRESS || l.loa == LOA_LINE);
379       gdb_assert (content_loa.loa == LOA_LINE
380                   || content_loa.loa == LOA_ADDRESS);
381       if (content_loa.loa == l.loa
382           && ((l.loa == LOA_LINE && content_loa.u.line_no == l.u.line_no)
383               || (content_loa.u.addr == l.u.addr)))
384         new_state = TRUE;
385       else
386         new_state = FALSE;
387       if (new_state != content[i]->which_element.source.is_exec_point)
388         {
389           changed++;
390           content[i]->which_element.source.is_exec_point = new_state;
391           tui_show_source_line (win_info, i + 1);
392         }
393       i++;
394     }
395   if (changed)
396     tui_refresh_win (&win_info->generic);
397 }
398
399 /* Update the execution windows to show the active breakpoints.
400    This is called whenever a breakpoint is inserted, removed or
401    has its state changed.  */
402 void
403 tui_update_all_breakpoint_info (void)
404 {
405   struct tui_list *list = tui_source_windows ();
406   int i;
407
408   for (i = 0; i < list->count; i++)
409     {
410       struct tui_win_info *win = list->list[i];
411
412       if (tui_update_breakpoint_info (win, FALSE))
413         {
414           tui_update_exec_info (win);
415         }
416     }
417 }
418
419
420 /* Scan the source window and the breakpoints to update the has_break
421    information for each line.
422
423    Returns 1 if something changed and the execution window must be
424    refreshed.  */
425
426 int
427 tui_update_breakpoint_info (struct tui_win_info *win, 
428                             int current_only)
429 {
430   int i;
431   int need_refresh = 0;
432   struct tui_source_info *src = &win->detail.source_info;
433
434   for (i = 0; i < win->generic.content_size; i++)
435     {
436       struct breakpoint *bp;
437       extern struct breakpoint *breakpoint_chain;
438       int mode;
439       struct tui_source_element *line;
440
441       line = &((struct tui_win_element *)
442                win->generic.content[i])->which_element.source;
443       if (current_only && !line->is_exec_point)
444          continue;
445
446       /* Scan each breakpoint to see if the current line has something to
447          do with it.  Identify enable/disabled breakpoints as well as
448          those that we already hit.  */
449       mode = 0;
450       for (bp = breakpoint_chain;
451            bp != (struct breakpoint *) NULL;
452            bp = bp->next)
453         {
454           gdb_assert (line->line_or_addr.loa == LOA_LINE
455                       || line->line_or_addr.loa == LOA_ADDRESS);
456           if ((win == TUI_SRC_WIN
457                && bp->source_file
458                && (strcmp (src->filename, bp->source_file) == 0)
459                && line->line_or_addr.loa == LOA_LINE
460                && bp->line_number == line->line_or_addr.u.line_no)
461               || (win == TUI_DISASM_WIN
462                   && line->line_or_addr.loa == LOA_ADDRESS
463                   && bp->loc != NULL
464                   && bp->loc->address == line->line_or_addr.u.addr))
465             {
466               if (bp->enable_state == bp_disabled)
467                 mode |= TUI_BP_DISABLED;
468               else
469                 mode |= TUI_BP_ENABLED;
470               if (bp->hit_count)
471                 mode |= TUI_BP_HIT;
472               if (bp->loc->cond)
473                 mode |= TUI_BP_CONDITIONAL;
474               if (bp->type == bp_hardware_breakpoint)
475                 mode |= TUI_BP_HARDWARE;
476             }
477         }
478       if (line->has_break != mode)
479         {
480           line->has_break = mode;
481           need_refresh = 1;
482         }
483     }
484   return need_refresh;
485 }
486
487
488 /* Function to initialize the content of the execution info window,
489    based upon the input window which is either the source or
490    disassembly window.  */
491 enum tui_status
492 tui_set_exec_info_content (struct tui_win_info *win_info)
493 {
494   enum tui_status ret = TUI_SUCCESS;
495
496   if (win_info->detail.source_info.execution_info
497       != (struct tui_gen_win_info *) NULL)
498     {
499       struct tui_gen_win_info *exec_info_ptr
500         = win_info->detail.source_info.execution_info;
501
502       if (exec_info_ptr->content == NULL)
503         exec_info_ptr->content =
504           (void **) tui_alloc_content (win_info->generic.height,
505                                          exec_info_ptr->type);
506       if (exec_info_ptr->content != NULL)
507         {
508           int i;
509
510           tui_update_breakpoint_info (win_info, 1);
511           for (i = 0; i < win_info->generic.content_size; i++)
512             {
513               struct tui_win_element *element;
514               struct tui_win_element *src_element;
515               int mode;
516
517               element = (struct tui_win_element *) exec_info_ptr->content[i];
518               src_element = (struct tui_win_element *)
519                 win_info->generic.content[i];
520
521               memset(element->which_element.simple_string, ' ',
522                      sizeof(element->which_element.simple_string));
523               element->which_element.simple_string[TUI_EXECINFO_SIZE - 1] = 0;
524
525               /* Now update the exec info content based upon the state
526                  of each line as indicated by the source content.  */
527               mode = src_element->which_element.source.has_break;
528               if (mode & TUI_BP_HIT)
529                 element->which_element.simple_string[TUI_BP_HIT_POS] =
530                   (mode & TUI_BP_HARDWARE) ? 'H' : 'B';
531               else if (mode & (TUI_BP_ENABLED | TUI_BP_DISABLED))
532                 element->which_element.simple_string[TUI_BP_HIT_POS] =
533                   (mode & TUI_BP_HARDWARE) ? 'h' : 'b';
534
535               if (mode & TUI_BP_ENABLED)
536                 element->which_element.simple_string[TUI_BP_BREAK_POS] = '+';
537               else if (mode & TUI_BP_DISABLED)
538                 element->which_element.simple_string[TUI_BP_BREAK_POS] = '-';
539
540               if (src_element->which_element.source.is_exec_point)
541                 element->which_element.simple_string[TUI_EXEC_POS] = '>';
542             }
543           exec_info_ptr->content_size = win_info->generic.content_size;
544         }
545       else
546         ret = TUI_FAILURE;
547     }
548
549   return ret;
550 }
551
552
553 void
554 tui_show_exec_info_content (struct tui_win_info *win_info)
555 {
556   struct tui_gen_win_info *exec_info
557     = win_info->detail.source_info.execution_info;
558   int cur_line;
559
560   werase (exec_info->handle);
561   tui_refresh_win (exec_info);
562   for (cur_line = 1; (cur_line <= exec_info->content_size); cur_line++)
563     mvwaddstr (exec_info->handle,
564                cur_line,
565                0,
566                ((struct tui_win_element *)
567                 exec_info->content[cur_line - 1])->which_element.simple_string);
568   tui_refresh_win (exec_info);
569   exec_info->content_in_use = TRUE;
570 }
571
572
573 void
574 tui_erase_exec_info_content (struct tui_win_info *win_info)
575 {
576   struct tui_gen_win_info *exec_info
577     = win_info->detail.source_info.execution_info;
578
579   werase (exec_info->handle);
580   tui_refresh_win (exec_info);
581 }
582
583 void
584 tui_clear_exec_info_content (struct tui_win_info *win_info)
585 {
586   win_info->detail.source_info.execution_info->content_in_use = FALSE;
587   tui_erase_exec_info_content (win_info);
588
589   return;
590 }
591
592 /* Function to update the execution info window.  */
593 void
594 tui_update_exec_info (struct tui_win_info *win_info)
595 {
596   tui_set_exec_info_content (win_info);
597   tui_show_exec_info_content (win_info);
598 }
599
600 enum tui_status
601 tui_alloc_source_buffer (struct tui_win_info *win_info)
602 {
603   char *src_line_buf;
604   int i, line_width, max_lines;
605
606   max_lines = win_info->generic.height; /* Less the highlight box.  */
607   line_width = win_info->generic.width - 1;
608   /*
609    * Allocate the buffer for the source lines.  Do this only once
610    * since they will be re-used for all source displays.  The only
611    * other time this will be done is when a window's size changes.
612    */
613   if (win_info->generic.content == NULL)
614     {
615       src_line_buf = (char *) 
616         xmalloc ((max_lines * line_width) * sizeof (char));
617       if (src_line_buf == (char *) NULL)
618         {
619           fputs_unfiltered ("Unable to Allocate Memory for "
620                             "Source or Disassembly Display.\n",
621                             gdb_stderr);
622           return TUI_FAILURE;
623         }
624       /* Allocate the content list.  */
625       if ((win_info->generic.content =
626            (void **) tui_alloc_content (max_lines, SRC_WIN)) == NULL)
627         {
628           xfree (src_line_buf);
629           fputs_unfiltered ("Unable to Allocate Memory for "
630                             "Source or Disassembly Display.\n",
631                             gdb_stderr);
632           return TUI_FAILURE;
633         }
634       for (i = 0; i < max_lines; i++)
635         ((struct tui_win_element *)
636          win_info->generic.content[i])->which_element.source.line =
637           src_line_buf + (line_width * i);
638     }
639
640   return TUI_SUCCESS;
641 }
642
643
644 /* Answer whether the a particular line number or address is displayed
645    in the current source window.  */
646 int
647 tui_line_is_displayed (int line, 
648                        struct tui_win_info *win_info,
649                        int check_threshold)
650 {
651   int is_displayed = FALSE;
652   int i, threshold;
653
654   if (check_threshold)
655     threshold = SCROLL_THRESHOLD;
656   else
657     threshold = 0;
658   i = 0;
659   while (i < win_info->generic.content_size - threshold
660          && !is_displayed)
661     {
662       is_displayed = (((struct tui_win_element *)
663                        win_info->generic.content[i])->which_element.source.line_or_addr.loa
664                       == LOA_LINE)
665         && (((struct tui_win_element *)
666              win_info->generic.content[i])->which_element.source.line_or_addr.u.line_no
667             == (int) line);
668       i++;
669     }
670
671   return is_displayed;
672 }
673
674
675 /* Answer whether the a particular line number or address is displayed
676    in the current source window.  */
677 int
678 tui_addr_is_displayed (CORE_ADDR addr, 
679                        struct tui_win_info *win_info,
680                        int check_threshold)
681 {
682   int is_displayed = FALSE;
683   int i, threshold;
684
685   if (check_threshold)
686     threshold = SCROLL_THRESHOLD;
687   else
688     threshold = 0;
689   i = 0;
690   while (i < win_info->generic.content_size - threshold
691          && !is_displayed)
692     {
693       is_displayed = (((struct tui_win_element *)
694                        win_info->generic.content[i])->which_element.source.line_or_addr.loa
695                       == LOA_ADDRESS)
696         && (((struct tui_win_element *)
697              win_info->generic.content[i])->which_element.source.line_or_addr.u.addr
698             == addr);
699       i++;
700     }
701
702   return is_displayed;
703 }
704
705
706 /*****************************************
707 ** STATIC LOCAL FUNCTIONS               **
708 ******************************************/