Fix logging redirection bug with pager
authorTom Tromey <tom@tromey.com>
Mon, 27 Dec 2021 17:53:16 +0000 (10:53 -0700)
committerTom Tromey <tom@tromey.com>
Wed, 29 Dec 2021 17:30:24 +0000 (10:30 -0700)
I noticed yesterday that if gdb output is redirected to a file, the
pager will still be active.  This is irritating, because the output
isn't actually visible -- just the pager prompt.  Looking in bugzilla,
I found that this had been filed 17 years ago, as PR cli/8798.

This patch fixes the bug.  It changes the pagination code to query the
particular ui-file to see if paging is allowable.  The ui-file
implementations are changed so that only the stdout implementation and
a tee (where one sub-file is stdout) can page.

Regression tested on x86-64 Fedora 34.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=8798

gdb/testsuite/gdb.base/page-logging.exp [new file with mode: 0644]
gdb/ui-file.h
gdb/utils.c

diff --git a/gdb/testsuite/gdb.base/page-logging.exp b/gdb/testsuite/gdb.base/page-logging.exp
new file mode 100644 (file)
index 0000000..8071687
--- /dev/null
@@ -0,0 +1,51 @@
+# Copyright (C) 2021 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Do not run if gdb debug is enabled as it will interfere with log redirect.
+if [gdb_debug_enabled] {
+    untested "debug is enabled"
+    return 0
+}
+
+gdb_start
+
+gdb_test_no_output "set width 100"
+gdb_test_no_output "set height 5"
+gdb_test_no_output "set pagination on"
+
+# Test that logging redirect disables the pager.
+set log_name [standard_output_file log.txt]
+gdb_test_no_output "set logging file $log_name" \
+    "set logging filename"
+gdb_test_no_output "set logging redirect on"
+gdb_test "set logging enabled on" "Copying debug output to .*"
+set ok 1
+set str "1\\n2\\n3\\n4\\n5\\n"
+gdb_test_multiple "printf \"$str\"" "printf without paging" {
+    -re "$pagination_prompt" {
+       set ok 0
+       send_gdb "c\n"
+       exp_continue
+    }
+    -re "\r\n$gdb_prompt $" {
+       # Ok.
+    }
+}
+if {$ok} {
+    pass "printf without paging"
+} else {
+    fail "printf without paging"
+}
+gdb_test "set logging enabled off" "Done logging to .*"
index 9593c94e673e3b58029f68ba906a3d0196844470..0faf84996aa886bba7432450bb94f7dbbf226f01 100644 (file)
@@ -88,6 +88,14 @@ public:
      Otherwise, return -1.  */
   virtual int fd () const
   { return -1; }
+
+  /* Return true if this object supports paging, false otherwise.  */
+  virtual bool can_page () const
+  {
+    /* Almost no file supports paging, which is why this is the
+       default.  */
+    return false;
+  }
 };
 
 typedef std::unique_ptr<ui_file> ui_file_up;
@@ -204,6 +212,11 @@ public:
   int fd () const override
   { return m_fd; }
 
+  virtual bool can_page () const override
+  {
+    return m_file == stdout;
+  }
+
 private:
   /* Sets the internal stream to FILE, and saves the FILE's file
      descriptor in M_FD.  */
@@ -278,6 +291,13 @@ public:
   bool can_emit_style_escape () override;
   void flush () override;
 
+  virtual bool can_page () const override
+  {
+    /* If one of the underlying files can page, then we allow it
+       here.  */
+    return m_one->can_page () || m_two->can_page ();
+  }
+
 private:
   /* The two underlying ui_files.  */
   ui_file *m_one;
index eba1acbc8f6a5614442bd2652c43c958b60caebb..f8c898dd502297b1160f86c131d1de4fcba4b635 100644 (file)
@@ -1749,7 +1749,7 @@ fputs_maybe_filtered (const char *linebuffer, struct ui_file *stream,
     return;
 
   /* Don't do any filtering if it is disabled.  */
-  if (stream != gdb_stdout
+  if (!stream->can_page ()
       || !pagination_enabled
       || pagination_disabled_for_command
       || batch_flag