Home | History | Annotate | Line # | Download | only in tui
tui-winsource.c revision 1.8
      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