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