xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/tui/tui-winsource.c (revision aef5eb5f59cdfe8314f1b5f78ac04eb144e44010)
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     tui_set_reverse_mode (win_info->generic.handle, true);
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     tui_set_reverse_mode (win_info->generic.handle, false);
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   if (exec_info->handle == NULL)
570     return;
571 
572   werase (exec_info->handle);
573   tui_refresh_win (exec_info);
574   for (cur_line = 1; (cur_line <= exec_info->content_size); cur_line++)
575     mvwaddstr (exec_info->handle,
576 	       cur_line,
577 	       0,
578 	       (char *) exec_info->content[cur_line - 1]
579 			  ->which_element.simple_string);
580   tui_refresh_win (exec_info);
581   exec_info->content_in_use = TRUE;
582 }
583 
584 
585 void
586 tui_erase_exec_info_content (struct tui_win_info *win_info)
587 {
588   struct tui_gen_win_info *exec_info
589     = win_info->detail.source_info.execution_info;
590 
591   if (exec_info->handle == NULL)
592     return;
593 
594   werase (exec_info->handle);
595   tui_refresh_win (exec_info);
596 }
597 
598 void
599 tui_clear_exec_info_content (struct tui_win_info *win_info)
600 {
601   win_info->detail.source_info.execution_info->content_in_use = FALSE;
602   tui_erase_exec_info_content (win_info);
603 
604   return;
605 }
606 
607 /* Function to update the execution info window.  */
608 void
609 tui_update_exec_info (struct tui_win_info *win_info)
610 {
611   tui_set_exec_info_content (win_info);
612   tui_show_exec_info_content (win_info);
613 }
614 
615 enum tui_status
616 tui_alloc_source_buffer (struct tui_win_info *win_info)
617 {
618   int i, line_width, max_lines;
619 
620   /* The window width/height includes the highlight box.  Determine actual
621      content dimensions, including string null-terminators.  */
622   max_lines = win_info->generic.height - 2;
623   line_width = win_info->generic.width - 2 + 1;
624 
625   /* Allocate the buffer for the source lines.  */
626   if (win_info->generic.content == NULL)
627     {
628       /* Allocate the content list.  */
629       win_info->generic.content = tui_alloc_content (max_lines, SRC_WIN);
630       for (i = 0; i < max_lines; i++)
631 	win_info->generic.content[i]->which_element.source.line
632 	  = (char *) xmalloc (line_width);
633     }
634 
635   return TUI_SUCCESS;
636 }
637 
638 
639 /* Answer whether a particular line number or address is displayed
640    in the current source window.  */
641 int
642 tui_line_is_displayed (int line,
643 		       struct tui_win_info *win_info,
644 		       int check_threshold)
645 {
646   int is_displayed = FALSE;
647   int i, threshold;
648 
649   if (check_threshold)
650     threshold = SCROLL_THRESHOLD;
651   else
652     threshold = 0;
653   i = 0;
654   while (i < win_info->generic.content_size - threshold
655 	 && !is_displayed)
656     {
657       is_displayed
658 	= win_info->generic.content[i]
659 	    ->which_element.source.line_or_addr.loa == LOA_LINE
660 	  && win_info->generic.content[i]
661 	       ->which_element.source.line_or_addr.u.line_no == line;
662       i++;
663     }
664 
665   return is_displayed;
666 }
667 
668 
669 /* Answer whether a particular line number or address is displayed
670    in the current source window.  */
671 int
672 tui_addr_is_displayed (CORE_ADDR addr,
673 		       struct tui_win_info *win_info,
674 		       int check_threshold)
675 {
676   int is_displayed = FALSE;
677   int i, threshold;
678 
679   if (check_threshold)
680     threshold = SCROLL_THRESHOLD;
681   else
682     threshold = 0;
683   i = 0;
684   while (i < win_info->generic.content_size - threshold
685 	 && !is_displayed)
686     {
687       is_displayed
688 	= win_info->generic.content[i]
689 	    ->which_element.source.line_or_addr.loa == LOA_ADDRESS
690 	  && win_info->generic.content[i]
691 	       ->which_element.source.line_or_addr.u.addr == addr;
692       i++;
693     }
694 
695   return is_displayed;
696 }
697 
698 
699 /*****************************************
700 ** STATIC LOCAL FUNCTIONS               **
701 ******************************************/
702