1 1.1 christos /* TUI display source/assembly window. 2 1.1 christos 3 1.11 christos Copyright (C) 1998-2024 Free Software Foundation, Inc. 4 1.1 christos 5 1.1 christos Contributed by Hewlett-Packard Company. 6 1.1 christos 7 1.1 christos This file is part of GDB. 8 1.1 christos 9 1.1 christos This program is free software; you can redistribute it and/or modify 10 1.1 christos it under the terms of the GNU General Public License as published by 11 1.1 christos the Free Software Foundation; either version 3 of the License, or 12 1.1 christos (at your option) any later version. 13 1.1 christos 14 1.1 christos This program is distributed in the hope that it will be useful, 15 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of 16 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 1.1 christos GNU General Public License for more details. 18 1.1 christos 19 1.1 christos You should have received a copy of the GNU General Public License 20 1.1 christos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 21 1.1 christos 22 1.12 christos #include "observable.h" 23 1.1 christos #include "symtab.h" 24 1.1 christos #include "frame.h" 25 1.1 christos #include "breakpoint.h" 26 1.1 christos #include "value.h" 27 1.1 christos #include "source.h" 28 1.1 christos #include "objfiles.h" 29 1.11 christos #include "gdbsupport/gdb-safe-ctype.h" 30 1.1 christos 31 1.1 christos #include "tui/tui.h" 32 1.1 christos #include "tui/tui-data.h" 33 1.8 christos #include "tui/tui-io.h" 34 1.11 christos #include "tui/tui-status.h" 35 1.1 christos #include "tui/tui-win.h" 36 1.1 christos #include "tui/tui-winsource.h" 37 1.1 christos #include "tui/tui-source.h" 38 1.1 christos #include "tui/tui-disasm.h" 39 1.10 christos #include "tui/tui-location.h" 40 1.1 christos #include "gdb_curses.h" 41 1.1 christos 42 1.11 christos /* ncurses returns -1, but BSD segfaults; the code assumes ncurses */ 43 1.11 christos #define tui_getmaxx(w) ((w) ? getmaxx (w) : -1) 44 1.11 christos #define tui_getmaxy(w) ((w) ? getmaxy (w) : -1) 45 1.11 christos 46 1.1 christos /* Function to display the "main" routine. */ 47 1.1 christos void 48 1.9 christos tui_display_main () 49 1.1 christos { 50 1.9 christos auto adapter = tui_source_windows (); 51 1.9 christos if (adapter.begin () != adapter.end ()) 52 1.1 christos { 53 1.1 christos struct gdbarch *gdbarch; 54 1.1 christos CORE_ADDR addr; 55 1.1 christos 56 1.1 christos tui_get_begin_asm_address (&gdbarch, &addr); 57 1.1 christos if (addr != (CORE_ADDR) 0) 58 1.1 christos { 59 1.3 christos struct symtab *s; 60 1.1 christos 61 1.1 christos tui_update_source_windows_with_addr (gdbarch, addr); 62 1.3 christos s = find_pc_line_symtab (addr); 63 1.10 christos tui_location.set_location (s); 64 1.1 christos } 65 1.1 christos } 66 1.1 christos } 67 1.1 christos 68 1.9 christos /* See tui-winsource.h. */ 69 1.1 christos 70 1.9 christos std::string 71 1.10 christos tui_copy_source_line (const char **ptr, int *length) 72 1.9 christos { 73 1.9 christos const char *lineptr = *ptr; 74 1.9 christos 75 1.9 christos /* Init the line with the line number. */ 76 1.9 christos std::string result; 77 1.9 christos 78 1.9 christos int column = 0; 79 1.9 christos char c; 80 1.9 christos do 81 1.9 christos { 82 1.9 christos int skip_bytes; 83 1.9 christos 84 1.9 christos c = *lineptr; 85 1.9 christos if (c == '\033' && skip_ansi_escape (lineptr, &skip_bytes)) 86 1.9 christos { 87 1.9 christos /* We always have to preserve escapes. */ 88 1.9 christos result.append (lineptr, lineptr + skip_bytes); 89 1.9 christos lineptr += skip_bytes; 90 1.9 christos continue; 91 1.9 christos } 92 1.9 christos if (c == '\0') 93 1.9 christos break; 94 1.9 christos 95 1.9 christos ++lineptr; 96 1.9 christos ++column; 97 1.9 christos 98 1.9 christos auto process_tab = [&] () 99 1.9 christos { 100 1.9 christos int max_tab_len = tui_tab_width; 101 1.9 christos 102 1.9 christos --column; 103 1.9 christos for (int j = column % max_tab_len; 104 1.10 christos j < max_tab_len; 105 1.9 christos column++, j++) 106 1.10 christos result.push_back (' '); 107 1.9 christos }; 108 1.9 christos 109 1.9 christos if (c == '\n' || c == '\r' || c == '\0') 110 1.9 christos { 111 1.9 christos /* Nothing. */ 112 1.9 christos } 113 1.10 christos else if (c == '\t') 114 1.10 christos process_tab (); 115 1.10 christos else if (ISCNTRL (c)) 116 1.9 christos { 117 1.9 christos result.push_back ('^'); 118 1.9 christos result.push_back (c + 0100); 119 1.10 christos ++column; 120 1.9 christos } 121 1.9 christos else if (c == 0177) 122 1.9 christos { 123 1.9 christos result.push_back ('^'); 124 1.9 christos result.push_back ('?'); 125 1.10 christos ++column; 126 1.9 christos } 127 1.9 christos else 128 1.9 christos result.push_back (c); 129 1.9 christos } 130 1.9 christos while (c != '\0' && c != '\n' && c != '\r'); 131 1.9 christos 132 1.9 christos if (c == '\r' && *lineptr == '\n') 133 1.9 christos ++lineptr; 134 1.9 christos *ptr = lineptr; 135 1.9 christos 136 1.10 christos if (length != nullptr) 137 1.10 christos *length = column; 138 1.10 christos 139 1.9 christos return result; 140 1.9 christos } 141 1.9 christos 142 1.9 christos void 143 1.9 christos tui_source_window_base::style_changed () 144 1.9 christos { 145 1.9 christos if (tui_active && is_visible ()) 146 1.9 christos refill (); 147 1.9 christos } 148 1.1 christos 149 1.1 christos /* Function to display source in the source window. This function 150 1.1 christos initializes the horizontal scroll to 0. */ 151 1.1 christos void 152 1.9 christos tui_source_window_base::update_source_window 153 1.9 christos (struct gdbarch *gdbarch, 154 1.9 christos const struct symtab_and_line &sal) 155 1.1 christos { 156 1.9 christos m_horizontal_offset = 0; 157 1.9 christos update_source_window_as_is (gdbarch, sal); 158 1.1 christos } 159 1.1 christos 160 1.1 christos 161 1.1 christos /* Function to display source in the source/asm window. This function 162 1.1 christos shows the source as specified by the horizontal offset. */ 163 1.1 christos void 164 1.9 christos tui_source_window_base::update_source_window_as_is 165 1.9 christos (struct gdbarch *gdbarch, 166 1.9 christos const struct symtab_and_line &sal) 167 1.1 christos { 168 1.9 christos bool ret = set_contents (gdbarch, sal); 169 1.1 christos 170 1.9 christos if (!ret) 171 1.9 christos erase_source_content (); 172 1.1 christos else 173 1.1 christos { 174 1.11 christos validate_scroll_offsets (); 175 1.9 christos update_breakpoint_info (nullptr, false); 176 1.11 christos update_exec_info (false); 177 1.9 christos show_source_content (); 178 1.1 christos } 179 1.1 christos } 180 1.1 christos 181 1.1 christos 182 1.11 christos /* See tui-winsource.h. */ 183 1.11 christos void 184 1.11 christos tui_source_window_base::update_source_window_with_addr (struct gdbarch *gdbarch, 185 1.11 christos CORE_ADDR addr) 186 1.11 christos { 187 1.11 christos struct symtab_and_line sal {}; 188 1.11 christos if (addr != 0) 189 1.11 christos sal = find_pc_line (addr, 0); 190 1.11 christos 191 1.11 christos update_source_window (gdbarch, sal); 192 1.11 christos } 193 1.11 christos 194 1.11 christos /* Function to ensure that the source and/or disassembly windows 195 1.1 christos reflect the input address. */ 196 1.1 christos void 197 1.1 christos tui_update_source_windows_with_addr (struct gdbarch *gdbarch, CORE_ADDR addr) 198 1.1 christos { 199 1.9 christos struct symtab_and_line sal {}; 200 1.1 christos if (addr != 0) 201 1.9 christos sal = find_pc_line (addr, 0); 202 1.1 christos 203 1.9 christos for (struct tui_source_window_base *win_info : tui_source_windows ()) 204 1.9 christos win_info->update_source_window (gdbarch, sal); 205 1.1 christos } 206 1.1 christos 207 1.9 christos /* Function to ensure that the source and/or disassembly windows 208 1.9 christos reflect the symtab and line. */ 209 1.1 christos void 210 1.9 christos tui_update_source_windows_with_line (struct symtab_and_line sal) 211 1.1 christos { 212 1.9 christos struct gdbarch *gdbarch = nullptr; 213 1.9 christos if (sal.symtab != nullptr) 214 1.9 christos { 215 1.9 christos find_line_pc (sal.symtab, sal.line, &sal.pc); 216 1.10 christos gdbarch = sal.symtab->compunit ()->objfile ()->arch (); 217 1.1 christos } 218 1.1 christos 219 1.9 christos for (struct tui_source_window_base *win_info : tui_source_windows ()) 220 1.9 christos win_info->update_source_window (gdbarch, sal); 221 1.1 christos } 222 1.1 christos 223 1.1 christos void 224 1.9 christos tui_source_window_base::do_erase_source_content (const char *str) 225 1.1 christos { 226 1.11 christos m_content.clear (); 227 1.11 christos if (handle != nullptr) 228 1.11 christos center_string (str); 229 1.11 christos } 230 1.11 christos 231 1.11 christos /* See tui-winsource.h. */ 232 1.9 christos 233 1.11 christos void 234 1.11 christos tui_source_window_base::puts_to_pad_with_skip (const char *string, int skip) 235 1.11 christos { 236 1.11 christos gdb_assert (m_pad.get () != nullptr); 237 1.11 christos WINDOW *w = m_pad.get (); 238 1.11 christos 239 1.11 christos while (skip > 0) 240 1.1 christos { 241 1.11 christos const char *next = strpbrk (string, "\033"); 242 1.11 christos 243 1.11 christos /* Print the plain text prefix. */ 244 1.11 christos size_t n_chars = next == nullptr ? strlen (string) : next - string; 245 1.11 christos if (n_chars > 0) 246 1.11 christos { 247 1.11 christos if (skip > 0) 248 1.11 christos { 249 1.11 christos if (skip < n_chars) 250 1.11 christos { 251 1.11 christos string += skip; 252 1.11 christos n_chars -= skip; 253 1.11 christos skip = 0; 254 1.11 christos } 255 1.11 christos else 256 1.11 christos { 257 1.11 christos skip -= n_chars; 258 1.11 christos string += n_chars; 259 1.11 christos n_chars = 0; 260 1.11 christos } 261 1.11 christos } 262 1.11 christos 263 1.11 christos if (n_chars > 0) 264 1.11 christos { 265 1.11 christos std::string copy (string, n_chars); 266 1.11 christos tui_puts (copy.c_str (), w); 267 1.11 christos } 268 1.11 christos } 269 1.11 christos 270 1.11 christos /* We finished. */ 271 1.11 christos if (next == nullptr) 272 1.11 christos break; 273 1.11 christos 274 1.11 christos gdb_assert (*next == '\033'); 275 1.1 christos 276 1.11 christos int n_read; 277 1.11 christos if (skip_ansi_escape (next, &n_read)) 278 1.11 christos { 279 1.11 christos std::string copy (next, n_read); 280 1.11 christos tui_puts (copy.c_str (), w); 281 1.11 christos next += n_read; 282 1.11 christos } 283 1.9 christos else 284 1.11 christos gdb_assert_not_reached ("unhandled escape"); 285 1.1 christos 286 1.11 christos string = next; 287 1.1 christos } 288 1.11 christos 289 1.11 christos if (*string != '\0') 290 1.11 christos tui_puts (string, w); 291 1.1 christos } 292 1.1 christos 293 1.9 christos /* Redraw the complete line of a source or disassembly window. */ 294 1.1 christos void 295 1.9 christos tui_source_window_base::show_source_line (int lineno) 296 1.1 christos { 297 1.9 christos struct tui_source_element *line; 298 1.9 christos 299 1.10 christos line = &m_content[lineno]; 300 1.9 christos if (line->is_exec_point) 301 1.10 christos tui_set_reverse_mode (m_pad.get (), true); 302 1.9 christos 303 1.10 christos wmove (m_pad.get (), lineno, 0); 304 1.11 christos puts_to_pad_with_skip (line->line.c_str (), m_pad_offset); 305 1.11 christos 306 1.9 christos if (line->is_exec_point) 307 1.10 christos tui_set_reverse_mode (m_pad.get (), false); 308 1.10 christos } 309 1.10 christos 310 1.10 christos /* See tui-winsource.h. */ 311 1.1 christos 312 1.10 christos void 313 1.10 christos tui_source_window_base::refresh_window () 314 1.10 christos { 315 1.11 christos TUI_SCOPED_DEBUG_START_END ("window `%s`", name ()); 316 1.11 christos 317 1.10 christos /* tui_win_info::refresh_window would draw the empty background window to 318 1.10 christos the screen, potentially creating a flicker. */ 319 1.10 christos wnoutrefresh (handle.get ()); 320 1.10 christos 321 1.12 christos if (m_content.empty ()) 322 1.12 christos return; 323 1.12 christos 324 1.11 christos int pad_width = tui_getmaxx (m_pad.get ()); 325 1.11 christos int left_margin = this->left_margin (); 326 1.11 christos int view_width = this->view_width (); 327 1.11 christos int content_width = m_max_length; 328 1.11 christos int pad_x = m_horizontal_offset - m_pad_offset; 329 1.11 christos 330 1.11 christos tui_debug_printf ("pad_width = %d, left_margin = %d, view_width = %d", 331 1.11 christos pad_width, left_margin, view_width); 332 1.11 christos tui_debug_printf ("content_width = %d, pad_x = %d, m_horizontal_offset = %d", 333 1.11 christos content_width, pad_x, m_horizontal_offset); 334 1.11 christos tui_debug_printf ("m_pad_offset = %d", m_pad_offset); 335 1.11 christos 336 1.11 christos gdb_assert (m_pad_offset >= 0); 337 1.11 christos gdb_assert (m_horizontal_offset + view_width 338 1.11 christos <= std::max (content_width, view_width)); 339 1.11 christos gdb_assert (pad_x >= 0); 340 1.11 christos gdb_assert (m_horizontal_offset >= 0); 341 1.11 christos 342 1.11 christos /* This function can be called before the pad has been allocated, this 343 1.11 christos should only occur during the initial startup. In this case the first 344 1.11 christos condition in the following asserts will not be true, but the nullptr 345 1.11 christos check will. */ 346 1.11 christos gdb_assert (pad_width > 0 || m_pad.get () == nullptr); 347 1.11 christos gdb_assert (pad_x + view_width <= pad_width || m_pad.get () == nullptr); 348 1.11 christos 349 1.11 christos int sminrow = y + box_width (); 350 1.11 christos int smincol = x + box_width () + left_margin; 351 1.11 christos int smaxrow = sminrow + m_content.size () - 1; 352 1.11 christos int smaxcol = smincol + view_width - 1; 353 1.11 christos if (m_pad.get ()) 354 1.12 christos pnoutrefresh (m_pad.get (), 0, pad_x, sminrow, smincol, smaxrow, smaxcol); 355 1.9 christos } 356 1.9 christos 357 1.9 christos void 358 1.9 christos tui_source_window_base::show_source_content () 359 1.9 christos { 360 1.11 christos TUI_SCOPED_DEBUG_START_END ("window `%s`", name ()); 361 1.11 christos 362 1.9 christos gdb_assert (!m_content.empty ()); 363 1.1 christos 364 1.11 christos /* The pad should be at least as wide as the window, but ideally, as wide 365 1.11 christos as the content, however, for some very wide content this might not be 366 1.11 christos possible. */ 367 1.11 christos int required_pad_width = std::max (m_max_length, width); 368 1.11 christos int required_pad_height = m_content.size (); 369 1.11 christos 370 1.11 christos /* If the required pad width is wider than the previously requested pad 371 1.11 christos width, then we might want to grow the pad. */ 372 1.11 christos if (required_pad_width > m_pad_requested_width 373 1.11 christos || required_pad_height > tui_getmaxy (m_pad.get ())) 374 1.11 christos { 375 1.11 christos /* The current pad width. */ 376 1.11 christos int pad_width = m_pad == nullptr ? 0 : tui_getmaxx (m_pad.get ()); 377 1.11 christos 378 1.11 christos gdb_assert (pad_width <= m_pad_requested_width); 379 1.11 christos 380 1.11 christos /* If the current pad width is smaller than the previously requested 381 1.11 christos pad width, then this means we previously failed to allocate a 382 1.11 christos bigger pad. There's no point asking again, so we'll just make so 383 1.11 christos with the pad we currently have. */ 384 1.11 christos if (pad_width == m_pad_requested_width 385 1.11 christos || required_pad_height > tui_getmaxy (m_pad.get ())) 386 1.11 christos { 387 1.11 christos pad_width = required_pad_width; 388 1.10 christos 389 1.11 christos do 390 1.11 christos { 391 1.11 christos /* Try to allocate a new pad. */ 392 1.11 christos m_pad.reset (newpad (required_pad_height, pad_width)); 393 1.10 christos 394 1.11 christos if (m_pad == nullptr) 395 1.11 christos { 396 1.11 christos int reduced_width = std::max (pad_width / 2, width); 397 1.11 christos if (reduced_width == pad_width) 398 1.11 christos error (_("failed to setup source window")); 399 1.11 christos pad_width = reduced_width; 400 1.11 christos } 401 1.11 christos } 402 1.11 christos while (m_pad == nullptr); 403 1.11 christos } 404 1.11 christos 405 1.11 christos m_pad_requested_width = required_pad_width; 406 1.11 christos tui_debug_printf ("requested width %d, allocated width %d", 407 1.11 christos required_pad_width, tui_getmaxx (m_pad.get ())); 408 1.11 christos } 409 1.11 christos 410 1.11 christos gdb_assert (m_pad != nullptr); 411 1.10 christos werase (m_pad.get ()); 412 1.10 christos for (int lineno = 0; lineno < m_content.size (); lineno++) 413 1.9 christos show_source_line (lineno); 414 1.1 christos 415 1.12 christos /* Calling check_and_display_highlight_if_needed will call 416 1.12 christos refresh_window. */ 417 1.12 christos check_and_display_highlight_if_needed (); 418 1.1 christos } 419 1.1 christos 420 1.9 christos tui_source_window_base::tui_source_window_base () 421 1.9 christos { 422 1.9 christos m_start_line_or_addr.loa = LOA_ADDRESS; 423 1.9 christos m_start_line_or_addr.u.addr = 0; 424 1.9 christos 425 1.10 christos gdb::observers::styling_changed.attach 426 1.9 christos (std::bind (&tui_source_window::style_changed, this), 427 1.10 christos m_observable, "tui-winsource"); 428 1.9 christos } 429 1.1 christos 430 1.9 christos tui_source_window_base::~tui_source_window_base () 431 1.1 christos { 432 1.10 christos gdb::observers::styling_changed.detach (m_observable); 433 1.9 christos } 434 1.1 christos 435 1.9 christos /* See tui-data.h. */ 436 1.1 christos 437 1.9 christos void 438 1.9 christos tui_source_window_base::update_tab_width () 439 1.9 christos { 440 1.9 christos werase (handle.get ()); 441 1.9 christos rerender (); 442 1.1 christos } 443 1.1 christos 444 1.1 christos void 445 1.9 christos tui_source_window_base::rerender () 446 1.1 christos { 447 1.11 christos TUI_SCOPED_DEBUG_START_END ("window `%s`", name ()); 448 1.11 christos 449 1.9 christos if (!m_content.empty ()) 450 1.1 christos { 451 1.12 christos symtab_and_line cursal 452 1.12 christos = get_current_source_symtab_and_line (current_program_space); 453 1.1 christos 454 1.9 christos if (m_start_line_or_addr.loa == LOA_LINE) 455 1.9 christos cursal.line = m_start_line_or_addr.u.line_no; 456 1.9 christos else 457 1.9 christos cursal.pc = m_start_line_or_addr.u.addr; 458 1.9 christos update_source_window (m_gdbarch, cursal); 459 1.9 christos } 460 1.9 christos else if (deprecated_safe_get_selected_frame () != NULL) 461 1.9 christos { 462 1.12 christos symtab_and_line cursal 463 1.12 christos = get_current_source_symtab_and_line (current_program_space); 464 1.10 christos frame_info_ptr frame = deprecated_safe_get_selected_frame (); 465 1.9 christos struct gdbarch *gdbarch = get_frame_arch (frame); 466 1.9 christos 467 1.9 christos struct symtab *s = find_pc_line_symtab (get_frame_pc (frame)); 468 1.12 christos if (this != tui_src_win ()) 469 1.9 christos find_line_pc (s, cursal.line, &cursal.pc); 470 1.11 christos 471 1.11 christos /* This centering code is copied from tui_source_window::maybe_update. 472 1.11 christos It would be nice to do centering more often, and do it in just one 473 1.11 christos location. But since this is a regression fix, handle this 474 1.11 christos conservatively for now. */ 475 1.11 christos int start_line = (cursal.line - ((height - box_size ()) / 2)) + 1; 476 1.11 christos if (start_line <= 0) 477 1.11 christos start_line = 1; 478 1.11 christos cursal.line = start_line; 479 1.11 christos 480 1.9 christos update_source_window (gdbarch, cursal); 481 1.1 christos } 482 1.1 christos else 483 1.11 christos { 484 1.11 christos CORE_ADDR addr; 485 1.11 christos struct gdbarch *gdbarch; 486 1.11 christos tui_get_begin_asm_address (&gdbarch, &addr); 487 1.11 christos if (addr == 0) 488 1.11 christos erase_source_content (); 489 1.11 christos else 490 1.11 christos update_source_window_with_addr (gdbarch, addr); 491 1.11 christos } 492 1.1 christos } 493 1.1 christos 494 1.9 christos /* See tui-data.h. */ 495 1.8 christos 496 1.8 christos void 497 1.9 christos tui_source_window_base::refill () 498 1.8 christos { 499 1.9 christos symtab_and_line sal {}; 500 1.8 christos 501 1.12 christos if (this == tui_src_win ()) 502 1.8 christos { 503 1.12 christos sal = get_current_source_symtab_and_line (current_program_space); 504 1.9 christos if (sal.symtab == NULL) 505 1.9 christos { 506 1.10 christos frame_info_ptr fi = deprecated_safe_get_selected_frame (); 507 1.9 christos if (fi != nullptr) 508 1.9 christos sal = find_pc_line (get_frame_pc (fi), 0); 509 1.9 christos } 510 1.8 christos } 511 1.8 christos 512 1.9 christos if (sal.pspace == nullptr) 513 1.9 christos sal.pspace = current_program_space; 514 1.9 christos 515 1.9 christos if (m_start_line_or_addr.loa == LOA_LINE) 516 1.9 christos sal.line = m_start_line_or_addr.u.line_no; 517 1.9 christos else 518 1.9 christos sal.pc = m_start_line_or_addr.u.addr; 519 1.9 christos 520 1.9 christos update_source_window_as_is (m_gdbarch, sal); 521 1.8 christos } 522 1.1 christos 523 1.11 christos /* See tui-winsource.h. */ 524 1.11 christos 525 1.11 christos bool 526 1.11 christos tui_source_window_base::validate_scroll_offsets () 527 1.11 christos { 528 1.11 christos TUI_SCOPED_DEBUG_START_END ("window `%s`", name ()); 529 1.11 christos 530 1.11 christos int original_pad_offset = m_pad_offset; 531 1.11 christos 532 1.11 christos if (m_horizontal_offset < 0) 533 1.11 christos m_horizontal_offset = 0; 534 1.11 christos 535 1.11 christos int content_width = m_max_length; 536 1.11 christos int pad_width = tui_getmaxx (m_pad.get ()); 537 1.11 christos int view_width = this->view_width (); 538 1.11 christos 539 1.11 christos tui_debug_printf ("pad_width = %d, view_width = %d, content_width = %d", 540 1.11 christos pad_width, view_width, content_width); 541 1.11 christos tui_debug_printf ("original_pad_offset = %d, m_horizontal_offset = %d", 542 1.11 christos original_pad_offset, m_horizontal_offset); 543 1.11 christos 544 1.11 christos if (m_horizontal_offset + view_width > content_width) 545 1.11 christos m_horizontal_offset = std::max (content_width - view_width, 0); 546 1.11 christos 547 1.11 christos if ((m_horizontal_offset + view_width) > (m_pad_offset + pad_width)) 548 1.11 christos { 549 1.11 christos m_pad_offset = std::min (m_horizontal_offset, content_width - pad_width); 550 1.11 christos m_pad_offset = std::max (m_pad_offset, 0); 551 1.11 christos } 552 1.11 christos else if (m_horizontal_offset < m_pad_offset) 553 1.11 christos m_pad_offset = std::max (m_horizontal_offset + view_width - pad_width, 0); 554 1.11 christos 555 1.11 christos gdb_assert (m_pad_offset >= 0); 556 1.11 christos return (original_pad_offset != m_pad_offset); 557 1.11 christos } 558 1.11 christos 559 1.1 christos /* Scroll the source forward or backward horizontally. */ 560 1.8 christos 561 1.1 christos void 562 1.9 christos tui_source_window_base::do_scroll_horizontal (int num_to_scroll) 563 1.1 christos { 564 1.9 christos if (!m_content.empty ()) 565 1.1 christos { 566 1.11 christos m_horizontal_offset += num_to_scroll; 567 1.11 christos 568 1.11 christos if (validate_scroll_offsets ()) 569 1.11 christos show_source_content (); 570 1.11 christos 571 1.10 christos refresh_window (); 572 1.1 christos } 573 1.1 christos } 574 1.1 christos 575 1.1 christos 576 1.9 christos /* Set or clear the is_exec_point flag in the line whose line is 577 1.1 christos line_no. */ 578 1.1 christos 579 1.1 christos void 580 1.9 christos tui_source_window_base::set_is_exec_point_at (struct tui_line_or_address l) 581 1.1 christos { 582 1.9 christos bool changed = false; 583 1.1 christos int i; 584 1.1 christos 585 1.1 christos i = 0; 586 1.9 christos while (i < m_content.size ()) 587 1.1 christos { 588 1.9 christos bool new_state; 589 1.1 christos struct tui_line_or_address content_loa = 590 1.9 christos m_content[i].line_or_addr; 591 1.1 christos 592 1.1 christos if (content_loa.loa == l.loa 593 1.1 christos && ((l.loa == LOA_LINE && content_loa.u.line_no == l.u.line_no) 594 1.10 christos || (l.loa == LOA_ADDRESS && content_loa.u.addr == l.u.addr))) 595 1.10 christos new_state = true; 596 1.1 christos else 597 1.9 christos new_state = false; 598 1.9 christos if (new_state != m_content[i].is_exec_point) 599 1.10 christos { 600 1.10 christos changed = true; 601 1.10 christos m_content[i].is_exec_point = new_state; 602 1.10 christos } 603 1.1 christos i++; 604 1.1 christos } 605 1.1 christos if (changed) 606 1.9 christos refill (); 607 1.1 christos } 608 1.1 christos 609 1.9 christos /* See tui-winsource.h. */ 610 1.9 christos 611 1.1 christos void 612 1.9 christos tui_update_all_breakpoint_info (struct breakpoint *being_deleted) 613 1.1 christos { 614 1.9 christos for (tui_source_window_base *win : tui_source_windows ()) 615 1.1 christos { 616 1.9 christos if (win->update_breakpoint_info (being_deleted, false)) 617 1.9 christos win->update_exec_info (); 618 1.1 christos } 619 1.1 christos } 620 1.1 christos 621 1.1 christos 622 1.9 christos /* Scan the source window and the breakpoints to update the break_mode 623 1.1 christos information for each line. 624 1.1 christos 625 1.9 christos Returns true if something changed and the execution window must be 626 1.1 christos refreshed. */ 627 1.1 christos 628 1.9 christos bool 629 1.9 christos tui_source_window_base::update_breakpoint_info 630 1.9 christos (struct breakpoint *being_deleted, bool current_only) 631 1.1 christos { 632 1.1 christos int i; 633 1.9 christos bool need_refresh = false; 634 1.1 christos 635 1.9 christos for (i = 0; i < m_content.size (); i++) 636 1.1 christos { 637 1.1 christos struct tui_source_element *line; 638 1.1 christos 639 1.9 christos line = &m_content[i]; 640 1.1 christos if (current_only && !line->is_exec_point) 641 1.10 christos continue; 642 1.1 christos 643 1.1 christos /* Scan each breakpoint to see if the current line has something to 644 1.10 christos do with it. Identify enable/disabled breakpoints as well as 645 1.10 christos those that we already hit. */ 646 1.9 christos tui_bp_flags mode = 0; 647 1.11 christos for (breakpoint &bp : all_breakpoints ()) 648 1.10 christos { 649 1.11 christos if (&bp == being_deleted) 650 1.10 christos continue; 651 1.1 christos 652 1.11 christos for (bp_location &loc : bp.locations ()) 653 1.1 christos { 654 1.11 christos if (location_matches_p (&loc, i)) 655 1.1 christos { 656 1.11 christos if (bp.enable_state == bp_disabled) 657 1.1 christos mode |= TUI_BP_DISABLED; 658 1.1 christos else 659 1.1 christos mode |= TUI_BP_ENABLED; 660 1.11 christos if (bp.hit_count) 661 1.1 christos mode |= TUI_BP_HIT; 662 1.11 christos if (bp.first_loc ().cond) 663 1.1 christos mode |= TUI_BP_CONDITIONAL; 664 1.11 christos if (bp.type == bp_hardware_breakpoint) 665 1.1 christos mode |= TUI_BP_HARDWARE; 666 1.1 christos } 667 1.1 christos } 668 1.10 christos } 669 1.10 christos 670 1.9 christos if (line->break_mode != mode) 671 1.10 christos { 672 1.10 christos line->break_mode = mode; 673 1.10 christos need_refresh = true; 674 1.10 christos } 675 1.1 christos } 676 1.1 christos return need_refresh; 677 1.1 christos } 678 1.1 christos 679 1.11 christos /* See tui-winsource.h. */ 680 1.11 christos 681 1.1 christos void 682 1.11 christos tui_source_window_base::update_exec_info (bool refresh_p) 683 1.1 christos { 684 1.9 christos update_breakpoint_info (nullptr, true); 685 1.9 christos for (int i = 0; i < m_content.size (); i++) 686 1.1 christos { 687 1.9 christos struct tui_source_element *src_element = &m_content[i]; 688 1.11 christos /* Add 1 for '\0'. */ 689 1.11 christos char element[TUI_EXECINFO_SIZE + 1]; 690 1.11 christos /* Initialize all but last element. */ 691 1.11 christos char space = tui_left_margin_verbose ? '_' : ' '; 692 1.11 christos memset (element, space, TUI_EXECINFO_SIZE); 693 1.11 christos /* Initialize last element. */ 694 1.11 christos element[TUI_EXECINFO_SIZE] = '\0'; 695 1.1 christos 696 1.9 christos /* Now update the exec info content based upon the state 697 1.9 christos of each line as indicated by the source content. */ 698 1.9 christos tui_bp_flags mode = src_element->break_mode; 699 1.9 christos if (mode & TUI_BP_HIT) 700 1.9 christos element[TUI_BP_HIT_POS] = (mode & TUI_BP_HARDWARE) ? 'H' : 'B'; 701 1.9 christos else if (mode & (TUI_BP_ENABLED | TUI_BP_DISABLED)) 702 1.9 christos element[TUI_BP_HIT_POS] = (mode & TUI_BP_HARDWARE) ? 'h' : 'b'; 703 1.1 christos 704 1.9 christos if (mode & TUI_BP_ENABLED) 705 1.9 christos element[TUI_BP_BREAK_POS] = '+'; 706 1.9 christos else if (mode & TUI_BP_DISABLED) 707 1.9 christos element[TUI_BP_BREAK_POS] = '-'; 708 1.1 christos 709 1.9 christos if (src_element->is_exec_point) 710 1.9 christos element[TUI_EXEC_POS] = '>'; 711 1.1 christos 712 1.11 christos mvwaddstr (handle.get (), i + box_width (), box_width (), element); 713 1.10 christos 714 1.10 christos show_line_number (i); 715 1.1 christos } 716 1.11 christos if (refresh_p) 717 1.11 christos refresh_window (); 718 1.1 christos } 719