aboutsummaryrefslogtreecommitdiff
path: root/gdb/utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/utils.c')
-rw-r--r--gdb/utils.c264
1 files changed, 137 insertions, 127 deletions
diff --git a/gdb/utils.c b/gdb/utils.c
index 17498e0..10d3d51 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -1,6 +1,6 @@
/* General utility routines for GDB, the GNU debugger.
- Copyright (C) 1986-2024 Free Software Foundation, Inc.
+ Copyright (C) 1986-2025 Free Software Foundation, Inc.
This file is part of GDB.
@@ -19,6 +19,7 @@
#include <ctype.h>
#include "gdbsupport/gdb_wait.h"
+#include "gdbsupport/scoped_signal_handler.h"
#include "event-top.h"
#include "gdbthread.h"
#include "fnmatch.h"
@@ -53,7 +54,6 @@
#include "top.h"
#include "ui.h"
#include "main.h"
-#include "solist.h"
#include "inferior.h"
@@ -80,6 +80,8 @@
#include "gdbsupport/buildargv.h"
#include "pager.h"
#include "run-on-main-thread.h"
+#include "gdbsupport/gdb_tilde_expand.h"
+#include "gdbsupport/eintr.h"
void (*deprecated_error_begin_hook) (void);
@@ -116,7 +118,7 @@ show_sevenbit_strings (struct ui_file *file, int from_tty,
/* String to be printed before warning messages, if any. */
-const char *warning_pre_print = "\nwarning: ";
+const char *warning_pre_print = "\n";
bool pagination_enabled = true;
static void
@@ -173,8 +175,9 @@ vwarning (const char *string, va_list args)
term_state.emplace ();
target_terminal::ours_for_output ();
}
- if (warning_pre_print)
- gdb_puts (warning_pre_print, gdb_stderr);
+ gdb_puts (warning_pre_print, gdb_stderr);
+ print_warning_prefix (gdb_stderr);
+ gdb_puts (_("warning: "), gdb_stderr);
gdb_vprintf (gdb_stderr, string, args);
gdb_printf (gdb_stderr, "\n");
}
@@ -192,7 +195,7 @@ verror (const char *string, va_list args)
/* Emit a message and abort. */
-static void ATTRIBUTE_NORETURN
+[[noreturn]] static void
abort_with_message (const char *msg)
{
if (current_ui == NULL)
@@ -379,7 +382,7 @@ internal_vproblem (struct internal_problem *problem,
#endif
/* Create a string containing the full error/warning message. Need
- to call query with this full string, as otherwize the reason
+ to call query with this full string, as otherwise the reason
(error/warning) and question become separated. Format using a
style similar to a compiler error message. Include extra detail
so that the user knows that they are living on the edge. */
@@ -596,11 +599,11 @@ add_internal_problem_command (struct internal_problem *problem)
if (problem->user_settable_should_dump_core)
{
std::string set_core_doc
- = string_printf (_("Set whether GDB should create a core file of "
- "GDB when %s is detected."), problem->name);
+ = string_printf (_("Set whether GDB should dump core "
+ "when %s is detected."), problem->name);
std::string show_core_doc
- = string_printf (_("Show whether GDB will create a core file of "
- "GDB when %s is detected."), problem->name);
+ = string_printf (_("Show whether GDB should dump core "
+ "when %s is detected."), problem->name);
add_setshow_enum_cmd ("corefile", class_maintenance,
internal_problem_modes,
&problem->should_dump_core,
@@ -616,11 +619,11 @@ add_internal_problem_command (struct internal_problem *problem)
if (problem->user_settable_should_print_backtrace)
{
std::string set_bt_doc
- = string_printf (_("Set whether GDB should print a backtrace of "
- "GDB when %s is detected."), problem->name);
+ = string_printf (_("Set whether GDB should show backtrace "
+ "when %s is detected."), problem->name);
std::string show_bt_doc
- = string_printf (_("Show whether GDB will print a backtrace of "
- "GDB when %s is detected."), problem->name);
+ = string_printf (_("Show whether GDB should show backtrace "
+ "when %s is detected."), problem->name);
add_setshow_boolean_cmd ("backtrace", class_maintenance,
&problem->should_print_backtrace,
set_bt_doc.c_str (),
@@ -818,7 +821,9 @@ defaulted_query (const char *ctlstr, const char defchar, va_list args)
}
/* Format the question outside of the loop, to avoid reusing args. */
- std::string question = string_vprintf (ctlstr, args);
+ string_file tem (gdb_stdout->can_emit_style_escape ());
+ gdb_vprintf (&tem, ctlstr, args);
+ std::string question = tem.release ();
std::string prompt
= string_printf (_("%s%s(%s or %s) %s"),
annotation_level > 1 ? "\n\032\032pre-query\n" : "",
@@ -1281,6 +1286,14 @@ set_screen_width_and_height (int width, int height)
set_width ();
}
+/* Import termcap variable UP (instead of readline private variable
+ _rl_term_up, which we're trying to avoid, see PR build/10723). The UP
+ variable doesn't seem be part of the regular termcap interface, but rather
+ curses-specific. But if it's missing in the termcap library, then readline
+ provides a fallback version. Let's assume the fallback is not part of the
+ private readline interface. */
+extern "C" char *UP;
+
/* Implement "maint info screen". */
static void
@@ -1339,6 +1352,46 @@ maintenance_info_screen (const char *args, int from_tty)
_("Number of lines environment thinks "
"are in a page is %s (LINES).\n"),
getenv ("LINES"));
+
+ bool have_up = UP != nullptr && *UP != '\0';
+
+ /* Fetch value of readline variable horizontal-scroll-mode. */
+ const char *horizontal_scroll_mode_value
+ = rl_variable_value ("horizontal-scroll-mode");
+ bool force_horizontal_scroll_mode
+ = (horizontal_scroll_mode_value != nullptr
+ && strcmp (horizontal_scroll_mode_value, "on") == 0);
+
+ const char *mode = nullptr;
+ const char *reason = nullptr;
+ if (batch_flag)
+ {
+ mode = "unsupported";
+ reason = "gdb batch mode";
+ }
+ else if (!have_up)
+ {
+ mode = "unsupported";
+ reason = "terminal is not Cursor Up capable";
+ }
+ else if (force_horizontal_scroll_mode)
+ {
+ mode = "disabled";
+ reason = "horizontal-scroll-mode";
+ }
+ else if (readline_hidden_cols)
+ {
+ mode = "readline";
+ reason = "terminal is not auto wrap capable, last column reserved";
+ }
+ else
+ {
+ mode = "terminal";
+ reason = "terminal is auto wrap capable";
+ }
+
+ gdb_printf (gdb_stdout, _("Readline wrapping mode: %s (%s).\n"), mode,
+ reason);
}
void
@@ -1348,24 +1401,31 @@ pager_file::emit_style_escape (const ui_file_style &style)
{
m_applied_style = style;
if (m_paging)
- m_stream->emit_style_escape (style);
+ {
+ /* Previous style changes will have been sent to m_stream via
+ escape sequences encoded in the m_wrap_buffer. As a result,
+ the m_stream->m_applied_style will not have been updated.
+
+ If we now use m_stream->emit_style_escape, then the required
+ style might not actually be emitted as the requested style
+ might happen to match the out of date value in
+ m_stream->m_applied_style.
+
+ Instead, send the style change directly using m_stream->puts.
+
+ However, we track what style is currently applied to the
+ underlying stream in m_stream_style, this is updated whenever
+ m_wrap_buffer is flushed to the underlying stream. And so, if
+ the style we are applying matches what we know is currently
+ applied to the underlying stream, then we can skip sending
+ this style to the stream. */
+ this->set_stream_style (m_applied_style);
+ }
else
m_wrap_buffer.append (style.to_ansi ());
}
}
-/* See pager.h. */
-
-void
-pager_file::reset_style ()
-{
- if (can_emit_style_escape ())
- {
- m_applied_style = ui_file_style ();
- m_wrap_buffer.append (m_applied_style.to_ansi ());
- }
-}
-
/* Wait, so the user can read what's on the screen. Prompt the user
to continue by pressing RETURN. 'q' is also provided because
telling users what to do in the prompt is more user-friendly than
@@ -1383,8 +1443,8 @@ pager_file::prompt_for_continue ()
scoped_restore save_paging = make_scoped_restore (&m_paging, true);
- /* Clear the current styling. */
- m_stream->emit_style_escape (ui_file_style ());
+ /* Clear the current styling on ourselves and the managed stream. */
+ this->emit_style_escape (ui_file_style ());
if (annotation_level > 1)
m_stream->puts (("\n\032\032pre-prompt-for-continue\n"));
@@ -1467,6 +1527,7 @@ pager_file::flush_wrap_buffer ()
if (!m_paging && !m_wrap_buffer.empty ())
{
m_stream->puts (m_wrap_buffer.c_str ());
+ m_stream_style = m_applied_style;
m_wrap_buffer.clear ();
}
}
@@ -1583,10 +1644,7 @@ begin_line (void)
void
pager_file::puts (const char *linebuffer)
{
- const char *lineptr;
-
- if (linebuffer == 0)
- return;
+ gdb_assert (linebuffer != nullptr);
/* Don't do any filtering or wrapping if both are disabled. */
if (batch_flag
@@ -1617,8 +1675,7 @@ pager_file::puts (const char *linebuffer)
when this is necessary; prompt user for new page when this is
necessary. */
- lineptr = linebuffer;
- while (*lineptr)
+ while (*linebuffer != '\0')
{
/* Possible new page. Note that PAGINATION_DISABLED_FOR_COMMAND
might be set during this loop, so we must continue to check
@@ -1628,39 +1685,39 @@ pager_file::puts (const char *linebuffer)
&& lines_printed >= lines_allowed)
prompt_for_continue ();
- while (*lineptr && *lineptr != '\n')
+ while (*linebuffer != '\0' && *linebuffer != '\n')
{
int skip_bytes;
/* Print a single line. */
- if (*lineptr == '\t')
+ if (*linebuffer == '\t')
{
m_wrap_buffer.push_back ('\t');
/* Shifting right by 3 produces the number of tab stops
we have already passed, and then adding one and
shifting left 3 advances to the next tab stop. */
chars_printed = ((chars_printed >> 3) + 1) << 3;
- lineptr++;
+ linebuffer++;
}
- else if (*lineptr == '\033'
- && skip_ansi_escape (lineptr, &skip_bytes))
+ else if (*linebuffer == '\033'
+ && skip_ansi_escape (linebuffer, &skip_bytes))
{
- m_wrap_buffer.append (lineptr, skip_bytes);
+ m_wrap_buffer.append (linebuffer, skip_bytes);
/* Note that we don't consider this a character, so we
don't increment chars_printed here. */
- lineptr += skip_bytes;
+ linebuffer += skip_bytes;
}
- else if (*lineptr == '\r')
+ else if (*linebuffer == '\r')
{
- m_wrap_buffer.push_back (*lineptr);
+ m_wrap_buffer.push_back (*linebuffer);
chars_printed = 0;
- lineptr++;
+ linebuffer++;
}
else
{
- m_wrap_buffer.push_back (*lineptr);
+ m_wrap_buffer.push_back (*linebuffer);
chars_printed++;
- lineptr++;
+ linebuffer++;
}
if (chars_printed >= chars_per_line)
@@ -1687,7 +1744,8 @@ pager_file::puts (const char *linebuffer)
current applied style to how it was at the WRAP_COLUMN
location. */
m_applied_style = m_wrap_style;
- m_stream->emit_style_escape (ui_file_style ());
+ this->set_stream_style (ui_file_style ());
+
/* If we aren't actually wrapping, don't output
newline -- if chars_per_line is right, we
probably just overflowed anyway; if it's wrong,
@@ -1715,7 +1773,7 @@ pager_file::puts (const char *linebuffer)
/* Having finished inserting the wrapping we should
restore the style as it was at the WRAP_COLUMN. */
- m_stream->emit_style_escape (m_wrap_style);
+ this->set_stream_style (m_wrap_style);
/* The WRAP_BUFFER will still contain content, and that
content might set some alternative style. Restore
@@ -1730,17 +1788,17 @@ pager_file::puts (const char *linebuffer)
m_wrap_column = 0; /* And disable fancy wrap */
}
else if (did_paginate)
- m_stream->emit_style_escape (save_style);
+ this->emit_style_escape (save_style);
}
}
- if (*lineptr == '\n')
+ if (*linebuffer == '\n')
{
chars_printed = 0;
wrap_here (0); /* Spit out chars, cancel further wraps. */
lines_printed++;
m_stream->puts ("\n");
- lineptr++;
+ linebuffer++;
}
}
@@ -1751,7 +1809,7 @@ void
pager_file::write (const char *buf, long length_buf)
{
/* We have to make a string here because the pager uses
- skip_ansi_escape, which requires NUL-termination. */
+ examine_ansi_escape, which requires NUL-termination. */
std::string str (buf, length_buf);
this->puts (str.c_str ());
}
@@ -3295,7 +3353,7 @@ gdb_argv_as_array_view_test ()
argument. */
std::string
-ldirname (const char *filename)
+gdb_ldirname (const char *filename)
{
std::string dirname;
const char *base = lbasename (filename);
@@ -3337,51 +3395,6 @@ parse_pid_to_attach (const char *args)
return pid;
}
-/* Substitute all occurrences of string FROM by string TO in *STRINGP. *STRINGP
- must come from xrealloc-compatible allocator and it may be updated. FROM
- needs to be delimited by IS_DIR_SEPARATOR or DIRNAME_SEPARATOR (or be
- located at the start or end of *STRINGP. */
-
-void
-substitute_path_component (char **stringp, const char *from, const char *to)
-{
- char *string = *stringp, *s;
- const size_t from_len = strlen (from);
- const size_t to_len = strlen (to);
-
- for (s = string;;)
- {
- s = strstr (s, from);
- if (s == NULL)
- break;
-
- if ((s == string || IS_DIR_SEPARATOR (s[-1])
- || s[-1] == DIRNAME_SEPARATOR)
- && (s[from_len] == '\0' || IS_DIR_SEPARATOR (s[from_len])
- || s[from_len] == DIRNAME_SEPARATOR))
- {
- char *string_new;
-
- string_new
- = (char *) xrealloc (string, (strlen (string) + to_len + 1));
-
- /* Relocate the current S pointer. */
- s = s - string + string_new;
- string = string_new;
-
- /* Replace from by to. */
- memmove (&s[to_len], &s[from_len], strlen (&s[from_len]) + 1);
- memcpy (s, to, to_len);
-
- s += to_len;
- }
- else
- s++;
- }
-
- *stringp = string;
-}
-
#ifdef HAVE_WAITPID
#ifdef SIGALRM
@@ -3416,35 +3429,19 @@ wait_to_die_with_timeout (pid_t pid, int *status, int timeout)
if (timeout > 0)
{
#ifdef SIGALRM
-#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
- struct sigaction sa, old_sa;
-
- sa.sa_handler = sigalrm_handler;
- sigemptyset (&sa.sa_mask);
- sa.sa_flags = 0;
- sigaction (SIGALRM, &sa, &old_sa);
-#else
- sighandler_t ofunc;
-
- ofunc = signal (SIGALRM, sigalrm_handler);
-#endif
+ scoped_signal_handler<SIGALRM> alarm_restore (sigalrm_handler);
alarm (timeout);
#endif
- waitpid_result = waitpid (pid, status, 0);
+ waitpid_result = gdb::waitpid (pid, status, 0);
#ifdef SIGALRM
alarm (0);
-#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
- sigaction (SIGALRM, &old_sa, NULL);
-#else
- signal (SIGALRM, ofunc);
-#endif
#endif
}
else
- waitpid_result = waitpid (pid, status, WNOHANG);
+ waitpid_result = gdb::waitpid (pid, status, WNOHANG);
if (waitpid_result == pid)
return pid;
@@ -3454,8 +3451,8 @@ wait_to_die_with_timeout (pid_t pid, int *status, int timeout)
#endif /* HAVE_WAITPID */
-/* Provide fnmatch compatible function for FNM_FILE_NAME matching of host files.
- Both FNM_FILE_NAME and FNM_NOESCAPE must be set in FLAGS.
+/* Provide fnmatch compatible function for matching of host files.
+ FNM_NOESCAPE must be set in FLAGS.
It handles correctly HAVE_DOS_BASED_FILE_SYSTEM and
HAVE_CASE_INSENSITIVE_FILE_SYSTEM. */
@@ -3463,8 +3460,6 @@ wait_to_die_with_timeout (pid_t pid, int *status, int timeout)
int
gdb_filename_fnmatch (const char *pattern, const char *string, int flags)
{
- gdb_assert ((flags & FNM_FILE_NAME) != 0);
-
/* It is unclear how '\' escaping vs. directory separator should coexist. */
gdb_assert ((flags & FNM_NOESCAPE) != 0);
@@ -3667,6 +3662,23 @@ copy_bitwise (gdb_byte *dest, ULONGEST dest_offset,
}
}
+/* See utils.h. */
+
+std::string
+extract_single_filename_arg (const char *args)
+{
+ if (args == nullptr)
+ return {};
+
+ std::string filename = extract_string_maybe_quoted (&args);
+ args = skip_spaces (args);
+ if (*args != '\0')
+ error (_("Junk after filename \"%s\": %s"), filename.c_str (), args);
+ if (!filename.empty ())
+ filename = gdb_tilde_expand (filename.c_str ());
+ return filename;
+}
+
#if GDB_SELF_TEST
static void
test_assign_set_return_if_changed ()
@@ -3704,9 +3716,7 @@ test_assign_set_return_if_changed ()
}
#endif
-void _initialize_utils ();
-void
-_initialize_utils ()
+INIT_GDB_FILE (utils)
{
add_setshow_uinteger_cmd ("width", class_support, &chars_per_line, _("\
Set number of characters where GDB should wrap lines of its output."), _("\