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