Fix crash with "maint print arc"
[binutils-gdb.git] / gdb / utils.c
index 8d3a89cf03629df116a126142505219b34257fea..f9dc4f234310c6bda1807a27507ee56f05472e13 100644 (file)
@@ -78,6 +78,7 @@
 #include "bt-utils.h"
 #include "gdbsupport/buildargv.h"
 #include "pager.h"
+#include "run-on-main-thread.h"
 
 void (*deprecated_error_begin_hook) (void);
 
@@ -146,9 +147,6 @@ vwarning (const char *string, va_list args)
          term_state.emplace ();
          target_terminal::ours_for_output ();
        }
-      if (filtered_printing_initialized ())
-       gdb_stdout->wrap_here (0);      /* Force out any buffered output.  */
-      gdb_flush (gdb_stdout);
       if (warning_pre_print)
        gdb_puts (warning_pre_print, gdb_stderr);
       gdb_vprintf (gdb_stderr, string, args);
@@ -308,6 +306,16 @@ struct internal_problem
   bool should_print_backtrace;
 };
 
+/* Return true if the readline callbacks have been initialized for UI.
+   This is always true once GDB is fully initialized, but during the early
+   startup phase this is initially false.  */
+
+static bool
+readline_initialized (struct ui *ui)
+{
+  return ui->call_readline != nullptr;
+}
+
 /* Report a problem, internal to GDB, to the user.  Once the problem
    has been reported, and assuming GDB didn't quit, the caller can
    either allow execution to resume or throw an error.  */
@@ -380,6 +388,7 @@ internal_vproblem (struct internal_problem *problem,
   if (problem->should_quit != internal_problem_ask
       || !confirm
       || !filtered_printing_initialized ()
+      || !readline_initialized (current_ui)
       || problem->should_print_backtrace)
     gdb_printf (gdb_stderr, "%s\n", reason.c_str ());
 
@@ -391,7 +400,8 @@ internal_vproblem (struct internal_problem *problem,
       /* Default (yes/batch case) is to quit GDB.  When in batch mode
         this lessens the likelihood of GDB going into an infinite
         loop.  */
-      if (!confirm || !filtered_printing_initialized ())
+      if (!confirm || !filtered_printing_initialized ()
+         || !readline_initialized (current_ui))
        quit_p = 1;
       else
        quit_p = query (_("%s\nQuit this debugging session? "),
@@ -406,15 +416,17 @@ internal_vproblem (struct internal_problem *problem,
 
   gdb_puts (_("\nThis is a bug, please report it."), gdb_stderr);
   if (REPORT_BUGS_TO[0])
-    gdb_printf (gdb_stderr, _("  For instructions, see:\n%s."),
-               REPORT_BUGS_TO);
+    gdb_printf (gdb_stderr, _("  For instructions, see:\n%ps."),
+               styled_string (file_name_style.style (),
+                              REPORT_BUGS_TO));
   gdb_puts ("\n\n", gdb_stderr);
 
   if (problem->should_dump_core == internal_problem_ask)
     {
       if (!can_dump_core_warn (LIMIT_MAX, reason.c_str ()))
        dump_core_p = 0;
-      else if (!filtered_printing_initialized ())
+      else if (!filtered_printing_initialized ()
+              || !readline_initialized (current_ui))
        dump_core_p = 1;
       else
        {
@@ -650,9 +662,6 @@ void
 print_sys_errmsg (const char *string, int errcode)
 {
   const char *err = safe_strerror (errcode);
-  /* We want anything which was printed on stdout to come out first, before
-     this message.  */
-  gdb_flush (gdb_stdout);
   gdb_printf (gdb_stderr, "%s: %s.\n", string, err);
 }
 
@@ -687,6 +696,9 @@ quit (void)
 void
 maybe_quit (void)
 {
+  if (!is_main_thread ())
+    return;
+
   if (sync_quit_force_run)
     quit ();
 
@@ -1570,10 +1582,8 @@ pager_file::puts (const char *linebuffer)
   if (linebuffer == 0)
     return;
 
-  /* Don't do any filtering if it is disabled.  */
-  if (!pagination_enabled
-      || pagination_disabled_for_command
-      || batch_flag
+  /* Don't do any filtering or wrapping if both are disabled.  */
+  if (batch_flag
       || (lines_per_page == UINT_MAX && chars_per_line == UINT_MAX)
       || top_level_interpreter () == NULL
       || top_level_interpreter ()->interp_ui_out ()->is_mi_like_p ())
@@ -1591,6 +1601,12 @@ pager_file::puts (const char *linebuffer)
                         m_wrap_indent = 0;
                       });
 
+  /* If the user does "set height 1" then the pager will exhibit weird
+     behavior.  This is pathological, though, so don't allow it.  */
+  const unsigned int lines_allowed = (lines_per_page > 1
+                                     ? lines_per_page - 1
+                                     : 1);
+
   /* Go through and output each character.  Show line extension
      when this is necessary; prompt user for new page when this is
      necessary.  */
@@ -1601,8 +1617,9 @@ pager_file::puts (const char *linebuffer)
       /* Possible new page.  Note that PAGINATION_DISABLED_FOR_COMMAND
         might be set during this loop, so we must continue to check
         it here.  */
-      if ((lines_printed >= lines_per_page - 1)
-         && !pagination_disabled_for_command)
+      if (pagination_enabled
+         && !pagination_disabled_for_command
+         && lines_printed >= lines_allowed)
        prompt_for_continue ();
 
       while (*lineptr && *lineptr != '\n')
@@ -1677,8 +1694,9 @@ pager_file::puts (const char *linebuffer)
              /* Possible new page.  Note that
                 PAGINATION_DISABLED_FOR_COMMAND might be set during
                 this loop, so we must continue to check it here.  */
-             if (lines_printed >= lines_per_page - 1
-                 && !pagination_disabled_for_command)
+             if (pagination_enabled
+                 && !pagination_disabled_for_command
+                 && lines_printed >= lines_allowed)
                {
                  prompt_for_continue ();
                  did_paginate = true;
@@ -1732,6 +1750,41 @@ pager_file::write (const char *buf, long length_buf)
   this->puts (str.c_str ());
 }
 
+#if GDB_SELF_TEST
+
+/* Test that disabling the pager does not also disable word
+   wrapping.  */
+
+static void
+test_pager ()
+{
+  string_file *strfile = new string_file ();
+  pager_file pager (strfile);
+
+  /* Make sure the pager is disabled.  */
+  scoped_restore save_enabled
+    = make_scoped_restore (&pagination_enabled, false);
+  scoped_restore save_disabled
+    = make_scoped_restore (&pagination_disabled_for_command, false);
+  scoped_restore save_batch
+    = make_scoped_restore (&batch_flag, false);
+  scoped_restore save_lines
+    = make_scoped_restore (&lines_per_page, 50);
+  /* Make it easy to word wrap.  */
+  scoped_restore save_chars
+    = make_scoped_restore (&chars_per_line, 15);
+  scoped_restore save_printed
+    = make_scoped_restore (&chars_printed, 0);
+
+  pager.puts ("aaaaaaaaaaaa");
+  pager.wrap_here (2);
+  pager.puts ("bbbbbbbbbbbb\n");
+
+  SELF_CHECK (strfile->string () == "aaaaaaaaaaaa\n  bbbbbbbbbbbb\n");
+}
+
+#endif /* GDB_SELF_TEST */
+
 void
 gdb_puts (const char *linebuffer, struct ui_file *stream)
 {
@@ -1785,16 +1838,13 @@ fputs_highlighted (const char *str, const compiled_regex &highlight,
     gdb_puts (str, stream);
 }
 
-/* Write character C to gdb_stdout using GDB's paging mechanism and return C.
-   May return nonlocally.  */
-
-int
+void
 gdb_putc (int c)
 {
   return gdb_stdout->putc (c);
 }
 
-int
+void
 gdb_putc (int c, struct ui_file *stream)
 {
   return stream->putc (c);
@@ -3684,5 +3734,6 @@ When set, debugging messages will be marked with seconds and microseconds."),
   selftests::register_test ("gdb_argv_array_view", gdb_argv_as_array_view_test);
   selftests::register_test ("strncmp_iw_with_mode",
                            strncmp_iw_with_mode_tests);
+  selftests::register_test ("pager", test_pager);
 #endif
 }