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