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