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