9925b79dff11fced0f606daa2514e9dbd0626ad0
[external/binutils.git] / gdb / tui / tui-winsource.c
1 /* TUI display source/assembly window.
2
3    Copyright (C) 1998-2019 Free Software Foundation, Inc.
4
5    Contributed by Hewlett-Packard Company.
6
7    This file is part of GDB.
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
21
22 #include "defs.h"
23 #include <ctype.h>
24 #include "symtab.h"
25 #include "frame.h"
26 #include "breakpoint.h"
27 #include "value.h"
28 #include "source.h"
29 #include "objfiles.h"
30 #include "filenames.h"
31
32 #include "tui/tui.h"
33 #include "tui/tui-data.h"
34 #include "tui/tui-io.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 #include "gdb_curses.h"
42
43 /* Function to display the "main" routine.  */
44 void
45 tui_display_main (void)
46 {
47   if ((tui_source_windows ())->count > 0)
48     {
49       struct gdbarch *gdbarch;
50       CORE_ADDR addr;
51
52       tui_get_begin_asm_address (&gdbarch, &addr);
53       if (addr != (CORE_ADDR) 0)
54         {
55           struct symtab *s;
56
57           tui_update_source_windows_with_addr (gdbarch, addr);
58           s = find_pc_line_symtab (addr);
59           if (s != NULL)
60              tui_update_locator_fullname (symtab_to_fullname (s));
61           else
62              tui_update_locator_fullname ("??");
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 gdbarch *gdbarch,
74                           struct symtab *s,
75                           struct tui_line_or_address line_or_addr,
76                           int noerror)
77 {
78   win_info->detail.source_info.horizontal_offset = 0;
79   tui_update_source_window_as_is (win_info, gdbarch, s, line_or_addr, noerror);
80
81   return;
82 }
83
84
85 /* Function to display source in the source/asm window.  This function
86    shows the source as specified by the horizontal offset.  */
87 void
88 tui_update_source_window_as_is (struct tui_win_info *win_info, 
89                                 struct gdbarch *gdbarch,
90                                 struct symtab *s,
91                                 struct tui_line_or_address line_or_addr, 
92                                 int noerror)
93 {
94   enum tui_status ret;
95
96   if (win_info->generic.type == SRC_WIN)
97     ret = tui_set_source_content (s, line_or_addr.u.line_no, noerror);
98   else
99     ret = tui_set_disassem_content (gdbarch, line_or_addr.u.addr);
100
101   if (ret == TUI_FAILURE)
102     {
103       tui_clear_source_content (win_info, EMPTY_SOURCE_PROMPT);
104       tui_clear_exec_info_content (win_info);
105     }
106   else
107     {
108       tui_update_breakpoint_info (win_info, 0);
109       tui_show_source_content (win_info);
110       tui_update_exec_info (win_info);
111       if (win_info->generic.type == SRC_WIN)
112         {
113           symtab_and_line sal;
114
115           sal.line = line_or_addr.u.line_no +
116             (win_info->generic.content_size - 2);
117           sal.symtab = s;
118           sal.pspace = SYMTAB_PSPACE (s);
119           set_current_source_symtab_and_line (sal);
120           /* If the focus was in the asm win, put it in the src win if
121              we don't have a split layout.  */
122           if (tui_win_with_focus () == TUI_DISASM_WIN
123               && tui_current_layout () != SRC_DISASSEM_COMMAND)
124             tui_set_win_focus_to (TUI_SRC_WIN);
125         }
126     }
127
128
129   return;
130 }
131
132
133 /* Function to ensure that the source and/or disassemly windows
134    reflect the input address.  */
135 void
136 tui_update_source_windows_with_addr (struct gdbarch *gdbarch, CORE_ADDR addr)
137 {
138   if (addr != 0)
139     {
140       struct symtab_and_line sal;
141       struct tui_line_or_address l;
142       
143       switch (tui_current_layout ())
144         {
145         case DISASSEM_COMMAND:
146         case DISASSEM_DATA_COMMAND:
147           tui_show_disassem (gdbarch, addr);
148           break;
149         case SRC_DISASSEM_COMMAND:
150           tui_show_disassem_and_update_source (gdbarch, addr);
151           break;
152         default:
153           sal = find_pc_line (addr, 0);
154           l.loa = LOA_LINE;
155           l.u.line_no = sal.line;
156           tui_show_symtab_source (gdbarch, sal.symtab, l, FALSE);
157           break;
158         }
159     }
160   else
161     {
162       int i;
163
164       for (i = 0; i < (tui_source_windows ())->count; i++)
165         {
166           struct tui_win_info *win_info = (tui_source_windows ())->list[i];
167
168           tui_clear_source_content (win_info, EMPTY_SOURCE_PROMPT);
169           tui_clear_exec_info_content (win_info);
170         }
171     }
172 }
173
174 /* Function to ensure that the source and/or disassemly windows
175    reflect the input address.  */
176 void
177 tui_update_source_windows_with_line (struct symtab *s, int line)
178 {
179   struct gdbarch *gdbarch;
180   CORE_ADDR pc;
181   struct tui_line_or_address l;
182
183   if (!s)
184     return;
185
186   gdbarch = get_objfile_arch (SYMTAB_OBJFILE (s));
187
188   switch (tui_current_layout ())
189     {
190     case DISASSEM_COMMAND:
191     case DISASSEM_DATA_COMMAND:
192       find_line_pc (s, line, &pc);
193       tui_update_source_windows_with_addr (gdbarch, pc);
194       break;
195     default:
196       l.loa = LOA_LINE;
197       l.u.line_no = line;
198       tui_show_symtab_source (gdbarch, s, l, FALSE);
199       if (tui_current_layout () == SRC_DISASSEM_COMMAND)
200         {
201           find_line_pc (s, line, &pc);
202           tui_show_disassem (gdbarch, pc);
203         }
204       break;
205     }
206
207   return;
208 }
209
210 void
211 tui_clear_source_content (struct tui_win_info *win_info, 
212                           int display_prompt)
213 {
214   if (win_info != NULL)
215     {
216       int i;
217
218       win_info->generic.content_in_use = FALSE;
219       tui_erase_source_content (win_info, display_prompt);
220       for (i = 0; i < win_info->generic.content_size; i++)
221         {
222           struct tui_win_element *element = win_info->generic.content[i];
223
224           element->which_element.source.has_break = FALSE;
225           element->which_element.source.is_exec_point = FALSE;
226         }
227     }
228 }
229
230
231 void
232 tui_erase_source_content (struct tui_win_info *win_info, 
233                           int display_prompt)
234 {
235   int x_pos;
236   int half_width = (win_info->generic.width - 2) / 2;
237
238   if (win_info->generic.handle != (WINDOW *) NULL)
239     {
240       werase (win_info->generic.handle);
241       tui_check_and_display_highlight_if_needed (win_info);
242       if (display_prompt == EMPTY_SOURCE_PROMPT)
243         {
244           const char *no_src_str;
245
246           if (win_info->generic.type == SRC_WIN)
247             no_src_str = NO_SRC_STRING;
248           else
249             no_src_str = NO_DISASSEM_STRING;
250           if (strlen (no_src_str) >= half_width)
251             x_pos = 1;
252           else
253             x_pos = half_width - strlen (no_src_str);
254           mvwaddstr (win_info->generic.handle,
255                      (win_info->generic.height / 2),
256                      x_pos,
257                      (char *) no_src_str);
258
259           /* elz: Added this function call to set the real contents of
260              the window to what is on the screen, so that later calls
261              to refresh, do display the correct stuff, and not the old
262              image.  */
263
264           tui_set_source_content_nil (win_info, no_src_str);
265         }
266       tui_refresh_win (&win_info->generic);
267     }
268 }
269
270
271 /* Redraw the complete line of a source or disassembly window.  */
272 static void
273 tui_show_source_line (struct tui_win_info *win_info, int lineno)
274 {
275   struct tui_win_element *line;
276   int x;
277
278   line = win_info->generic.content[lineno - 1];
279   if (line->which_element.source.is_exec_point)
280     wattron (win_info->generic.handle, A_STANDOUT);
281
282   wmove (win_info->generic.handle, lineno, 1);
283   tui_puts (line->which_element.source.line,
284             win_info->generic.handle);
285   if (line->which_element.source.is_exec_point)
286     wattroff (win_info->generic.handle, A_STANDOUT);
287
288   /* Clear to end of line but stop before the border.  */
289   x = getcurx (win_info->generic.handle);
290   while (x + 1 < win_info->generic.width)
291     {
292       waddch (win_info->generic.handle, ' ');
293       x = getcurx (win_info->generic.handle);
294     }
295 }
296
297 void
298 tui_show_source_content (struct tui_win_info *win_info)
299 {
300   if (win_info->generic.content_size > 0)
301     {
302       int lineno;
303
304       for (lineno = 1; lineno <= win_info->generic.content_size; lineno++)
305         tui_show_source_line (win_info, lineno);
306     }
307   else
308     tui_erase_source_content (win_info, TRUE);
309
310   tui_check_and_display_highlight_if_needed (win_info);
311   tui_refresh_win (&win_info->generic);
312   win_info->generic.content_in_use = TRUE;
313 }
314
315 /* Refill the source window's source cache and update it.  If WIN_INFO
316    is a disassembly window, then just update it.  */
317
318 void
319 tui_refill_source_window (struct tui_win_info *win_info)
320 {
321   symtab *s = nullptr;
322
323   if (win_info->generic.type == SRC_WIN)
324     {
325       symtab_and_line cursal = get_current_source_symtab_and_line ();
326       s = (cursal.symtab == NULL
327            ? find_pc_line_symtab (get_frame_pc (get_selected_frame (NULL)))
328            : cursal.symtab);
329     }
330
331   tui_update_source_window_as_is (win_info,
332                                   win_info->detail.source_info.gdbarch,
333                                   s,
334                                   win_info->generic.content[0]
335                                     ->which_element.source.line_or_addr,
336                                   FALSE);
337 }
338
339 /* Scroll the source forward or backward horizontally.  */
340
341 void
342 tui_horizontal_source_scroll (struct tui_win_info *win_info,
343                               enum tui_scroll_direction direction,
344                               int num_to_scroll)
345 {
346   if (win_info->generic.content != NULL)
347     {
348       int offset;
349
350       if (direction == LEFT_SCROLL)
351         offset = win_info->detail.source_info.horizontal_offset
352           + num_to_scroll;
353       else
354         {
355           offset = win_info->detail.source_info.horizontal_offset
356             - num_to_scroll;
357           if (offset < 0)
358             offset = 0;
359         }
360       win_info->detail.source_info.horizontal_offset = offset;
361       tui_refill_source_window (win_info);
362     }
363 }
364
365
366 /* Set or clear the has_break flag in the line whose line is
367    line_no.  */
368
369 void
370 tui_set_is_exec_point_at (struct tui_line_or_address l, 
371                           struct tui_win_info *win_info)
372 {
373   int changed = 0;
374   int i;
375   tui_win_content content = win_info->generic.content;
376
377   i = 0;
378   while (i < win_info->generic.content_size)
379     {
380       int new_state;
381       struct tui_line_or_address content_loa =
382         content[i]->which_element.source.line_or_addr;
383
384       gdb_assert (l.loa == LOA_ADDRESS || l.loa == LOA_LINE);
385       gdb_assert (content_loa.loa == LOA_LINE
386                   || content_loa.loa == LOA_ADDRESS);
387       if (content_loa.loa == l.loa
388           && ((l.loa == LOA_LINE && content_loa.u.line_no == l.u.line_no)
389               || (content_loa.u.addr == l.u.addr)))
390         new_state = TRUE;
391       else
392         new_state = FALSE;
393       if (new_state != content[i]->which_element.source.is_exec_point)
394         {
395           changed++;
396           content[i]->which_element.source.is_exec_point = new_state;
397           tui_show_source_line (win_info, i + 1);
398         }
399       i++;
400     }
401   if (changed)
402     tui_refill_source_window (win_info);
403 }
404
405 /* Update the execution windows to show the active breakpoints.
406    This is called whenever a breakpoint is inserted, removed or
407    has its state changed.  */
408 void
409 tui_update_all_breakpoint_info (void)
410 {
411   struct tui_list *list = tui_source_windows ();
412   int i;
413
414   for (i = 0; i < list->count; i++)
415     {
416       struct tui_win_info *win = list->list[i];
417
418       if (tui_update_breakpoint_info (win, FALSE))
419         {
420           tui_update_exec_info (win);
421         }
422     }
423 }
424
425
426 /* Scan the source window and the breakpoints to update the has_break
427    information for each line.
428
429    Returns 1 if something changed and the execution window must be
430    refreshed.  */
431
432 int
433 tui_update_breakpoint_info (struct tui_win_info *win, 
434                             int current_only)
435 {
436   int i;
437   int need_refresh = 0;
438   struct tui_source_info *src = &win->detail.source_info;
439
440   for (i = 0; i < win->generic.content_size; i++)
441     {
442       struct breakpoint *bp;
443       extern struct breakpoint *breakpoint_chain;
444       int mode;
445       struct tui_source_element *line;
446
447       line = &win->generic.content[i]->which_element.source;
448       if (current_only && !line->is_exec_point)
449          continue;
450
451       /* Scan each breakpoint to see if the current line has something to
452          do with it.  Identify enable/disabled breakpoints as well as
453          those that we already hit.  */
454       mode = 0;
455       for (bp = breakpoint_chain;
456            bp != (struct breakpoint *) NULL;
457            bp = bp->next)
458         {
459           struct bp_location *loc;
460
461           gdb_assert (line->line_or_addr.loa == LOA_LINE
462                       || line->line_or_addr.loa == LOA_ADDRESS);
463
464           for (loc = bp->loc; loc != NULL; loc = loc->next)
465             {
466               if ((win == TUI_SRC_WIN
467                    && loc->symtab != NULL
468                    && filename_cmp (src->fullname,
469                                     symtab_to_fullname (loc->symtab)) == 0
470                    && line->line_or_addr.loa == LOA_LINE
471                    && loc->line_number == line->line_or_addr.u.line_no)
472                   || (win == TUI_DISASM_WIN
473                       && line->line_or_addr.loa == LOA_ADDRESS
474                       && loc->address == line->line_or_addr.u.addr))
475                 {
476                   if (bp->enable_state == bp_disabled)
477                     mode |= TUI_BP_DISABLED;
478                   else
479                     mode |= TUI_BP_ENABLED;
480                   if (bp->hit_count)
481                     mode |= TUI_BP_HIT;
482                   if (bp->loc->cond)
483                     mode |= TUI_BP_CONDITIONAL;
484                   if (bp->type == bp_hardware_breakpoint)
485                     mode |= TUI_BP_HARDWARE;
486                 }
487             }
488         }
489       if (line->has_break != mode)
490         {
491           line->has_break = mode;
492           need_refresh = 1;
493         }
494     }
495   return need_refresh;
496 }
497
498
499 /* Function to initialize the content of the execution info window,
500    based upon the input window which is either the source or
501    disassembly window.  */
502 enum tui_status
503 tui_set_exec_info_content (struct tui_win_info *win_info)
504 {
505   enum tui_status ret = TUI_SUCCESS;
506
507   if (win_info->detail.source_info.execution_info
508       != (struct tui_gen_win_info *) NULL)
509     {
510       struct tui_gen_win_info *exec_info_ptr
511         = win_info->detail.source_info.execution_info;
512
513       if (exec_info_ptr->content == NULL)
514         exec_info_ptr->content =
515           tui_alloc_content (win_info->generic.height, exec_info_ptr->type);
516       if (exec_info_ptr->content != NULL)
517         {
518           int i;
519
520           tui_update_breakpoint_info (win_info, 1);
521           for (i = 0; i < win_info->generic.content_size; i++)
522             {
523               struct tui_win_element *element;
524               struct tui_win_element *src_element;
525               int mode;
526
527               element = exec_info_ptr->content[i];
528               src_element = win_info->generic.content[i];
529
530               memset(element->which_element.simple_string, ' ',
531                      sizeof(element->which_element.simple_string));
532               element->which_element.simple_string[TUI_EXECINFO_SIZE - 1] = 0;
533
534               /* Now update the exec info content based upon the state
535                  of each line as indicated by the source content.  */
536               mode = src_element->which_element.source.has_break;
537               if (mode & TUI_BP_HIT)
538                 element->which_element.simple_string[TUI_BP_HIT_POS] =
539                   (mode & TUI_BP_HARDWARE) ? 'H' : 'B';
540               else if (mode & (TUI_BP_ENABLED | TUI_BP_DISABLED))
541                 element->which_element.simple_string[TUI_BP_HIT_POS] =
542                   (mode & TUI_BP_HARDWARE) ? 'h' : 'b';
543
544               if (mode & TUI_BP_ENABLED)
545                 element->which_element.simple_string[TUI_BP_BREAK_POS] = '+';
546               else if (mode & TUI_BP_DISABLED)
547                 element->which_element.simple_string[TUI_BP_BREAK_POS] = '-';
548
549               if (src_element->which_element.source.is_exec_point)
550                 element->which_element.simple_string[TUI_EXEC_POS] = '>';
551             }
552           exec_info_ptr->content_size = win_info->generic.content_size;
553         }
554       else
555         ret = TUI_FAILURE;
556     }
557
558   return ret;
559 }
560
561
562 void
563 tui_show_exec_info_content (struct tui_win_info *win_info)
564 {
565   struct tui_gen_win_info *exec_info
566     = win_info->detail.source_info.execution_info;
567   int cur_line;
568
569   werase (exec_info->handle);
570   tui_refresh_win (exec_info);
571   for (cur_line = 1; (cur_line <= exec_info->content_size); cur_line++)
572     mvwaddstr (exec_info->handle,
573                cur_line,
574                0,
575                (char *) exec_info->content[cur_line - 1]
576                           ->which_element.simple_string);
577   tui_refresh_win (exec_info);
578   exec_info->content_in_use = TRUE;
579 }
580
581
582 void
583 tui_erase_exec_info_content (struct tui_win_info *win_info)
584 {
585   struct tui_gen_win_info *exec_info
586     = win_info->detail.source_info.execution_info;
587
588   werase (exec_info->handle);
589   tui_refresh_win (exec_info);
590 }
591
592 void
593 tui_clear_exec_info_content (struct tui_win_info *win_info)
594 {
595   win_info->detail.source_info.execution_info->content_in_use = FALSE;
596   tui_erase_exec_info_content (win_info);
597
598   return;
599 }
600
601 /* Function to update the execution info window.  */
602 void
603 tui_update_exec_info (struct tui_win_info *win_info)
604 {
605   tui_set_exec_info_content (win_info);
606   tui_show_exec_info_content (win_info);
607 }
608
609 enum tui_status
610 tui_alloc_source_buffer (struct tui_win_info *win_info)
611 {
612   int i, line_width, max_lines;
613
614   /* The window width/height includes the highlight box.  Determine actual
615      content dimensions, including string null-terminators.  */
616   max_lines = win_info->generic.height - 2;
617   line_width = win_info->generic.width - 2 + 1;
618
619   /* Allocate the buffer for the source lines.  */
620   if (win_info->generic.content == NULL)
621     {
622       /* Allocate the content list.  */
623       win_info->generic.content = tui_alloc_content (max_lines, SRC_WIN);
624       for (i = 0; i < max_lines; i++)
625         win_info->generic.content[i]->which_element.source.line
626           = (char *) xmalloc (line_width);
627     }
628
629   return TUI_SUCCESS;
630 }
631
632
633 /* Answer whether a particular line number or address is displayed
634    in the current source window.  */
635 int
636 tui_line_is_displayed (int line, 
637                        struct tui_win_info *win_info,
638                        int check_threshold)
639 {
640   int is_displayed = FALSE;
641   int i, threshold;
642
643   if (check_threshold)
644     threshold = SCROLL_THRESHOLD;
645   else
646     threshold = 0;
647   i = 0;
648   while (i < win_info->generic.content_size - threshold
649          && !is_displayed)
650     {
651       is_displayed
652         = win_info->generic.content[i]
653             ->which_element.source.line_or_addr.loa == LOA_LINE
654           && win_info->generic.content[i]
655                ->which_element.source.line_or_addr.u.line_no == line;
656       i++;
657     }
658
659   return is_displayed;
660 }
661
662
663 /* Answer whether a particular line number or address is displayed
664    in the current source window.  */
665 int
666 tui_addr_is_displayed (CORE_ADDR addr, 
667                        struct tui_win_info *win_info,
668                        int check_threshold)
669 {
670   int is_displayed = FALSE;
671   int i, threshold;
672
673   if (check_threshold)
674     threshold = SCROLL_THRESHOLD;
675   else
676     threshold = 0;
677   i = 0;
678   while (i < win_info->generic.content_size - threshold
679          && !is_displayed)
680     {
681       is_displayed
682         = win_info->generic.content[i]
683             ->which_element.source.line_or_addr.loa == LOA_ADDRESS
684           && win_info->generic.content[i]
685                ->which_element.source.line_or_addr.u.addr == addr;
686       i++;
687     }
688
689   return is_displayed;
690 }
691
692
693 /*****************************************
694 ** STATIC LOCAL FUNCTIONS               **
695 ******************************************/