1/* TUI display source window. 2 3 Copyright (C) 1998-2023 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 <math.h> 24#include <ctype.h> 25#include "symtab.h" 26#include "frame.h" 27#include "breakpoint.h" 28#include "source.h" 29#include "objfiles.h" 30#include "filenames.h" 31#include "source-cache.h" 32 33#include "tui/tui.h" 34#include "tui/tui-data.h" 35#include "tui/tui-io.h" 36#include "tui/tui-stack.h" 37#include "tui/tui-win.h" 38#include "tui/tui-winsource.h" 39#include "tui/tui-source.h" 40#include "tui/tui-location.h" 41#include "gdb_curses.h" 42 43/* Function to display source in the source window. */ 44bool 45tui_source_window::set_contents (struct gdbarch *arch, 46 const struct symtab_and_line &sal) 47{ 48 struct symtab *s = sal.symtab; 49 int line_no = sal.line; 50 51 if (s == NULL) 52 return false; 53 54 /* Take hilite (window border) into account, when 55 calculating the number of lines. */ 56 int nlines = height - 2; 57 58 std::string srclines; 59 const std::vector<off_t> *offsets; 60 if (!g_source_cache.get_source_lines (s, line_no, line_no + nlines, 61 &srclines) 62 || !g_source_cache.get_line_charpos (s, &offsets)) 63 return false; 64 65 int cur_line_no, cur_line; 66 const char *s_filename = symtab_to_filename_for_display (s); 67 68 title = s_filename; 69 70 m_fullname = make_unique_xstrdup (symtab_to_fullname (s)); 71 72 cur_line = 0; 73 m_gdbarch = s->compunit ()->objfile ()->arch (); 74 m_start_line_or_addr.loa = LOA_LINE; 75 cur_line_no = m_start_line_or_addr.u.line_no = line_no; 76 77 m_digits = 7; 78 if (compact_source) 79 { 80 /* Solaris 11+gcc 5.5 has ambiguous overloads of log10, so we 81 cast to double to get the right one. */ 82 double l = log10 ((double) offsets->size ()); 83 m_digits = 1 + (int) l; 84 } 85 86 m_max_length = -1; 87 const char *iter = srclines.c_str (); 88 m_content.resize (nlines); 89 while (cur_line < nlines) 90 { 91 struct tui_source_element *element = &m_content[cur_line]; 92 93 std::string text; 94 if (*iter != '\0') 95 { 96 int line_len; 97 text = tui_copy_source_line (&iter, &line_len); 98 m_max_length = std::max (m_max_length, line_len); 99 } 100 101 /* Set whether element is the execution point 102 and whether there is a break point on it. */ 103 element->line_or_addr.loa = LOA_LINE; 104 element->line_or_addr.u.line_no = cur_line_no; 105 element->is_exec_point 106 = (filename_cmp (tui_location.full_name ().c_str (), 107 symtab_to_fullname (s)) == 0 108 && cur_line_no == tui_location.line_no ()); 109 110 m_content[cur_line].line = std::move (text); 111 112 cur_line++; 113 cur_line_no++; 114 } 115 116 return true; 117} 118 119 120/* Answer whether the source is currently displayed in the source 121 window. */ 122bool 123tui_source_window::showing_source_p (const char *fullname) const 124{ 125 return (!m_content.empty () 126 && (filename_cmp (tui_location.full_name ().c_str (), 127 fullname) == 0)); 128} 129 130 131/* Scroll the source forward or backward vertically. */ 132void 133tui_source_window::do_scroll_vertical (int num_to_scroll) 134{ 135 if (!m_content.empty ()) 136 { 137 struct symtab *s; 138 struct symtab_and_line cursal = get_current_source_symtab_and_line (); 139 struct gdbarch *arch = m_gdbarch; 140 141 if (cursal.symtab == NULL) 142 { 143 frame_info_ptr fi = get_selected_frame (NULL); 144 s = find_pc_line_symtab (get_frame_pc (fi)); 145 arch = get_frame_arch (fi); 146 } 147 else 148 s = cursal.symtab; 149 150 int line_no = m_start_line_or_addr.u.line_no + num_to_scroll; 151 const std::vector<off_t> *offsets; 152 if (g_source_cache.get_line_charpos (s, &offsets) 153 && line_no > offsets->size ()) 154 line_no = m_start_line_or_addr.u.line_no; 155 if (line_no <= 0) 156 line_no = 1; 157 158 cursal.line = line_no; 159 find_line_pc (cursal.symtab, cursal.line, &cursal.pc); 160 for (struct tui_source_window_base *win_info : tui_source_windows ()) 161 win_info->update_source_window_as_is (arch, cursal); 162 } 163} 164 165bool 166tui_source_window::location_matches_p (struct bp_location *loc, int line_no) 167{ 168 return (m_content[line_no].line_or_addr.loa == LOA_LINE 169 && m_content[line_no].line_or_addr.u.line_no == loc->line_number 170 && loc->symtab != NULL 171 && filename_cmp (m_fullname.get (), 172 symtab_to_fullname (loc->symtab)) == 0); 173} 174 175/* See tui-source.h. */ 176 177bool 178tui_source_window::line_is_displayed (int line) const 179{ 180 if (m_content.size () < SCROLL_THRESHOLD) 181 return false; 182 183 for (size_t i = 0; i < m_content.size () - SCROLL_THRESHOLD; ++i) 184 { 185 if (m_content[i].line_or_addr.loa == LOA_LINE 186 && m_content[i].line_or_addr.u.line_no == line) 187 return true; 188 } 189 190 return false; 191} 192 193void 194tui_source_window::maybe_update (frame_info_ptr fi, symtab_and_line sal) 195{ 196 int start_line = (sal.line - ((height - 2) / 2)) + 1; 197 if (start_line <= 0) 198 start_line = 1; 199 200 bool source_already_displayed = (sal.symtab != 0 201 && showing_source_p (m_fullname.get ())); 202 203 if (!(source_already_displayed && line_is_displayed (sal.line))) 204 { 205 sal.line = start_line; 206 update_source_window (get_frame_arch (fi), sal); 207 } 208 else 209 { 210 struct tui_line_or_address l; 211 212 l.loa = LOA_LINE; 213 l.u.line_no = sal.line; 214 set_is_exec_point_at (l); 215 } 216} 217 218void 219tui_source_window::display_start_addr (struct gdbarch **gdbarch_p, 220 CORE_ADDR *addr_p) 221{ 222 struct symtab_and_line cursal = get_current_source_symtab_and_line (); 223 224 *gdbarch_p = m_gdbarch; 225 find_line_pc (cursal.symtab, m_start_line_or_addr.u.line_no, addr_p); 226} 227 228/* See tui-winsource.h. */ 229 230void 231tui_source_window::show_line_number (int offset) const 232{ 233 int lineno = m_content[0].line_or_addr.u.line_no + offset; 234 char text[20]; 235 /* To completely overwrite the previous border when the source window height 236 is increased, both spaces after the line number have to be redrawn. */ 237 xsnprintf (text, sizeof (text), "%*d ", m_digits - 1, lineno); 238 waddstr (handle.get (), text); 239} 240