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