6ec1f1bc0b6c72adae0ea02d85f54100bd780a6f
[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 ()
46 {
47   if (!tui_source_windows ().empty ())
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_source_window_base *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->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_source_window_base *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->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->type == SRC_WIN)
112         {
113           symtab_and_line sal;
114
115           sal.line = line_or_addr.u.line_no +
116             (win_info->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       for (struct tui_source_window_base *win_info : tui_source_windows ())
163         {
164           tui_clear_source_content (win_info, EMPTY_SOURCE_PROMPT);
165           tui_clear_exec_info_content (win_info);
166         }
167     }
168 }
169
170 /* Function to ensure that the source and/or disassemly windows
171    reflect the input address.  */
172 void
173 tui_update_source_windows_with_line (struct symtab *s, int line)
174 {
175   struct gdbarch *gdbarch;
176   CORE_ADDR pc;
177   struct tui_line_or_address l;
178
179   if (!s)
180     return;
181
182   gdbarch = get_objfile_arch (SYMTAB_OBJFILE (s));
183
184   switch (tui_current_layout ())
185     {
186     case DISASSEM_COMMAND:
187     case DISASSEM_DATA_COMMAND:
188       find_line_pc (s, line, &pc);
189       tui_update_source_windows_with_addr (gdbarch, pc);
190       break;
191     default:
192       l.loa = LOA_LINE;
193       l.u.line_no = line;
194       tui_show_symtab_source (gdbarch, s, l, FALSE);
195       if (tui_current_layout () == SRC_DISASSEM_COMMAND)
196         {
197           find_line_pc (s, line, &pc);
198           tui_show_disassem (gdbarch, pc);
199         }
200       break;
201     }
202
203   return;
204 }
205
206 void
207 tui_clear_source_content (struct tui_source_window_base *win_info,
208                           int display_prompt)
209 {
210   if (win_info != NULL)
211     {
212       int i;
213
214       win_info->content_in_use = FALSE;
215       tui_erase_source_content (win_info, display_prompt);
216       for (i = 0; i < win_info->content.size (); i++)
217         {
218           struct tui_source_element *element = &win_info->content[i];
219
220           element->has_break = FALSE;
221           element->is_exec_point = false;
222         }
223     }
224 }
225
226
227 void
228 tui_erase_source_content (struct tui_source_window_base *win_info,
229                           int display_prompt)
230 {
231   int x_pos;
232   int half_width = (win_info->width - 2) / 2;
233
234   if (win_info->handle != NULL)
235     {
236       werase (win_info->handle);
237       tui_check_and_display_highlight_if_needed (win_info);
238       if (display_prompt == EMPTY_SOURCE_PROMPT)
239         {
240           const char *no_src_str;
241
242           if (win_info->type == SRC_WIN)
243             no_src_str = NO_SRC_STRING;
244           else
245             no_src_str = NO_DISASSEM_STRING;
246           if (strlen (no_src_str) >= half_width)
247             x_pos = 1;
248           else
249             x_pos = half_width - strlen (no_src_str);
250           mvwaddstr (win_info->handle,
251                      (win_info->height / 2),
252                      x_pos,
253                      (char *) no_src_str);
254
255           /* elz: Added this function call to set the real contents of
256              the window to what is on the screen, so that later calls
257              to refresh, do display the correct stuff, and not the old
258              image.  */
259
260           tui_set_source_content_nil (win_info, no_src_str);
261         }
262       win_info->refresh_window ();
263     }
264 }
265
266
267 /* Redraw the complete line of a source or disassembly window.  */
268 static void
269 tui_show_source_line (struct tui_source_window_base *win_info, int lineno)
270 {
271   struct tui_source_element *line;
272   int x;
273
274   line = &win_info->content[lineno - 1];
275   if (line->is_exec_point)
276     tui_set_reverse_mode (win_info->handle, true);
277
278   wmove (win_info->handle, lineno, 1);
279   tui_puts (line->line,
280             win_info->handle);
281   if (line->is_exec_point)
282     tui_set_reverse_mode (win_info->handle, false);
283
284   /* Clear to end of line but stop before the border.  */
285   x = getcurx (win_info->handle);
286   while (x + 1 < win_info->width)
287     {
288       waddch (win_info->handle, ' ');
289       x = getcurx (win_info->handle);
290     }
291 }
292
293 void
294 tui_show_source_content (struct tui_source_window_base *win_info)
295 {
296   if (!win_info->content.empty ())
297     {
298       int lineno;
299
300       for (lineno = 1; lineno <= win_info->content.size (); lineno++)
301         tui_show_source_line (win_info, lineno);
302     }
303   else
304     tui_erase_source_content (win_info, TRUE);
305
306   tui_check_and_display_highlight_if_needed (win_info);
307   win_info->refresh_window ();
308   win_info->content_in_use = TRUE;
309 }
310
311 /* See tui-data.h.  */
312
313 void
314 tui_source_window_base::refill ()
315 {
316   symtab *s = nullptr;
317
318   if (type == SRC_WIN)
319     {
320       symtab_and_line cursal = get_current_source_symtab_and_line ();
321       s = (cursal.symtab == NULL
322            ? find_pc_line_symtab (get_frame_pc (get_selected_frame (NULL)))
323            : cursal.symtab);
324     }
325
326   tui_update_source_window_as_is (this, gdbarch, s,
327                                   content[0].line_or_addr,
328                                   FALSE);
329 }
330
331 /* Scroll the source forward or backward horizontally.  */
332
333 void
334 tui_source_window_base::do_scroll_horizontal (int num_to_scroll)
335 {
336   if (!content.empty ())
337     {
338       int offset = horizontal_offset + num_to_scroll;
339       if (offset < 0)
340         offset = 0;
341       horizontal_offset = offset;
342       refill ();
343     }
344 }
345
346
347 /* Set or clear the has_break flag in the line whose line is
348    line_no.  */
349
350 void
351 tui_source_window_base::set_is_exec_point_at (struct tui_line_or_address l)
352 {
353   bool changed = false;
354   int i;
355
356   i = 0;
357   while (i < content.size ())
358     {
359       bool new_state;
360       struct tui_line_or_address content_loa =
361         content[i].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               || (l.loa == LOA_ADDRESS && content_loa.u.addr == l.u.addr)))
369         new_state = true;
370       else
371         new_state = false;
372       if (new_state != content[i].is_exec_point)
373         {
374           changed = true;
375           content[i].is_exec_point = new_state;
376           tui_show_source_line (this, i + 1);
377         }
378       i++;
379     }
380   if (changed)
381     refill ();
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 ()
389 {
390   for (tui_source_window_base *win : tui_source_windows ())
391     {
392       if (tui_update_breakpoint_info (win, FALSE))
393         {
394           tui_update_exec_info (win);
395         }
396     }
397 }
398
399
400 /* Scan the source window and the breakpoints to update the has_break
401    information for each line.
402
403    Returns 1 if something changed and the execution window must be
404    refreshed.  */
405
406 int
407 tui_update_breakpoint_info (struct tui_source_window_base *win, 
408                             int current_only)
409 {
410   int i;
411   int need_refresh = 0;
412   tui_source_window_base *src = (tui_source_window_base *) win;
413
414   for (i = 0; i < win->content.size (); i++)
415     {
416       struct breakpoint *bp;
417       extern struct breakpoint *breakpoint_chain;
418       int mode;
419       struct tui_source_element *line;
420
421       line = &win->content[i];
422       if (current_only && !line->is_exec_point)
423          continue;
424
425       /* Scan each breakpoint to see if the current line has something to
426          do with it.  Identify enable/disabled breakpoints as well as
427          those that we already hit.  */
428       mode = 0;
429       for (bp = breakpoint_chain;
430            bp != NULL;
431            bp = bp->next)
432         {
433           struct bp_location *loc;
434
435           gdb_assert (line->line_or_addr.loa == LOA_LINE
436                       || line->line_or_addr.loa == LOA_ADDRESS);
437
438           for (loc = bp->loc; loc != NULL; loc = loc->next)
439             {
440               if ((win == TUI_SRC_WIN
441                    && loc->symtab != NULL
442                    && filename_cmp (src->fullname,
443                                     symtab_to_fullname (loc->symtab)) == 0
444                    && line->line_or_addr.loa == LOA_LINE
445                    && loc->line_number == line->line_or_addr.u.line_no)
446                   || (win == TUI_DISASM_WIN
447                       && line->line_or_addr.loa == LOA_ADDRESS
448                       && 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         }
463       if (line->has_break != mode)
464         {
465           line->has_break = mode;
466           need_refresh = 1;
467         }
468     }
469   return need_refresh;
470 }
471
472 /* See tui-data.h.  */
473
474 tui_exec_info_content *
475 tui_exec_info_window::maybe_allocate_content (int n_elements)
476 {
477   if (m_content == nullptr)
478     m_content = XNEWVEC (tui_exec_info_content, n_elements);
479   return m_content;
480 }
481
482
483 /* Function to initialize the content of the execution info window,
484    based upon the input window which is either the source or
485    disassembly window.  */
486 void
487 tui_set_exec_info_content (struct tui_source_window_base *win_info)
488 {
489   if (win_info->execution_info != NULL)
490     {
491       tui_exec_info_content *content
492         = win_info->execution_info->maybe_allocate_content (win_info->height);
493
494       tui_update_breakpoint_info (win_info, 1);
495       for (int i = 0; i < win_info->content.size (); i++)
496         {
497           tui_exec_info_content &element = content[i];
498           struct tui_source_element *src_element;
499           int mode;
500
501           src_element = &win_info->content[i];
502
503           memset (element, ' ', sizeof (tui_exec_info_content));
504           element[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->has_break;
509           if (mode & TUI_BP_HIT)
510             element[TUI_BP_HIT_POS] = (mode & TUI_BP_HARDWARE) ? 'H' : 'B';
511           else if (mode & (TUI_BP_ENABLED | TUI_BP_DISABLED))
512             element[TUI_BP_HIT_POS] = (mode & TUI_BP_HARDWARE) ? 'h' : 'b';
513
514           if (mode & TUI_BP_ENABLED)
515             element[TUI_BP_BREAK_POS] = '+';
516           else if (mode & TUI_BP_DISABLED)
517             element[TUI_BP_BREAK_POS] = '-';
518
519           if (src_element->is_exec_point)
520             element[TUI_EXEC_POS] = '>';
521         }
522     }
523 }
524
525
526 void
527 tui_show_exec_info_content (struct tui_source_window_base *win_info)
528 {
529   struct tui_exec_info_window *exec_info = win_info->execution_info;
530   const tui_exec_info_content *content = exec_info->get_content ();
531
532   werase (exec_info->handle);
533   exec_info->refresh_window ();
534   for (int cur_line = 1; cur_line <= win_info->content.size (); cur_line++)
535     mvwaddstr (exec_info->handle,
536                cur_line,
537                0,
538                content[cur_line - 1]);
539   exec_info->refresh_window ();
540   exec_info->content_in_use = TRUE;
541 }
542
543
544 void
545 tui_erase_exec_info_content (struct tui_source_window_base *win_info)
546 {
547   struct tui_gen_win_info *exec_info = win_info->execution_info;
548
549   werase (exec_info->handle);
550   exec_info->refresh_window ();
551 }
552
553 void
554 tui_clear_exec_info_content (struct tui_source_window_base *win_info)
555 {
556   win_info->execution_info->content_in_use = FALSE;
557   tui_erase_exec_info_content (win_info);
558 }
559
560 /* Function to update the execution info window.  */
561 void
562 tui_update_exec_info (struct tui_source_window_base *win_info)
563 {
564   tui_set_exec_info_content (win_info);
565   tui_show_exec_info_content (win_info);
566 }
567
568 void
569 tui_alloc_source_buffer (struct tui_source_window_base *win_info)
570 {
571   int i, line_width, max_lines;
572
573   /* The window width/height includes the highlight box.  Determine actual
574      content dimensions, including string null-terminators.  */
575   max_lines = win_info->height - 2;
576   line_width = win_info->width - 2 + 1;
577
578   /* Allocate the buffer for the source lines.  */
579   win_info->content.resize (max_lines);
580   for (i = 0; i < max_lines; i++)
581     {
582       if (win_info->content[i].line == nullptr)
583         win_info->content[i].line = (char *) xmalloc (line_width);
584     }
585 }
586
587
588 /* Answer whether a particular line number or address is displayed
589    in the current source window.  */
590 int
591 tui_line_is_displayed (int line, 
592                        struct tui_source_window_base *win_info,
593                        int check_threshold)
594 {
595   int is_displayed = FALSE;
596   int i, threshold;
597
598   if (check_threshold)
599     threshold = SCROLL_THRESHOLD;
600   else
601     threshold = 0;
602   i = 0;
603   while (i < win_info->content.size () - threshold
604          && !is_displayed)
605     {
606       is_displayed
607         = win_info->content[i].line_or_addr.loa == LOA_LINE
608           && win_info->content[i].line_or_addr.u.line_no == line;
609       i++;
610     }
611
612   return is_displayed;
613 }
614
615
616 /* Answer whether a particular line number or address is displayed
617    in the current source window.  */
618 int
619 tui_addr_is_displayed (CORE_ADDR addr, 
620                        struct tui_source_window_base *win_info,
621                        int check_threshold)
622 {
623   int is_displayed = FALSE;
624   int i, threshold;
625
626   if (check_threshold)
627     threshold = SCROLL_THRESHOLD;
628   else
629     threshold = 0;
630   i = 0;
631   while (i < win_info->content.size () - threshold
632          && !is_displayed)
633     {
634       is_displayed
635         = win_info->content[i].line_or_addr.loa == LOA_ADDRESS
636           && win_info->content[i].line_or_addr.u.addr == addr;
637       i++;
638     }
639
640   return is_displayed;
641 }
642
643
644 /*****************************************
645 ** STATIC LOCAL FUNCTIONS               **
646 ******************************************/