a85269657cf15c51e6923b112696b74e619f2eff
[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
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_source_window_base *win_info, 
87                                 struct gdbarch *gdbarch,
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->type == SRC_WIN)
95     ret = tui_set_source_content (win_info, s, line_or_addr.u.line_no,
96                                   noerror);
97   else
98     ret = tui_set_disassem_content (win_info, gdbarch, line_or_addr.u.addr);
99
100   if (ret == TUI_FAILURE)
101     tui_clear_source_content (win_info);
102   else
103     {
104       tui_update_breakpoint_info (win_info, nullptr, false);
105       win_info->show_source_content ();
106       win_info->update_exec_info ();
107       if (win_info->type == SRC_WIN)
108         {
109           symtab_and_line sal;
110
111           sal.line = line_or_addr.u.line_no +
112             (win_info->content.size () - 2);
113           sal.symtab = s;
114           sal.pspace = SYMTAB_PSPACE (s);
115           set_current_source_symtab_and_line (sal);
116           /* If the focus was in the asm win, put it in the src win if
117              we don't have a split layout.  */
118           if (tui_win_with_focus () == TUI_DISASM_WIN
119               && tui_current_layout () != SRC_DISASSEM_COMMAND)
120             tui_set_win_focus_to (win_info);
121         }
122     }
123 }
124
125
126 /* Function to ensure that the source and/or disassemly windows
127    reflect the input address.  */
128 void
129 tui_update_source_windows_with_addr (struct gdbarch *gdbarch, CORE_ADDR addr)
130 {
131   if (addr != 0)
132     {
133       struct symtab_and_line sal;
134       struct tui_line_or_address l;
135       
136       switch (tui_current_layout ())
137         {
138         case DISASSEM_COMMAND:
139         case DISASSEM_DATA_COMMAND:
140           tui_show_disassem (gdbarch, addr);
141           break;
142         case SRC_DISASSEM_COMMAND:
143           tui_show_disassem_and_update_source (gdbarch, addr);
144           break;
145         default:
146           sal = find_pc_line (addr, 0);
147           l.loa = LOA_LINE;
148           l.u.line_no = sal.line;
149           tui_show_symtab_source (TUI_SRC_WIN, gdbarch, sal.symtab, l, FALSE);
150           break;
151         }
152     }
153   else
154     {
155       for (struct tui_source_window_base *win_info : tui_source_windows ())
156         tui_clear_source_content (win_info);
157     }
158 }
159
160 /* Function to ensure that the source and/or disassemly windows
161    reflect the input address.  */
162 void
163 tui_update_source_windows_with_line (struct symtab *s, int line)
164 {
165   struct gdbarch *gdbarch;
166   CORE_ADDR pc;
167   struct tui_line_or_address l;
168
169   if (!s)
170     return;
171
172   gdbarch = get_objfile_arch (SYMTAB_OBJFILE (s));
173
174   switch (tui_current_layout ())
175     {
176     case DISASSEM_COMMAND:
177     case DISASSEM_DATA_COMMAND:
178       find_line_pc (s, line, &pc);
179       tui_update_source_windows_with_addr (gdbarch, pc);
180       break;
181     default:
182       l.loa = LOA_LINE;
183       l.u.line_no = line;
184       tui_show_symtab_source (TUI_SRC_WIN, gdbarch, s, l, FALSE);
185       if (tui_current_layout () == SRC_DISASSEM_COMMAND)
186         {
187           find_line_pc (s, line, &pc);
188           tui_show_disassem (gdbarch, pc);
189         }
190       break;
191     }
192 }
193
194 void
195 tui_clear_source_content (struct tui_source_window_base *win_info)
196 {
197   if (win_info != NULL)
198     {
199       int i;
200
201       tui_erase_source_content (win_info);
202       for (i = 0; i < win_info->content.size (); i++)
203         {
204           struct tui_source_element *element = &win_info->content[i];
205
206           element->break_mode = 0;
207           element->is_exec_point = false;
208         }
209     }
210 }
211
212
213 void
214 tui_erase_source_content (struct tui_source_window_base *win_info)
215 {
216   int x_pos;
217   int half_width = (win_info->width - 2) / 2;
218
219   if (win_info->handle != NULL)
220     {
221       werase (win_info->handle);
222       win_info->check_and_display_highlight_if_needed ();
223
224       const char *no_src_str;
225
226       if (win_info->type == SRC_WIN)
227         no_src_str = NO_SRC_STRING;
228       else
229         no_src_str = NO_DISASSEM_STRING;
230       if (strlen (no_src_str) >= half_width)
231         x_pos = 1;
232       else
233         x_pos = half_width - strlen (no_src_str);
234       mvwaddstr (win_info->handle,
235                  (win_info->height / 2),
236                  x_pos,
237                  (char *) no_src_str);
238
239       win_info->content.clear ();
240       win_info->refresh_window ();
241
242       struct tui_gen_win_info *exec_info = win_info->execution_info;
243
244       werase (exec_info->handle);
245       exec_info->refresh_window ();
246     }
247 }
248
249
250 /* Redraw the complete line of a source or disassembly window.  */
251 static void
252 tui_show_source_line (struct tui_source_window_base *win_info, int lineno)
253 {
254   struct tui_source_element *line;
255   int x;
256
257   line = &win_info->content[lineno - 1];
258   if (line->is_exec_point)
259     tui_set_reverse_mode (win_info->handle, true);
260
261   wmove (win_info->handle, lineno, 1);
262   tui_puts (line->line,
263             win_info->handle);
264   if (line->is_exec_point)
265     tui_set_reverse_mode (win_info->handle, false);
266
267   /* Clear to end of line but stop before the border.  */
268   x = getcurx (win_info->handle);
269   while (x + 1 < win_info->width)
270     {
271       waddch (win_info->handle, ' ');
272       x = getcurx (win_info->handle);
273     }
274 }
275
276 void
277 tui_source_window_base::show_source_content ()
278 {
279   if (!content.empty ())
280     {
281       int lineno;
282
283       for (lineno = 1; lineno <= content.size (); lineno++)
284         tui_show_source_line (this, lineno);
285     }
286   else
287     tui_erase_source_content (this);
288
289   check_and_display_highlight_if_needed ();
290   refresh_window ();
291 }
292
293 /* See tui-data.h.  */
294
295 void
296 tui_source_window_base::clear_detail ()
297 {
298   gdbarch = NULL;
299   start_line_or_addr.loa = LOA_ADDRESS;
300   start_line_or_addr.u.addr = 0;
301   horizontal_offset = 0;
302 }
303
304 tui_source_window_base::tui_source_window_base (enum tui_win_type type)
305   : tui_win_info (type),
306     execution_info (new tui_exec_info_window ())
307 {
308   gdb_assert (type == SRC_WIN || type == DISASSEM_WIN);
309   start_line_or_addr.loa = LOA_ADDRESS;
310   start_line_or_addr.u.addr = 0;
311 }
312
313
314 tui_source_window_base::~tui_source_window_base ()
315 {
316   xfree (fullname);
317   delete execution_info;
318 }  
319
320 void
321 tui_source_window_base::reset (int height, int width,
322                                int origin_x, int origin_y)
323 {
324   tui_gen_win_info::reset (height, width - 3,
325                            origin_x + 3, origin_y);
326   execution_info->reset (height, 3, origin_x, origin_y);
327 }
328
329 /* See tui-data.h.  */
330
331 void
332 tui_source_window_base::refresh_all ()
333 {
334   show_source_content ();
335   check_and_display_highlight_if_needed ();
336   update_exec_info ();
337 }
338
339 /* See tui-data.h.  */
340
341 void
342 tui_source_window_base::update_tab_width ()
343 {
344   /* We don't really change the height of any windows, but
345      calling these 2 functions causes a complete regeneration
346      and redisplay of the window's contents, which will take
347      the new tab width into account.  */
348   make_invisible_and_set_new_height (height);
349   make_visible_with_new_height ();
350 }
351
352 /* See tui-data.h.  */
353
354 void
355 tui_source_window_base::set_new_height (int height)
356 {
357   execution_info->make_visible (false);
358   execution_info->height = height;
359   execution_info->origin.y = origin.y;
360   if (height > 1)
361     execution_info->viewport_height = height - 1;
362   else
363     execution_info->viewport_height = height;
364   execution_info->viewport_height--;
365
366   if (m_has_locator)
367     {
368       tui_locator_window *gen_win_info = tui_locator_win_info_ptr ();
369       gen_win_info->make_visible (false);
370       gen_win_info->origin.y = origin.y + height;
371     }
372 }
373
374 /* See tui-data.h.  */
375
376 void
377 tui_source_window_base::do_make_visible_with_new_height ()
378 {
379   execution_info->make_visible (true);
380   if (!content.empty ())
381     {
382       struct tui_line_or_address line_or_addr;
383       struct symtab_and_line cursal
384         = get_current_source_symtab_and_line ();
385
386       line_or_addr = start_line_or_addr;
387       tui_update_source_window (this, gdbarch,
388                                 cursal.symtab, line_or_addr, TRUE);
389     }
390   else if (deprecated_safe_get_selected_frame () != NULL)
391     {
392       struct tui_line_or_address line;
393       struct symtab_and_line cursal
394         = get_current_source_symtab_and_line ();
395       struct frame_info *frame = deprecated_safe_get_selected_frame ();
396       struct gdbarch *gdbarch = get_frame_arch (frame);
397
398       struct symtab *s = find_pc_line_symtab (get_frame_pc (frame));
399       if (type == SRC_WIN)
400         {
401           line.loa = LOA_LINE;
402           line.u.line_no = cursal.line;
403         }
404       else
405         {
406           line.loa = LOA_ADDRESS;
407           find_line_pc (s, cursal.line, &line.u.addr);
408         }
409       tui_update_source_window (this, gdbarch, s, line, TRUE);
410     }
411   if (m_has_locator)
412     {
413       tui_locator_win_info_ptr ()->make_visible (true);
414       tui_show_locator_content ();
415     }
416 }
417
418 /* See tui-data.h.  */
419
420 void
421 tui_source_window_base::make_visible (bool visible)
422 {
423   execution_info->make_visible (visible);
424   tui_win_info::make_visible (visible);
425 }
426
427 /* See tui-data.h.  */
428
429 void
430 tui_source_window_base::refresh_window ()
431 {
432   execution_info->refresh_window ();
433   tui_win_info::refresh_window ();
434 }
435
436 /* See tui-data.h.  */
437
438 void
439 tui_source_window_base::refill ()
440 {
441   symtab *s = nullptr;
442
443   if (type == SRC_WIN)
444     {
445       symtab_and_line cursal = get_current_source_symtab_and_line ();
446       s = (cursal.symtab == NULL
447            ? find_pc_line_symtab (get_frame_pc (get_selected_frame (NULL)))
448            : cursal.symtab);
449     }
450
451   tui_update_source_window_as_is (this, gdbarch, s,
452                                   content[0].line_or_addr,
453                                   FALSE);
454 }
455
456 /* Scroll the source forward or backward horizontally.  */
457
458 void
459 tui_source_window_base::do_scroll_horizontal (int num_to_scroll)
460 {
461   if (!content.empty ())
462     {
463       int offset = horizontal_offset + num_to_scroll;
464       if (offset < 0)
465         offset = 0;
466       horizontal_offset = offset;
467       refill ();
468     }
469 }
470
471
472 /* Set or clear the is_exec_point flag in the line whose line is
473    line_no.  */
474
475 void
476 tui_source_window_base::set_is_exec_point_at (struct tui_line_or_address l)
477 {
478   bool changed = false;
479   int i;
480
481   i = 0;
482   while (i < content.size ())
483     {
484       bool new_state;
485       struct tui_line_or_address content_loa =
486         content[i].line_or_addr;
487
488       gdb_assert (l.loa == LOA_ADDRESS || l.loa == LOA_LINE);
489       gdb_assert (content_loa.loa == LOA_LINE
490                   || content_loa.loa == LOA_ADDRESS);
491       if (content_loa.loa == l.loa
492           && ((l.loa == LOA_LINE && content_loa.u.line_no == l.u.line_no)
493               || (l.loa == LOA_ADDRESS && content_loa.u.addr == l.u.addr)))
494         new_state = true;
495       else
496         new_state = false;
497       if (new_state != content[i].is_exec_point)
498         {
499           changed = true;
500           content[i].is_exec_point = new_state;
501           tui_show_source_line (this, i + 1);
502         }
503       i++;
504     }
505   if (changed)
506     refill ();
507 }
508
509 /* See tui-winsource.h.  */
510
511 void
512 tui_update_all_breakpoint_info (struct breakpoint *being_deleted)
513 {
514   for (tui_source_window_base *win : tui_source_windows ())
515     {
516       if (tui_update_breakpoint_info (win, being_deleted, false))
517         {
518           win->update_exec_info ();
519         }
520     }
521 }
522
523
524 /* Scan the source window and the breakpoints to update the break_mode
525    information for each line.
526
527    Returns true if something changed and the execution window must be
528    refreshed.  */
529
530 bool
531 tui_update_breakpoint_info (struct tui_source_window_base *win,
532                             struct breakpoint *being_deleted,
533                             bool current_only)
534 {
535   int i;
536   bool need_refresh = false;
537
538   for (i = 0; i < win->content.size (); i++)
539     {
540       struct breakpoint *bp;
541       extern struct breakpoint *breakpoint_chain;
542       struct tui_source_element *line;
543
544       line = &win->content[i];
545       if (current_only && !line->is_exec_point)
546          continue;
547
548       /* Scan each breakpoint to see if the current line has something to
549          do with it.  Identify enable/disabled breakpoints as well as
550          those that we already hit.  */
551       tui_bp_flags mode = 0;
552       for (bp = breakpoint_chain;
553            bp != NULL;
554            bp = bp->next)
555         {
556           struct bp_location *loc;
557
558           gdb_assert (line->line_or_addr.loa == LOA_LINE
559                       || line->line_or_addr.loa == LOA_ADDRESS);
560
561           if (bp == being_deleted)
562             continue;
563
564           for (loc = bp->loc; loc != NULL; loc = loc->next)
565             {
566               if (win->location_matches_p (loc, i))
567                 {
568                   if (bp->enable_state == bp_disabled)
569                     mode |= TUI_BP_DISABLED;
570                   else
571                     mode |= TUI_BP_ENABLED;
572                   if (bp->hit_count)
573                     mode |= TUI_BP_HIT;
574                   if (bp->loc->cond)
575                     mode |= TUI_BP_CONDITIONAL;
576                   if (bp->type == bp_hardware_breakpoint)
577                     mode |= TUI_BP_HARDWARE;
578                 }
579             }
580         }
581       if (line->break_mode != mode)
582         {
583           line->break_mode = mode;
584           need_refresh = true;
585         }
586     }
587   return need_refresh;
588 }
589
590 /* Function to initialize the content of the execution info window,
591    based upon the input window which is either the source or
592    disassembly window.  */
593 void
594 tui_source_window_base::update_exec_info ()
595 {
596   werase (execution_info->handle);
597   tui_update_breakpoint_info (this, nullptr, true);
598   for (int i = 0; i < content.size (); i++)
599     {
600       struct tui_source_element *src_element = &content[i];
601       char element[TUI_EXECINFO_SIZE] = "   ";
602
603       /* Now update the exec info content based upon the state
604          of each line as indicated by the source content.  */
605       tui_bp_flags mode = src_element->break_mode;
606       if (mode & TUI_BP_HIT)
607         element[TUI_BP_HIT_POS] = (mode & TUI_BP_HARDWARE) ? 'H' : 'B';
608       else if (mode & (TUI_BP_ENABLED | TUI_BP_DISABLED))
609         element[TUI_BP_HIT_POS] = (mode & TUI_BP_HARDWARE) ? 'h' : 'b';
610
611       if (mode & TUI_BP_ENABLED)
612         element[TUI_BP_BREAK_POS] = '+';
613       else if (mode & TUI_BP_DISABLED)
614         element[TUI_BP_BREAK_POS] = '-';
615
616       if (src_element->is_exec_point)
617         element[TUI_EXEC_POS] = '>';
618
619       mvwaddstr (execution_info->handle, i + 1, 0, element);
620     }
621   execution_info->refresh_window ();
622 }
623
624
625 void
626 tui_alloc_source_buffer (struct tui_source_window_base *win_info)
627 {
628   int i, line_width, max_lines;
629
630   /* The window width/height includes the highlight box.  Determine actual
631      content dimensions, including string null-terminators.  */
632   max_lines = win_info->height - 2;
633   line_width = win_info->width - 2 + 1;
634
635   /* Allocate the buffer for the source lines.  */
636   win_info->content.resize (max_lines);
637   for (i = 0; i < max_lines; i++)
638     {
639       if (win_info->content[i].line == nullptr)
640         win_info->content[i].line = (char *) xmalloc (line_width);
641     }
642 }