tui-winsource.c revision 1.12 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