Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Tom de Vries <tdevries@suse.de>
To: gdb-patches@sourceware.org
Subject: [PATCH 3/3] [gdb] Fix backtrace in log file (execinfo case)
Date: Fri, 23 Oct 2026 09:38:13 +0200	[thread overview]
Message-ID: <20261023073813.2224939-4-tdevries@suse.de> (raw)
In-Reply-To: <20261023073813.2224939-1-tdevries@suse.de>

Consider test-case gdb.base/logging-internal-error.exp.

It enables logging to a file log.txt, and then does "maint internal-error".

Now say we build gdb with --disable-libbacktrace, and run the test-case.

In gdb.log we find the expected output:
...
(gdb) maint internal-error
gdb/maint.c:82: internal-error:
A problem internal to GDB has been detected,
further debugging may prove unreliable.
----- Backtrace -----
gdb/gdb() [0x659b60]
  ...
gdb/gdb() [0xbb2f72]
Backtrace might be incomplete.
---------------------

This is a bug, please report it.  For instructions, see:
<https://www.gnu.org/software/gdb/bugs/>.

Command aborted.
(gdb)
...

But in log.txt, we have:
...
gdb/maint.c:82: internal-error:
A problem internal to GDB has been detected,
further debugging may prove unreliable.
----- Backtrace -----
Backtrace might be incomplete.
---------------------

This is a bug, please report it.  For instructions, see:
<https://www.gnu.org/software/gdb/bugs/>.

Command aborted.
...

Make the test-case detect this by making a regexp a bit stricter.

The problem is in gdb_internal_backtrace_1, where we do:
...
  int fd = ((gdb_stderr == nullptr || gdb_stderr->fd () == -1)
            ? 2
            : gdb_stderr->fd ());
  backtrace_symbols_fd (buffer, frames, fd);
...

We want to write to two files, but there's just one file descriptor.

Fix this by adding a new member function ui_file::for_each_fd, and using it in
gdb_internal_backtrace_1 to call backtrace_symbols_fd.
---
 gdb/bt-utils.c                                   | 12 ++++++++----
 gdb/cli/cli-logging.c                            | 14 ++++++++++++++
 gdb/logging-file.h                               |  1 +
 .../gdb.base/logging-internal-error.exp          |  2 +-
 gdb/ui-file.h                                    | 16 ++++++++++++++++
 5 files changed, 40 insertions(+), 5 deletions(-)

diff --git a/gdb/bt-utils.c b/gdb/bt-utils.c
index fcb912c8021..b0000e92da2 100644
--- a/gdb/bt-utils.c
+++ b/gdb/bt-utils.c
@@ -134,10 +134,14 @@ gdb_internal_backtrace_1 ()
   void *buffer[25];
   int frames = backtrace (buffer, ARRAY_SIZE (buffer));
 
-  int fd = ((gdb_stderr == nullptr || gdb_stderr->fd () == -1)
-	    ? 2
-	    : gdb_stderr->fd ());
-  backtrace_symbols_fd (buffer, frames, fd);
+  bool handled = (gdb_stderr != nullptr
+		  && gdb_stderr->for_each_fd ([&] (int fd)
+		  {
+		    backtrace_symbols_fd (buffer, frames, fd);
+		  }));
+  if (!handled)
+    backtrace_symbols_fd (buffer, frames, 2);
+
   if (frames == ARRAY_SIZE (buffer))
     sig_write (_("Backtrace might be incomplete.\n"));
 }
diff --git a/gdb/cli/cli-logging.c b/gdb/cli/cli-logging.c
index d8212de4abb..53fc66dda56 100644
--- a/gdb/cli/cli-logging.c
+++ b/gdb/cli/cli-logging.c
@@ -187,6 +187,20 @@ logging_file<T>::write_async_safe (const char *buf, long length_buf)
 
 /* See logging-file.h.  */
 
+template<typename T>
+bool
+logging_file<T>::for_each_fd (gdb::function_view<void (int)> f)
+{
+  bool handled = false;
+  if (log_file != nullptr)
+    handled = log_file->for_each_fd (f);
+  if (ordinary_output ())
+    handled = m_out->for_each_fd (f);
+  return handled;
+}
+
+/* See logging-file.h.  */
+
 template<typename T>
 void
 logging_file<T>::puts (const char *linebuffer)
diff --git a/gdb/logging-file.h b/gdb/logging-file.h
index f8b9f101150..7a4c265ed08 100644
--- a/gdb/logging-file.h
+++ b/gdb/logging-file.h
@@ -47,6 +47,7 @@ class logging_file : public ui_file
   bool can_page () const override;
   void emit_style_escape (const ui_file_style &style) override;
   void puts_unfiltered (const char *str) override;
+  bool for_each_fd (gdb::function_view<void (int)> f) override;
 
   bool isatty () override
   {
diff --git a/gdb/testsuite/gdb.base/logging-internal-error.exp b/gdb/testsuite/gdb.base/logging-internal-error.exp
index b121ca42612..9a46ed7c3e2 100644
--- a/gdb/testsuite/gdb.base/logging-internal-error.exp
+++ b/gdb/testsuite/gdb.base/logging-internal-error.exp
@@ -69,7 +69,7 @@ close $fd
 
 set test "Logged backtrace"
 if {$seen_bt} {
-    gdb_assert {[regexp $re_bt $data]} $test
+    gdb_assert {[regexp $re_bt.*$hex $data]} $test
 } else {
     unsupported $test
 }
diff --git a/gdb/ui-file.h b/gdb/ui-file.h
index 23cbd2c7e78..6ef9722ead8 100644
--- a/gdb/ui-file.h
+++ b/gdb/ui-file.h
@@ -22,6 +22,7 @@
 #include <string>
 #include <tuple>
 #include "ui-style.h"
+#include "gdbsupport/function-view.h"
 
 /* The abstract ui_file base class.  */
 
@@ -117,6 +118,18 @@ class ui_file
   virtual int fd () const
   { return -1; }
 
+  /* Use this function to write to a file descriptor, rather than using
+     write (fd (), ...).  In some cases, multiple descriptors need to be
+     written.  Return true if the write was handled.  */
+  virtual bool for_each_fd (gdb::function_view<void (int)> f)
+  {
+    int fd = this->fd ();
+    if (fd == -1)
+      return false;
+    f (fd);
+    return true;
+  }
+
   /* Return true if this object supports paging, false otherwise.  */
   virtual bool can_page () const
   {
@@ -436,6 +449,9 @@ class wrapped_file : public ui_file
   int fd () const override
   { return m_stream->fd (); }
 
+  bool for_each_fd (gdb::function_view<void (int)> f) override
+  { return m_stream->for_each_fd (f); }
+
   void puts_unfiltered (const char *str) override
   { m_stream->puts_unfiltered (str); }
 
-- 
2.51.0


      parent reply	other threads:[~2026-10-23  7:38 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-23  7:38 [PATCH 0/3] [gdb] Fix backtrace in log file Tom de Vries
2026-10-23  7:38 ` [PATCH 1/3] [gdb] Fix backtrace in log file (libbacktrace case) Tom de Vries
2026-10-23  7:38 ` [PATCH 2/3] [gdb] Don't flush in handle_fatal_signal Tom de Vries
2026-10-23  7:38 ` Tom de Vries [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261023073813.2224939-4-tdevries@suse.de \
    --to=tdevries@suse.de \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox