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