arm, objdump: print obsolote warning when 26-bit set in instructions
[binutils-gdb.git] / gdb / tui / tui-winsource.c
bloba313e44bb33b240755103f4e5acafc7d3ad5d1ea
1 /* TUI display source/assembly window.
3 Copyright (C) 1998-2024 Free Software Foundation, Inc.
5 Contributed by Hewlett-Packard Company.
7 This file is part of GDB.
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.
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.
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/>. */
22 #include "observable.h"
23 #include "symtab.h"
24 #include "frame.h"
25 #include "breakpoint.h"
26 #include "value.h"
27 #include "source.h"
28 #include "objfiles.h"
29 #include "gdbsupport/gdb-safe-ctype.h"
31 #include "tui/tui.h"
32 #include "tui/tui-data.h"
33 #include "tui/tui-io.h"
34 #include "tui/tui-status.h"
35 #include "tui/tui-win.h"
36 #include "tui/tui-winsource.h"
37 #include "tui/tui-source.h"
38 #include "tui/tui-disasm.h"
39 #include "tui/tui-location.h"
40 #include "gdb_curses.h"
42 /* Function to display the "main" routine. */
43 void
44 tui_display_main ()
46 auto adapter = tui_source_windows ();
47 if (adapter.begin () != adapter.end ())
49 struct gdbarch *gdbarch;
50 CORE_ADDR addr;
52 tui_get_begin_asm_address (&gdbarch, &addr);
53 if (addr != (CORE_ADDR) 0)
55 struct symtab *s;
57 tui_update_source_windows_with_addr (gdbarch, addr);
58 s = find_pc_line_symtab (addr);
59 tui_location.set_location (s);
64 /* See tui-winsource.h. */
66 std::string
67 tui_copy_source_line (const char **ptr, int *length)
69 const char *lineptr = *ptr;
71 /* Init the line with the line number. */
72 std::string result;
74 int column = 0;
75 char c;
78 int skip_bytes;
80 c = *lineptr;
81 if (c == '\033' && skip_ansi_escape (lineptr, &skip_bytes))
83 /* We always have to preserve escapes. */
84 result.append (lineptr, lineptr + skip_bytes);
85 lineptr += skip_bytes;
86 continue;
88 if (c == '\0')
89 break;
91 ++lineptr;
92 ++column;
94 auto process_tab = [&] ()
96 int max_tab_len = tui_tab_width;
98 --column;
99 for (int j = column % max_tab_len;
100 j < max_tab_len;
101 column++, j++)
102 result.push_back (' ');
105 if (c == '\n' || c == '\r' || c == '\0')
107 /* Nothing. */
109 else if (c == '\t')
110 process_tab ();
111 else if (ISCNTRL (c))
113 result.push_back ('^');
114 result.push_back (c + 0100);
115 ++column;
117 else if (c == 0177)
119 result.push_back ('^');
120 result.push_back ('?');
121 ++column;
123 else
124 result.push_back (c);
126 while (c != '\0' && c != '\n' && c != '\r');
128 if (c == '\r' && *lineptr == '\n')
129 ++lineptr;
130 *ptr = lineptr;
132 if (length != nullptr)
133 *length = column;
135 return result;
138 void
139 tui_source_window_base::style_changed ()
141 if (tui_active && is_visible ())
142 refill ();
145 /* Function to display source in the source window. This function
146 initializes the horizontal scroll to 0. */
147 void
148 tui_source_window_base::update_source_window
149 (struct gdbarch *gdbarch,
150 const struct symtab_and_line &sal)
152 m_horizontal_offset = 0;
153 update_source_window_as_is (gdbarch, sal);
157 /* Function to display source in the source/asm window. This function
158 shows the source as specified by the horizontal offset. */
159 void
160 tui_source_window_base::update_source_window_as_is
161 (struct gdbarch *gdbarch,
162 const struct symtab_and_line &sal)
164 bool ret = set_contents (gdbarch, sal);
166 if (!ret)
167 erase_source_content ();
168 else
170 validate_scroll_offsets ();
171 update_breakpoint_info (nullptr, false);
172 update_exec_info (false);
173 show_source_content ();
178 /* See tui-winsource.h. */
179 void
180 tui_source_window_base::update_source_window_with_addr (struct gdbarch *gdbarch,
181 CORE_ADDR addr)
183 struct symtab_and_line sal {};
184 if (addr != 0)
185 sal = find_pc_line (addr, 0);
187 update_source_window (gdbarch, sal);
190 /* Function to ensure that the source and/or disassembly windows
191 reflect the input address. */
192 void
193 tui_update_source_windows_with_addr (struct gdbarch *gdbarch, CORE_ADDR addr)
195 struct symtab_and_line sal {};
196 if (addr != 0)
197 sal = find_pc_line (addr, 0);
199 for (struct tui_source_window_base *win_info : tui_source_windows ())
200 win_info->update_source_window (gdbarch, sal);
203 /* Function to ensure that the source and/or disassembly windows
204 reflect the symtab and line. */
205 void
206 tui_update_source_windows_with_line (struct symtab_and_line sal)
208 struct gdbarch *gdbarch = nullptr;
209 if (sal.symtab != nullptr)
211 find_line_pc (sal.symtab, sal.line, &sal.pc);
212 gdbarch = sal.symtab->compunit ()->objfile ()->arch ();
215 for (struct tui_source_window_base *win_info : tui_source_windows ())
216 win_info->update_source_window (gdbarch, sal);
219 void
220 tui_source_window_base::do_erase_source_content (const char *str)
222 m_content.clear ();
223 if (handle != nullptr)
224 center_string (str);
227 /* See tui-winsource.h. */
229 void
230 tui_source_window_base::puts_to_pad_with_skip (const char *string, int skip)
232 gdb_assert (m_pad.get () != nullptr);
233 WINDOW *w = m_pad.get ();
235 while (skip > 0)
237 const char *next = strpbrk (string, "\033");
239 /* Print the plain text prefix. */
240 size_t n_chars = next == nullptr ? strlen (string) : next - string;
241 if (n_chars > 0)
243 if (skip > 0)
245 if (skip < n_chars)
247 string += skip;
248 n_chars -= skip;
249 skip = 0;
251 else
253 skip -= n_chars;
254 string += n_chars;
255 n_chars = 0;
259 if (n_chars > 0)
261 std::string copy (string, n_chars);
262 tui_puts (copy.c_str (), w);
266 /* We finished. */
267 if (next == nullptr)
268 break;
270 gdb_assert (*next == '\033');
272 int n_read;
273 if (skip_ansi_escape (next, &n_read))
275 std::string copy (next, n_read);
276 tui_puts (copy.c_str (), w);
277 next += n_read;
279 else
280 gdb_assert_not_reached ("unhandled escape");
282 string = next;
285 if (*string != '\0')
286 tui_puts (string, w);
289 /* Redraw the complete line of a source or disassembly window. */
290 void
291 tui_source_window_base::show_source_line (int lineno)
293 struct tui_source_element *line;
295 line = &m_content[lineno];
296 if (line->is_exec_point)
297 tui_set_reverse_mode (m_pad.get (), true);
299 wmove (m_pad.get (), lineno, 0);
300 puts_to_pad_with_skip (line->line.c_str (), m_pad_offset);
302 if (line->is_exec_point)
303 tui_set_reverse_mode (m_pad.get (), false);
306 /* See tui-winsource.h. */
308 void
309 tui_source_window_base::refresh_window ()
311 TUI_SCOPED_DEBUG_START_END ("window `%s`", name ());
313 /* tui_win_info::refresh_window would draw the empty background window to
314 the screen, potentially creating a flicker. */
315 wnoutrefresh (handle.get ());
317 int pad_width = getmaxx (m_pad.get ());
318 int left_margin = this->left_margin ();
319 int view_width = this->view_width ();
320 int content_width = m_max_length;
321 int pad_x = m_horizontal_offset - m_pad_offset;
323 tui_debug_printf ("pad_width = %d, left_margin = %d, view_width = %d",
324 pad_width, left_margin, view_width);
325 tui_debug_printf ("content_width = %d, pad_x = %d, m_horizontal_offset = %d",
326 content_width, pad_x, m_horizontal_offset);
327 tui_debug_printf ("m_pad_offset = %d", m_pad_offset);
329 gdb_assert (m_pad_offset >= 0);
330 gdb_assert (m_horizontal_offset + view_width
331 <= std::max (content_width, view_width));
332 gdb_assert (pad_x >= 0);
333 gdb_assert (m_horizontal_offset >= 0);
335 /* This function can be called before the pad has been allocated, this
336 should only occur during the initial startup. In this case the first
337 condition in the following asserts will not be true, but the nullptr
338 check will. */
339 gdb_assert (pad_width > 0 || m_pad.get () == nullptr);
340 gdb_assert (pad_x + view_width <= pad_width || m_pad.get () == nullptr);
342 int sminrow = y + box_width ();
343 int smincol = x + box_width () + left_margin;
344 int smaxrow = sminrow + m_content.size () - 1;
345 int smaxcol = smincol + view_width - 1;
346 pnoutrefresh (m_pad.get (), 0, pad_x, sminrow, smincol, smaxrow, smaxcol);
349 void
350 tui_source_window_base::show_source_content ()
352 TUI_SCOPED_DEBUG_START_END ("window `%s`", name ());
354 gdb_assert (!m_content.empty ());
356 /* The pad should be at least as wide as the window, but ideally, as wide
357 as the content, however, for some very wide content this might not be
358 possible. */
359 int required_pad_width = std::max (m_max_length, width);
360 int required_pad_height = m_content.size ();
362 /* If the required pad width is wider than the previously requested pad
363 width, then we might want to grow the pad. */
364 if (required_pad_width > m_pad_requested_width
365 || required_pad_height > getmaxy (m_pad.get ()))
367 /* The current pad width. */
368 int pad_width = m_pad == nullptr ? 0 : getmaxx (m_pad.get ());
370 gdb_assert (pad_width <= m_pad_requested_width);
372 /* If the current pad width is smaller than the previously requested
373 pad width, then this means we previously failed to allocate a
374 bigger pad. There's no point asking again, so we'll just make so
375 with the pad we currently have. */
376 if (pad_width == m_pad_requested_width
377 || required_pad_height > getmaxy (m_pad.get ()))
379 pad_width = required_pad_width;
383 /* Try to allocate a new pad. */
384 m_pad.reset (newpad (required_pad_height, pad_width));
386 if (m_pad == nullptr)
388 int reduced_width = std::max (pad_width / 2, width);
389 if (reduced_width == pad_width)
390 error (_("failed to setup source window"));
391 pad_width = reduced_width;
394 while (m_pad == nullptr);
397 m_pad_requested_width = required_pad_width;
398 tui_debug_printf ("requested width %d, allocated width %d",
399 required_pad_width, getmaxx (m_pad.get ()));
402 gdb_assert (m_pad != nullptr);
403 werase (m_pad.get ());
404 for (int lineno = 0; lineno < m_content.size (); lineno++)
405 show_source_line (lineno);
407 /* Calling check_and_display_highlight_if_needed will call
408 refresh_window. */
409 check_and_display_highlight_if_needed ();
412 tui_source_window_base::tui_source_window_base ()
414 m_start_line_or_addr.loa = LOA_ADDRESS;
415 m_start_line_or_addr.u.addr = 0;
417 gdb::observers::styling_changed.attach
418 (std::bind (&tui_source_window::style_changed, this),
419 m_observable, "tui-winsource");
422 tui_source_window_base::~tui_source_window_base ()
424 gdb::observers::styling_changed.detach (m_observable);
427 /* See tui-data.h. */
429 void
430 tui_source_window_base::update_tab_width ()
432 werase (handle.get ());
433 rerender ();
436 void
437 tui_source_window_base::rerender ()
439 TUI_SCOPED_DEBUG_START_END ("window `%s`", name ());
441 if (!m_content.empty ())
443 symtab_and_line cursal
444 = get_current_source_symtab_and_line (current_program_space);
446 if (m_start_line_or_addr.loa == LOA_LINE)
447 cursal.line = m_start_line_or_addr.u.line_no;
448 else
449 cursal.pc = m_start_line_or_addr.u.addr;
450 update_source_window (m_gdbarch, cursal);
452 else if (deprecated_safe_get_selected_frame () != NULL)
454 symtab_and_line cursal
455 = get_current_source_symtab_and_line (current_program_space);
456 frame_info_ptr frame = deprecated_safe_get_selected_frame ();
457 struct gdbarch *gdbarch = get_frame_arch (frame);
459 struct symtab *s = find_pc_line_symtab (get_frame_pc (frame));
460 if (this != tui_src_win ())
461 find_line_pc (s, cursal.line, &cursal.pc);
463 /* This centering code is copied from tui_source_window::maybe_update.
464 It would be nice to do centering more often, and do it in just one
465 location. But since this is a regression fix, handle this
466 conservatively for now. */
467 int start_line = (cursal.line - ((height - box_size ()) / 2)) + 1;
468 if (start_line <= 0)
469 start_line = 1;
470 cursal.line = start_line;
472 update_source_window (gdbarch, cursal);
474 else
476 CORE_ADDR addr;
477 struct gdbarch *gdbarch;
478 tui_get_begin_asm_address (&gdbarch, &addr);
479 if (addr == 0)
480 erase_source_content ();
481 else
482 update_source_window_with_addr (gdbarch, addr);
486 /* See tui-data.h. */
488 void
489 tui_source_window_base::refill ()
491 symtab_and_line sal {};
493 if (this == tui_src_win ())
495 sal = get_current_source_symtab_and_line (current_program_space);
496 if (sal.symtab == NULL)
498 frame_info_ptr fi = deprecated_safe_get_selected_frame ();
499 if (fi != nullptr)
500 sal = find_pc_line (get_frame_pc (fi), 0);
504 if (sal.pspace == nullptr)
505 sal.pspace = current_program_space;
507 if (m_start_line_or_addr.loa == LOA_LINE)
508 sal.line = m_start_line_or_addr.u.line_no;
509 else
510 sal.pc = m_start_line_or_addr.u.addr;
512 update_source_window_as_is (m_gdbarch, sal);
515 /* See tui-winsource.h. */
517 bool
518 tui_source_window_base::validate_scroll_offsets ()
520 TUI_SCOPED_DEBUG_START_END ("window `%s`", name ());
522 int original_pad_offset = m_pad_offset;
524 if (m_horizontal_offset < 0)
525 m_horizontal_offset = 0;
527 int content_width = m_max_length;
528 int pad_width = getmaxx (m_pad.get ());
529 int view_width = this->view_width ();
531 tui_debug_printf ("pad_width = %d, view_width = %d, content_width = %d",
532 pad_width, view_width, content_width);
533 tui_debug_printf ("original_pad_offset = %d, m_horizontal_offset = %d",
534 original_pad_offset, m_horizontal_offset);
536 if (m_horizontal_offset + view_width > content_width)
537 m_horizontal_offset = std::max (content_width - view_width, 0);
539 if ((m_horizontal_offset + view_width) > (m_pad_offset + pad_width))
541 m_pad_offset = std::min (m_horizontal_offset, content_width - pad_width);
542 m_pad_offset = std::max (m_pad_offset, 0);
544 else if (m_horizontal_offset < m_pad_offset)
545 m_pad_offset = std::max (m_horizontal_offset + view_width - pad_width, 0);
547 gdb_assert (m_pad_offset >= 0);
548 return (original_pad_offset != m_pad_offset);
551 /* Scroll the source forward or backward horizontally. */
553 void
554 tui_source_window_base::do_scroll_horizontal (int num_to_scroll)
556 if (!m_content.empty ())
558 m_horizontal_offset += num_to_scroll;
560 if (validate_scroll_offsets ())
561 show_source_content ();
563 refresh_window ();
568 /* Set or clear the is_exec_point flag in the line whose line is
569 line_no. */
571 void
572 tui_source_window_base::set_is_exec_point_at (struct tui_line_or_address l)
574 bool changed = false;
575 int i;
577 i = 0;
578 while (i < m_content.size ())
580 bool new_state;
581 struct tui_line_or_address content_loa =
582 m_content[i].line_or_addr;
584 if (content_loa.loa == l.loa
585 && ((l.loa == LOA_LINE && content_loa.u.line_no == l.u.line_no)
586 || (l.loa == LOA_ADDRESS && content_loa.u.addr == l.u.addr)))
587 new_state = true;
588 else
589 new_state = false;
590 if (new_state != m_content[i].is_exec_point)
592 changed = true;
593 m_content[i].is_exec_point = new_state;
595 i++;
597 if (changed)
598 refill ();
601 /* See tui-winsource.h. */
603 void
604 tui_update_all_breakpoint_info (struct breakpoint *being_deleted)
606 for (tui_source_window_base *win : tui_source_windows ())
608 if (win->update_breakpoint_info (being_deleted, false))
609 win->update_exec_info ();
614 /* Scan the source window and the breakpoints to update the break_mode
615 information for each line.
617 Returns true if something changed and the execution window must be
618 refreshed. */
620 bool
621 tui_source_window_base::update_breakpoint_info
622 (struct breakpoint *being_deleted, bool current_only)
624 int i;
625 bool need_refresh = false;
627 for (i = 0; i < m_content.size (); i++)
629 struct tui_source_element *line;
631 line = &m_content[i];
632 if (current_only && !line->is_exec_point)
633 continue;
635 /* Scan each breakpoint to see if the current line has something to
636 do with it. Identify enable/disabled breakpoints as well as
637 those that we already hit. */
638 tui_bp_flags mode = 0;
639 for (breakpoint &bp : all_breakpoints ())
641 if (&bp == being_deleted)
642 continue;
644 for (bp_location &loc : bp.locations ())
646 if (location_matches_p (&loc, i))
648 if (bp.enable_state == bp_disabled)
649 mode |= TUI_BP_DISABLED;
650 else
651 mode |= TUI_BP_ENABLED;
652 if (bp.hit_count)
653 mode |= TUI_BP_HIT;
654 if (bp.first_loc ().cond)
655 mode |= TUI_BP_CONDITIONAL;
656 if (bp.type == bp_hardware_breakpoint)
657 mode |= TUI_BP_HARDWARE;
662 if (line->break_mode != mode)
664 line->break_mode = mode;
665 need_refresh = true;
668 return need_refresh;
671 /* See tui-winsource.h. */
673 void
674 tui_source_window_base::update_exec_info (bool refresh_p)
676 update_breakpoint_info (nullptr, true);
677 for (int i = 0; i < m_content.size (); i++)
679 struct tui_source_element *src_element = &m_content[i];
680 /* Add 1 for '\0'. */
681 char element[TUI_EXECINFO_SIZE + 1];
682 /* Initialize all but last element. */
683 char space = tui_left_margin_verbose ? '_' : ' ';
684 memset (element, space, TUI_EXECINFO_SIZE);
685 /* Initialize last element. */
686 element[TUI_EXECINFO_SIZE] = '\0';
688 /* Now update the exec info content based upon the state
689 of each line as indicated by the source content. */
690 tui_bp_flags mode = src_element->break_mode;
691 if (mode & TUI_BP_HIT)
692 element[TUI_BP_HIT_POS] = (mode & TUI_BP_HARDWARE) ? 'H' : 'B';
693 else if (mode & (TUI_BP_ENABLED | TUI_BP_DISABLED))
694 element[TUI_BP_HIT_POS] = (mode & TUI_BP_HARDWARE) ? 'h' : 'b';
696 if (mode & TUI_BP_ENABLED)
697 element[TUI_BP_BREAK_POS] = '+';
698 else if (mode & TUI_BP_DISABLED)
699 element[TUI_BP_BREAK_POS] = '-';
701 if (src_element->is_exec_point)
702 element[TUI_EXEC_POS] = '>';
704 mvwaddstr (handle.get (), i + box_width (), box_width (), element);
706 show_line_number (i);
708 if (refresh_p)
709 refresh_window ();