From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id US81HkYP22pLHA8AWB0awg (envelope-from ) for ; Fri, 23 Oct 2026 03:39:50 -0400 Authentication-Results: simark.ca; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=RSZ/Cioi; dkim=fail reason="signature verification failed" header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=F8zYYJDw; dkim=fail reason="signature verification failed" (1024-bit key) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=RSZ/Cioi; dkim=neutral header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=F8zYYJDw; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id 776C0378002; Fri, 23 Oct 2026 03:39:50 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-5.1 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIM_INVALID,DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham autolearn_force=no version=4.0.1 Received: from vm01.sourceware.org (vm01.sourceware.org [IPv6:2620:52:6:3111::32]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id D9FCF378002 for ; Fri, 23 Oct 2026 03:39:48 -0400 (EDT) Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 1B68C4BA79BC for ; Fri, 23 Oct 2026 07:39:48 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 1B68C4BA79BC Authentication-Results: sourceware.org; dkim=fail reason="signature verification failed" (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=RSZ/Cioi; dkim=fail reason="signature verification failed" header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=F8zYYJDw; dkim=fail reason="signature verification failed" (1024-bit key) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=RSZ/Cioi; dkim=neutral header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=F8zYYJDw Received: from smtp-out1.suse.de (smtp-out1.suse.de [195.135.223.130]) by sourceware.org (Postfix) with ESMTPS id 4E06E4BA79A9 for ; Fri, 23 Oct 2026 07:38:15 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 4E06E4BA79A9 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=suse.de Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=suse.de ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 4E06E4BA79A9 Authentication-Results: sourceware.org; arc=none smtp.remote-ip=195.135.223.130 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1792741095; cv=none; b=hANE2cRLD8ClYp56ItaEgGUpOJzkyvV/HL8TQyi7EimgqP7RcBLsnfumZDt2jsC4vt+hBOIkjeIbh8BQHa2sK/NBkzVMazdjC1LJ4iXIKn+PrOiyeRf0EHpDqRqMc/ZrbLrjirka21LYHlhEyvbU9p5p2ohVP52XWTw0+zLD85U= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1792741095; c=relaxed/simple; bh=TYfFKjieIuMPo1x7zUS/yV+C0AlBKBZH49UHQ5DPXjI=; h=DKIM-Signature:DKIM-Signature:DKIM-Signature:DKIM-Signature:From: To:Subject:Date:Message-ID:MIME-Version; b=sOxEWMTjn8801m4CfFWm71tqivgPAlocCS7otw7XhWQHR4cbSM2BPOo8D1Xtv6Gh2YaiNUS7fs3UwSuZfPYSPkMSJIfVAaDlm75WbYfzOW5HXcNSWcTPqzgKMmLPYzLPfjGoXsJaampm6G/tG755nJmmmMZMMYp9yfpsJr9N1y0= ARC-Authentication-Results: i=1; sourceware.org; dkim=fail (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=RSZ/Cioi reason="signature verification failed"; dkim=fail header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=F8zYYJDw reason="signature verification failed"; dkim=fail (1024-bit key) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=RSZ/Cioi reason="signature verification failed"; dkim=neutral header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=F8zYYJDw DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 4E06E4BA79A9 Received: from imap1.dmz-prg2.suse.org (unknown [10.150.64.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id 4581322125 for ; Fri, 23 Oct 2026 07:38:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1792741094; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=AIAD+vbrTSQ8zAUljJl+4JYnYATc8UQCFXB/zl8vHco=; b=RSZ/CioiGKNSu+GCSawv9tcrq8MghZz3oxJtx6f033H7lTvRvTMYgkQUpOMmF/9/YLr+Og m65sarPTOK9BoSdtSfurWy6uRnlHlVYcE9VFoWezuuvmz/VhMbJs4lJZiu1zpfwRrekVNU NS7e5O1dF7Giw3ZZTdTerqKGLCrMBM4= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1792741094; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=AIAD+vbrTSQ8zAUljJl+4JYnYATc8UQCFXB/zl8vHco=; b=F8zYYJDwVrOVOl3SKKff6yRH7EjU8pegT/9DcAuYSbfwCXZoOX0I5/I+Yh1ygoTGkv6mw0 NeyQrs5jvoaNr8Bg== Authentication-Results: smtp-out1.suse.de; none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1792741094; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=AIAD+vbrTSQ8zAUljJl+4JYnYATc8UQCFXB/zl8vHco=; b=RSZ/CioiGKNSu+GCSawv9tcrq8MghZz3oxJtx6f033H7lTvRvTMYgkQUpOMmF/9/YLr+Og m65sarPTOK9BoSdtSfurWy6uRnlHlVYcE9VFoWezuuvmz/VhMbJs4lJZiu1zpfwRrekVNU NS7e5O1dF7Giw3ZZTdTerqKGLCrMBM4= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1792741094; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=AIAD+vbrTSQ8zAUljJl+4JYnYATc8UQCFXB/zl8vHco=; b=F8zYYJDwVrOVOl3SKKff6yRH7EjU8pegT/9DcAuYSbfwCXZoOX0I5/I+Yh1ygoTGkv6mw0 NeyQrs5jvoaNr8Bg== Received: from imap1.dmz-prg2.suse.org (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by imap1.dmz-prg2.suse.org (Postfix) with ESMTPS id 0DF4F134E6 for ; Fri, 23 Oct 2026 07:38:14 +0000 (UTC) Received: from dovecot-director2.suse.de ([2a07:de40:b281:106:10:150:64:167]) by imap1.dmz-prg2.suse.org with ESMTPSA id Jy73LeUO22qkUAAAD6G6ig:T2 (envelope-from ) for ; Fri, 23 Oct 2026 07:38:14 +0000 From: Tom de Vries To: gdb-patches@sourceware.org Subject: [PATCH 1/3] [gdb] Fix backtrace in log file (libbacktrace case) Date: Fri, 23 Oct 2026 09:38:11 +0200 Message-ID: <20261023073813.2224939-2-tdevries@suse.de> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20261023073813.2224939-1-tdevries@suse.de> References: <20261023073813.2224939-1-tdevries@suse.de> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spamd-Result: default: False [-11.80 / 50.00]; SUSE_INTERNAL_BYPASS(-9.00)[]; BAYES_HAM(-3.00)[100.00%]; MID_CONTAINS_FROM(1.00)[]; NEURAL_HAM_LONG(-1.00)[-1.000]; R_MISSING_CHARSET(0.50)[]; NEURAL_HAM_SHORT(-0.20)[-0.999]; MIME_GOOD(-0.10)[text/plain]; RCPT_COUNT_ONE(0.00)[1]; RCVD_VIA_SMTP_AUTH(0.00)[]; ARC_NA(0.00)[]; DKIM_SIGNED(0.00)[suse.de:s=susede2_rsa,suse.de:s=susede2_ed25519]; DBL_BLOCKED_OPENRESOLVER(0.00)[imap1.dmz-prg2.suse.org:helo,gnu.org:url]; FROM_EQ_ENVFROM(0.00)[]; FROM_HAS_DN(0.00)[]; MIME_TRACE(0.00)[0:+]; RCVD_COUNT_TWO(0.00)[2]; TO_MATCH_ENVRCPT_ALL(0.00)[]; TO_DN_NONE(0.00)[]; PREVIOUSLY_DELIVERED(0.00)[gdb-patches@sourceware.org]; RCVD_TLS_ALL(0.00)[] X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~public-inbox=simark.ca@sourceware.org Consider test-case gdb.base/logging-internal-error.exp (added by this patch). It enables logging to a file log.txt, and then does "maint internal-error". 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 ----- 0x659d42 gdb_internal_backtrace_1 gdb/bt-utils.c:122 ... 0x419554 main gdb/gdb.c:38 --------------------- This is a bug, please report it. For instructions, see: . Command aborted. (gdb) ... But in log.txt, the backtrace is missing: ... gdb/maint.c:82: internal-error: A problem internal to GDB has been detected, further debugging may prove unreliable. This is a bug, please report it. For instructions, see: . Command aborted. ... The backtrace is printed using sig_write: ... void sig_write (const char *msg) { if (gdb_stderr == nullptr || gdb_stderr->fd () == -1) std::ignore = ::write (2, msg, strlen (msg)); else gdb_stderr->write_async_safe (msg, strlen (msg)); } ... Because logging_file::fd () == -1, plain write is used instead of write_async_safe. Consequently, the message is printed, but not recorded in the log file. Presumably the fd () == -1 check in sig_write is there to avoid running into the default implementation of write_async_safe: ... virtual void write_async_safe (const char *buf, long length_buf) { gdb_assert_not_reached ("write_async_safe"); } ... when gdb_stderr is temporarily set to a string_file. Fix this by: - making the default write_async_safe call do something more useful than asserting: a write to fd (), - making write_async_safe return true if the write was handled, and - using that return value in sig_write to decide whether to call a fallback. --- gdb/bt-utils.c | 9 ++- gdb/cli/cli-logging.c | 8 +- gdb/logging-file.h | 2 +- gdb/mi/mi-console.c | 7 +- gdb/mi/mi-console.h | 2 +- .../gdb.base/logging-internal-error.exp | 75 +++++++++++++++++++ gdb/ui-file.c | 17 +---- gdb/ui-file.h | 20 +++-- 8 files changed, 108 insertions(+), 32 deletions(-) create mode 100644 gdb/testsuite/gdb.base/logging-internal-error.exp diff --git a/gdb/bt-utils.c b/gdb/bt-utils.c index 21a291c3df3..fcb912c8021 100644 --- a/gdb/bt-utils.c +++ b/gdb/bt-utils.c @@ -45,10 +45,11 @@ gdb_internal_backtrace_set_cmd (const char *args, int from_tty, void sig_write (const char *msg) { - if (gdb_stderr == nullptr || gdb_stderr->fd () == -1) - std::ignore = ::write (2, msg, strlen (msg)); - else - gdb_stderr->write_async_safe (msg, strlen (msg)); + size_t len = strlen (msg); + + if (gdb_stderr == nullptr + || !gdb_stderr->write_async_safe (msg, len)) + std::ignore = ::write (2, msg, len); } #ifdef GDB_PRINT_INTERNAL_BACKTRACE diff --git a/gdb/cli/cli-logging.c b/gdb/cli/cli-logging.c index c9482d59199..d8212de4abb 100644 --- a/gdb/cli/cli-logging.c +++ b/gdb/cli/cli-logging.c @@ -174,13 +174,15 @@ logging_file::write (const char *buf, long length_buf) /* See logging-file.h. */ template -void +bool logging_file::write_async_safe (const char *buf, long length_buf) { + bool handled = false; if (log_file != nullptr) - log_file->write_async_safe (buf, length_buf); + handled = log_file->write_async_safe (buf, length_buf); if (ordinary_output ()) - m_out->write_async_safe (buf, length_buf); + handled = m_out->write_async_safe (buf, length_buf); + return handled; } /* See logging-file.h. */ diff --git a/gdb/logging-file.h b/gdb/logging-file.h index 5dfe1118494..f8b9f101150 100644 --- a/gdb/logging-file.h +++ b/gdb/logging-file.h @@ -41,7 +41,7 @@ class logging_file : public ui_file } void write (const char *buf, long length_buf) override; - void write_async_safe (const char *buf, long length_buf) override; + bool write_async_safe (const char *buf, long length_buf) override; void puts (const char *) override; void flush () override; bool can_page () const override; diff --git a/gdb/mi/mi-console.c b/gdb/mi/mi-console.c index 1a10bfa21fb..a5f69691277 100644 --- a/gdb/mi/mi-console.c +++ b/gdb/mi/mi-console.c @@ -47,10 +47,12 @@ mi_console_file::write (const char *buf, long length_buf) this->flush (); } -void +bool mi_console_file::write_async_safe (const char *buf, long length_buf) { - m_raw->write_async_safe (m_prefix, strlen (m_prefix)); + if (!m_raw->write_async_safe (m_prefix, strlen (m_prefix))) + return false; + if (m_quote) { m_raw->write_async_safe (&m_quote, 1); @@ -62,6 +64,7 @@ mi_console_file::write_async_safe (const char *buf, long length_buf) char nl = '\n'; m_raw->write_async_safe (&nl, 1); + return true; } void diff --git a/gdb/mi/mi-console.h b/gdb/mi/mi-console.h index 8dea558fb9b..3e5618495ee 100644 --- a/gdb/mi/mi-console.h +++ b/gdb/mi/mi-console.h @@ -36,7 +36,7 @@ class mi_console_file : public ui_file void write (const char *buf, long length_buf) override; - void write_async_safe (const char *buf, long length_buf) override; + bool write_async_safe (const char *buf, long length_buf) override; private: /* The wrapped raw output stream. */ diff --git a/gdb/testsuite/gdb.base/logging-internal-error.exp b/gdb/testsuite/gdb.base/logging-internal-error.exp new file mode 100644 index 00000000000..b121ca42612 --- /dev/null +++ b/gdb/testsuite/gdb.base/logging-internal-error.exp @@ -0,0 +1,75 @@ +# Copyright 2026 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 . + +# Check that the backtrace generated by "maint internal-error", if any, also +# ends up in the log file. + +require {!isremote host} + +# Do not run if gdb debug is enabled as it will interfere with logging. +require !gdb_debug_enabled + +clean_restart + +# Don't quit, don't produce a core file. +gdb_test_no_output "maint set internal-error corefile no" +gdb_test_no_output "maint set internal-error quit no" + +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 overwrite on" +gdb_test "set logging enabled on" "Copying output to .*" + +set seen_bt 0 +set re_bt [string_to_regexp "----- Backtrace -----"] + +set cmd "maint internal-error" +send_gdb "$cmd\n" +set re \ + [multi_line \ + [string_to_regexp "Command aborted."] \ + "$gdb_prompt $"] +gdb_expect { + -re $re_bt { + set seen_bt 1 + exp_continue + } + -re $re { + pass $cmd + } + -re "$gdb_prompt $" { + fail $cmd + } + timeout { + fail "$cmd (timeout)" + } + eof { + fail "$cmd (eof)" + } +} + +gdb_test "set logging enabled off" "Done logging to .*" + +set fd [open $log_name] +set data [read -nonewline $fd] +close $fd + +set test "Logged backtrace" +if {$seen_bt} { + gdb_assert {[regexp $re_bt $data]} $test +} else { + unsupported $test +} diff --git a/gdb/ui-file.c b/gdb/ui-file.c index 006bdc923e4..85de5440f0c 100644 --- a/gdb/ui-file.c +++ b/gdb/ui-file.c @@ -157,10 +157,11 @@ null_file::puts (const char *) /* Discard the request. */ } -void +bool null_file::write_async_safe (const char *buf, long sizeof_buf) { - /* Discard the request. */ + /* Discard the request. We consider it handled though. */ + return true; } @@ -271,18 +272,6 @@ stdio_file::write (const char *buf, long length_buf) } } -void -stdio_file::write_async_safe (const char *buf, long length_buf) -{ - /* This is written the way it is to avoid a warning from gcc about not using the - result of write (since it can be declared with attribute warn_unused_result). - Alas casting to void doesn't work for this. */ - if (::write (m_fd, buf, length_buf)) - { - /* Nothing. */ - } -} - void stdio_file::puts (const char *linebuffer) { diff --git a/gdb/ui-file.h b/gdb/ui-file.h index f5c23b9b6d9..23cbd2c7e78 100644 --- a/gdb/ui-file.h +++ b/gdb/ui-file.h @@ -20,6 +20,7 @@ #define GDB_UI_FILE_H #include +#include #include "ui-style.h" /* The abstract ui_file base class. */ @@ -67,9 +68,16 @@ class ui_file first. Implementations are also free to ignore some or all of the request. puts_async is not provided as the async versions are rarely used, no point in having both for a rarely used - interface. */ - virtual void write_async_safe (const char *buf, long length_buf) - { gdb_assert_not_reached ("write_async_safe"); } + interface. This default implementation writes to fd (). Return true if + the write was handled. */ + virtual bool write_async_safe (const char *buf, long length_buf) + { + int fd = this->fd (); + if (fd == -1) + return false; + std::ignore = ::write (fd, buf, length_buf); + return true; + } /* Some ui_files override this to provide a efficient implementation that avoids a strlen. */ @@ -163,7 +171,7 @@ class null_file : public ui_file { public: void write (const char *buf, long length_buf) override; - void write_async_safe (const char *buf, long sizeof_buf) override; + bool write_async_safe (const char *buf, long sizeof_buf) override; void puts (const char *str) override; }; @@ -267,8 +275,6 @@ class stdio_file : public ui_file void write (const char *buf, long length_buf) override; - void write_async_safe (const char *buf, long length_buf) override; - void puts (const char *) override; long read (char *buf, long length_buf) override; @@ -436,7 +442,7 @@ class wrapped_file : public ui_file void write (const char *buf, long length_buf) override { return m_stream->write (buf, length_buf); } - void write_async_safe (const char *buf, long length_buf) override + bool write_async_safe (const char *buf, long length_buf) override { return m_stream->write_async_safe (buf, length_buf); } bool can_page () const override -- 2.51.0