From patchwork Tue Apr 7 10:22:27 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 132752 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id 9CC394BA2E16 for ; Tue, 7 Apr 2026 10:23:34 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 9CC394BA2E16 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=IZI32DOy X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id 985A14BA2E0B for ; Tue, 7 Apr 2026 10:22:36 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 985A14BA2E0B Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 985A14BA2E0B Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1775557356; cv=none; b=HZnv9CSHKPeM1o2d0eTHH9p4LYR4zmXsi1PW9l/avP91LOmo7vMw0jUMyMKrEtQZIFhQvmxCBLnFI+ECp+ls40kcClvXJvdY8wByh0+LRmc9zO3rlBVN1QsW3yX4CChdryAfutUQ9INv8tNYq8jFTtmA9pfR1E5eu3chpf9Xn/E= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1775557356; c=relaxed/simple; bh=/T3Y1Mcwgng3Xu6VnBrsBGA48TfMeQz7lGGjsivazjE=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=iPOVZIrnOU9OxBr1j7arQBqEuU2yiMh8q+6Ykzh+o/tTUpOlQSLbbiugu3hCvWFKlXa0UGAQVE0+2dZqX7LLe3E1/K62dNrZ39XKmXHYLZT6bbDt0cLJ5doKDJDaolJQDIhngZ4xAjjx+dUAFC4zmh9GjpT1ejGYeEH+rYTJxlw= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 985A14BA2E0B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1775557356; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=/PzGU5gRw1z4p3kVngNgpPLmuNsbdEBFW2z+kfM/OXI=; b=IZI32DOykwGNm/x8ITXyRUPhM8DFlDIqnR7ut35rkEi5ce66YIGrqF4KofpwmipQtHhKV8 WESS8Zjh6j7kVfguqVQ8qCQGvvnZNEqniOH/Xo31aCFhVaWnUGVJ+slergsvcXKhL0ohUF JAVQSViiDFtybsB9Vlk+BatilwF8/MQ= Received: from mail-wr1-f72.google.com (mail-wr1-f72.google.com [209.85.221.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-376-uAG3Qpe7MYaFRrBAK2TbCQ-1; Tue, 07 Apr 2026 06:22:34 -0400 X-MC-Unique: uAG3Qpe7MYaFRrBAK2TbCQ-1 X-Mimecast-MFC-AGG-ID: uAG3Qpe7MYaFRrBAK2TbCQ_1775557353 Received: by mail-wr1-f72.google.com with SMTP id ffacd0b85a97d-43cfedb10a8so3203369f8f.1 for ; Tue, 07 Apr 2026 03:22:34 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775557353; x=1776162153; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=/PzGU5gRw1z4p3kVngNgpPLmuNsbdEBFW2z+kfM/OXI=; b=eL3QC3gJJOi20jhQAN+05i/imevuRF99ka8XdG1lv69Fh+BrTmM6pMk/kPN9JWXxtL Xj0q7wFIV4wrw+TSQbjf7GczR9HVRLCnJXUpx9mA0f8IjQ9LJLRpLvqBP4OM8xn7oFCo VUiQU2alCcIFRczqJVWJcJ/6yABxkNf6dQvnsLvkC+PRzm5Q+ypCgWSZSVNlmXniVQ0p 0XOd1lx2dKQIiIkFOJKBbsdgqgfjNJy8/HNkxnp4XjFISdjPTOWce29ye8L2IKxr6Eve GywXho4Mw2D9gr2/ZQz8diWZR76x07nIHufaxYNnPvVjt8fsw5jLrjfXhHoQx7X+7G9l TCQA== X-Gm-Message-State: AOJu0YwtyiZM0EeqEwRzLMxECPe+it9HxsvEHTc9J4+LcJxKM73fcVPE NqtlaTfIliE76Ke2NeUDI/9Yctbk/iqK8RzzRJM4Kvp5/pmm1lYm7IeljkHooZsZ28kvLKcryM0 1QICHeICqk7TLZmz1S/C85aEXZwW9rfFs1l00ZY04HzEr0XKTtGZh1FGh8LvPqAhc+D4XKSt/2+ 6bsm+gXugcsRPRx52owOLSB5hGw/TAJUrsLPQVf2/LvXfHRWM= X-Gm-Gg: AeBDiesuQ1ffQmXDgCaAnRO0PayiI8X3dkzO6Eop38j6iac6P6b0xZZFSOXQ8EPYVsG HYTwXLqEaOeb/mZoNmC0C9Xdqm5BO8qjBxXqtwWyCOq+HTYvlDQJH6AH0A7N1q2f1lUn4m5c+UV GhUVuz628DV087Vw0VY1nSPBF4SRz8yWeSuj0Lj0j+1xejPpUswNQIHK394YG4/EPgbyDZOl3AY uo8KMWxPWdFH1DeisIQCuHTdLYEccm5W8bgSrGNi/PDsidZeHdsmrv7CP7yXvlQfzkVns5BAFcN MosU7EVvHlb9R8Z++p8K89Pv87ACIgW9RHi0GrsSr1iic4itE4z7NrV+PHp+LTIj5R9zmkor4Oy OH8tTJdl8eisgTKNT X-Received: by 2002:a05:6000:25c6:b0:43c:ffee:ee91 with SMTP id ffacd0b85a97d-43d292ff366mr23102244f8f.36.1775557352698; Tue, 07 Apr 2026 03:22:32 -0700 (PDT) X-Received: by 2002:a05:6000:25c6:b0:43c:ffee:ee91 with SMTP id ffacd0b85a97d-43d292ff366mr23102186f8f.36.1775557352110; Tue, 07 Apr 2026 03:22:32 -0700 (PDT) Received: from localhost ([31.111.84.232]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43d1e2a71f7sm51286623f8f.1.2026.04.07.03.22.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 07 Apr 2026 03:22:31 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCH 1/3] gdb: int to bool conversion in linux-thread-db.c Date: Tue, 7 Apr 2026 11:22:27 +0100 Message-Id: <06e340b55f36093000d86d6da7dc6c71910223ca.1775557188.git.aburgess@redhat.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: eWqMh60kaPnm24h9xr-24jw0d6RI3RaG6LLsVNRFlo4_1775557353 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true X-Spam-Status: No, score=-11.9 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org 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~patchwork=sourceware.org@sourceware.org Some 'int' to 'bool' cleanup in linux-thread-db.c. There should be no user visible changes after this commit. Reviewed-By: Keith Seitz --- gdb/linux-nat.h | 2 +- gdb/linux-thread-db.c | 40 ++++++++++++++++++++-------------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/gdb/linux-nat.h b/gdb/linux-nat.h index 0f128892735..180059a9496 100644 --- a/gdb/linux-nat.h +++ b/gdb/linux-nat.h @@ -316,7 +316,7 @@ lwp_info_safe_range all_lwps_safe (); does whatever is required to have the child LWP under the thread_db's control --- e.g., enabling event reporting. Returns true on success, false if the process isn't using libpthread. */ -extern int thread_db_notice_clone (ptid_t parent, ptid_t child); +extern bool thread_db_notice_clone (ptid_t parent, ptid_t child); /* Return the number of signals used by the threads library. */ extern unsigned int lin_thread_get_thread_signal_num (void); diff --git a/gdb/linux-thread-db.c b/gdb/linux-thread-db.c index 0753d2e7915..cd25c55a898 100644 --- a/gdb/linux-thread-db.c +++ b/gdb/linux-thread-db.c @@ -429,7 +429,7 @@ thread_from_lwp (thread_info *stopped, ptid_t ptid) /* See linux-nat.h. */ -int +bool thread_db_notice_clone (ptid_t parent, ptid_t child) { struct thread_db_info *info; @@ -437,7 +437,7 @@ thread_db_notice_clone (ptid_t parent, ptid_t child) info = get_thread_db_info (linux_target, child.pid ()); if (info == NULL) - return 0; + return false; thread_info *stopped = linux_target->find_thread (parent); @@ -446,7 +446,7 @@ thread_db_notice_clone (ptid_t parent, ptid_t child) /* If we do not know about the main thread's pthread info yet, this would be a good time to find it. */ thread_from_lwp (stopped, parent); - return 1; + return true; } static void * @@ -460,10 +460,10 @@ verbose_dlsym (void *handle, const char *name) } /* Verify inferior's '\0'-terminated symbol VER_SYMBOL starts with "%d.%d" and - return 1 if this version is lower (and not equal) to - VER_MAJOR_MIN.VER_MINOR_MIN. Return 0 in all other cases. */ + return true if this version is lower (and not equal) to + VER_MAJOR_MIN.VER_MINOR_MIN. Return false in all other cases. */ -static int +static bool inferior_has_bug (const char *ver_symbol, int ver_major_min, int ver_minor_min) { CORE_ADDR version_addr; @@ -472,7 +472,7 @@ inferior_has_bug (const char *ver_symbol, int ver_major_min, int ver_minor_min) bound_minimal_symbol version_msym = lookup_minimal_symbol (current_program_space, ver_symbol); if (version_msym.minsym == NULL) - return 0; + return false; version_addr = version_msym.value_address (); gdb::unique_xmalloc_ptr version @@ -493,10 +493,10 @@ inferior_has_bug (const char *ver_symbol, int ver_major_min, int ver_minor_min) /* Similar as thread_db_find_new_threads_1, but try to silently ignore errors if appropriate. - Return 1 if the caller should abort libthread_db initialization. Return 0 - otherwise. */ + Return true if the caller should abort libthread_db initialization. + Return false otherwise. */ -static int +static bool thread_db_find_new_threads_silently (thread_info *stopped) { @@ -518,25 +518,25 @@ thread_db_find_new_threads_silently (thread_info *stopped) itself. If the nptl bug is NOT present in the inferior and still thread_db - reports an error return 1. It means the inferior has corrupted thread - list and GDB should fall back only to LWPs. + reports an error return true. It means the inferior has corrupted + thread list and GDB should fall back only to LWPs. - If the nptl bug is present in the inferior return 0 to silently ignore - such errors, and let gdb enumerate threads again later. In such case - GDB cannot properly display LWPs if the inferior thread list is - corrupted. For core files it does not apply, no 'later enumeration' - is possible. */ + If the nptl bug is present in the inferior return false to + silently ignore such errors, and let gdb enumerate threads again + later. In such case GDB cannot properly display LWPs if the + inferior thread list is corrupted. For core files it does not + apply, no 'later enumeration' is possible. */ if (!target_has_execution () || !inferior_has_bug ("nptl_version", 2, 7)) { exception_fprintf (gdb_stderr, except, _("Warning: couldn't activate thread debugging " "using libthread_db: ")); - return 1; + return true; } } - return 0; + return false; } /* Lookup a library in which given symbol resides. @@ -924,7 +924,7 @@ try_thread_db_load_1 (struct thread_db_info *info) linux_unstop_all_lwps (); } - else if (thread_db_find_new_threads_silently (inferior_thread ()) != 0) + else if (thread_db_find_new_threads_silently (inferior_thread ())) { /* Even if libthread_db initializes, if the thread list is corrupted, we'd not manage to list any threads. Better reject this From patchwork Tue Apr 7 10:22:28 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 132751 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id 438D44BA2E27 for ; Tue, 7 Apr 2026 10:23:21 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 438D44BA2E27 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=aQJiz00l X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id D039C4BA2E0D for ; Tue, 7 Apr 2026 10:22:36 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org D039C4BA2E0D Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org D039C4BA2E0D Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1775557356; cv=none; b=uB3P3E3GUGEg8HxBoEKAhNY62xonQAGOri49NPPulL2/ukUSVH6wiQNo+rRh7+nFaWOzu8i+eFBjXlBLe+BdjZtNz8pJC/Eo371fbwcM1IwYVOA3wmUnBChsWomp92oHpyZVvZYYRdz9COhnye+w4mmrDjkNAfU+E8Zn7rMF3hU= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1775557356; c=relaxed/simple; bh=s9I47/PwYIG1ErgJSoDouPR5ueZPNztiG763BywneqE=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=vTlpPy+2DnsFLpYEzJHF3Di6oSBuJmqEaCQ4jyZ5S4ylP28kK7tHfAaVdfrWlIEEaeM6j6LOuDQoekW7ilsXaqFujM9GUnD98PYX+Era0SVLb35PBtBzK6/sIDyq3VrT4ZIKw5PpXwIDAZXgrLR1pYi71CuiU1MkONRVmJ1xKGU= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org D039C4BA2E0D DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1775557356; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=iYhYgb5obz1Et6Jx8OuDFolaWIP4Wrfxp9ZRUZATo6I=; b=aQJiz00lQA8limsG+/QY5ulhn0pyi4LV6KpndLxscK/PD0W983yq4xOA6BpQOEduSdUHec i0vzQarc3QttWSe+9oMW7XtDT8Cf3+eyJV5ixlxypIU/Qml3qN17f56OYuqEqcDm5ZnsZt waoPSWGbWbE53t7smz08op8sxJqufTs= Received: from mail-wr1-f70.google.com (mail-wr1-f70.google.com [209.85.221.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-644-nn5C7zUlOkWdZvMytHL4wA-1; Tue, 07 Apr 2026 06:22:35 -0400 X-MC-Unique: nn5C7zUlOkWdZvMytHL4wA-1 X-Mimecast-MFC-AGG-ID: nn5C7zUlOkWdZvMytHL4wA_1775557354 Received: by mail-wr1-f70.google.com with SMTP id ffacd0b85a97d-43d0c06c232so4257763f8f.1 for ; Tue, 07 Apr 2026 03:22:35 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775557353; x=1776162153; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=iYhYgb5obz1Et6Jx8OuDFolaWIP4Wrfxp9ZRUZATo6I=; b=a4MTNjl5GeaOUwbFS+YSjM00UNdFLBdgcxx551qmc1PFP2cvXxwOpJV6+X7mCXxVhK TGANxVn9ujMvVfppulFjxHcOmUvf3Jwlv9rDDUcNI8rLIl5xDZPAKk3NxVNbIwbQVT8H MEHpIKy9Hv7AqzpgcDSX/CT3O+vzIPiTQS7cpf2KlE0auYC21JRDFxh7h4YxnFNTXNMS HXy/tdKEewKAbj3iV+I9Xd270xCWMpXIPyEzRwPmrKIA3MhdNi9qgwo6ChWilb0EnPEB PeU8gK2OEZUxBgT9JBsWSYxzKEIh41hVLkukKuY1LlOR0V9hhABKAGSpJOI4J2CJcNWY CQxA== X-Gm-Message-State: AOJu0YyhJm4Gl9v2jaKyl1EptPTH8huCQgHLt1ciHNolQHjGUHvLrT5H 7t/tiN3NocCIlsttakv3/uujmVf34S2iPhqLS47Y1e+Cg/xGlK7ds9LyNopsx4N73FfLNcwwVLn +9MdsvuY2pfb+2wKbK+V7La7L3LZHnkjUYX3+qCv0aIhzf291TbpAmPVZNmSwcGnFRs3WaAAiUl y5MFqyoZ2o31RASKRmN87yC9awby0cvtXEngGX6KGDZ1bEMGk= X-Gm-Gg: AeBDieukuTLdMldS6/qS+j9nQz4vpDYh7KB4NgzVfCknoWrarmekDxaUW+BbFPVII8C YbufD201lPJPKrPmtNA6Ac0P86/aFZPgtGEpFjAnF9fLMSOKatYKZF2Zlqdg4HNnuGS8YjwYxZn C/S19VuLtTchxRSPhTYsF4e1ACQteCHv4PEBNd5tY+S/G9iC7DBuGwe+WVXn6K8ee4oj3g1GSAU 557Tr4FMAhZD65sUiqitsoQ5uza5bRW/FSWFm2JzdQS/pNs6uPkdngU14bTNX7CSdLbblgbTePr KuxLeXgOpD/1QEc5ZT6hY4xifd+Htmr2/UCP8KQKdJ8yPbOOoR2cb8dI11s6RiXfr9nZHzPJzbc ueaMmMk319PU5r5Lq X-Received: by 2002:a5d:5f86:0:b0:43b:43d3:62ac with SMTP id ffacd0b85a97d-43d292a8a5amr25002206f8f.18.1775557353501; Tue, 07 Apr 2026 03:22:33 -0700 (PDT) X-Received: by 2002:a5d:5f86:0:b0:43b:43d3:62ac with SMTP id ffacd0b85a97d-43d292a8a5amr25002152f8f.18.1775557353025; Tue, 07 Apr 2026 03:22:33 -0700 (PDT) Received: from localhost ([31.111.84.232]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43d1e2a6f5bsm44498829f8f.7.2026.04.07.03.22.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 07 Apr 2026 03:22:32 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCH 2/3] gdb: add some asserts to thread_db_notice_clone Date: Tue, 7 Apr 2026 11:22:28 +0100 Message-Id: <2c5f44442eacd91020ce9058abf16442ecf3718a.1775557188.git.aburgess@redhat.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: qBc3PXvLebS67Zikr2WeSKl4k4tsOF-QLzTrIht3kLA_1775557354 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true X-Spam-Status: No, score=-11.9 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org 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~patchwork=sourceware.org@sourceware.org This commit adds some asserts to thread_db_notice_clone, and reorders some code. This is really just a refactor ahead of the next commit. The changes made here are: 1. Add an assert that STOPPED is not NULL. We pass STOPPED as the first argument to thread_from_lwp, which already assumes that the pointer is not NULL. If STOPPED was ever NULL then we would have hit a segfault in thread_from_lwp long ago. 2. Move the thread_from_lwp call relating to the PARENT thread before the call relating to the CHILD thread, and assert that the value we get back is STOPPED. The thread_from_lwp might also gather thread-db related information about PARENT, so the call is important, but even if PARENT cannot be managed via thread-db, the result we get back should always still be STOPPED (see record_thread for more details). Moving this call before the call relating to the CHILD thread makes the next commit cleaner. There should be no user visible changes after this commit as I believe both of the things being asserted have always been true. Reviewed-By: Keith Seitz --- gdb/linux-thread-db.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/gdb/linux-thread-db.c b/gdb/linux-thread-db.c index cd25c55a898..1807352ed76 100644 --- a/gdb/linux-thread-db.c +++ b/gdb/linux-thread-db.c @@ -440,12 +440,17 @@ thread_db_notice_clone (ptid_t parent, ptid_t child) return false; thread_info *stopped = linux_target->find_thread (parent); - - thread_from_lwp (stopped, child); + gdb_assert (stopped != nullptr); /* If we do not know about the main thread's pthread info yet, this - would be a good time to find it. */ - thread_from_lwp (stopped, parent); + would be a good time to find it. This should return the same + thread_info as STOPPED, but a side effect of this call is that the + pthread/thread-db information might have been filled in if it was not + already known. */ + thread_info *parent_info = thread_from_lwp (stopped, parent); + gdb_assert (parent_info == stopped); + + thread_from_lwp (stopped, child); return true; } From patchwork Tue Apr 7 10:22:29 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 132753 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id E28F74BA2E1D for ; Tue, 7 Apr 2026 10:24:10 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org E28F74BA2E1D Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=T1bofGmT X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id CFD9C4BA2E14 for ; Tue, 7 Apr 2026 10:22:38 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org CFD9C4BA2E14 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org CFD9C4BA2E14 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1775557358; cv=none; b=Gc7iM7ESVZ+MqvHjRz9JNh8/dP8BbbuLFRxIJ+Oxzw60z7ravRquLmAnjJ/G2NB3pGmp5fM8h7LiAaYq/bpymKfDpzvesCUlRFBb+Y18iqF1GHCqNZJDYHfj4gaqiuYZkizLHP+sI+Zg1DZskIGNbibpsVPgcDg30ZxKDE06uoY= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1775557358; c=relaxed/simple; bh=WR5BmjeaC8ThmQlsFovm1jqLrTmNYK0tGor+7z8lpFE=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=gmDyZpY6tTtOzw8OnrY1JgWKg9SLAtOCY6inNybZyZyyOCGPhXXNedhllyovJ056MVPbfOfVLjzqHdmz/DkIA88izdceAoXT4/r8i4kgpVX+FT58jrvlNRcsESTvfC3G42/JkxN4Ww+Wr9GrsjFp2qZnyoCSp372MuhwoEEIMhE= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org CFD9C4BA2E14 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1775557358; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=5L0ntv+bsERDxVC8qsfMy+c0ORIzWbC6ic11WMOS7L8=; b=T1bofGmTvEvC2dBo19ZoFXnauvlN4FGj5ESuw/YjmgCm99ekU6bEC4r5Wl1w7wwoycsTKa vX8odPftwaB98iM37NPf7P/3p3F7Y6hLBSDSEbXdJYCfNMlbn+e3FVubLCbwdcUpI8hLF+ ozUVeg8O4PuLm9XyBrdtOvol92h1hfc= Received: from mail-wm1-f69.google.com (mail-wm1-f69.google.com [209.85.128.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-448-j4YxkzX7N5uuzHYFD3PhEA-1; Tue, 07 Apr 2026 06:22:37 -0400 X-MC-Unique: j4YxkzX7N5uuzHYFD3PhEA-1 X-Mimecast-MFC-AGG-ID: j4YxkzX7N5uuzHYFD3PhEA_1775557356 Received: by mail-wm1-f69.google.com with SMTP id 5b1f17b1804b1-488bf01961cso3270565e9.0 for ; Tue, 07 Apr 2026 03:22:37 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775557356; x=1776162156; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=5L0ntv+bsERDxVC8qsfMy+c0ORIzWbC6ic11WMOS7L8=; b=rVxwSniEHybb+0rY9jt8oISoig/NCxLRpTdEy2oPfTFpq84r6dC5yWB0q2Tt7hY4SX LHJLxNrilTedN7J/rx2ddNicesuUO45XERqJL96ERGP18CNhhlY8c7TuI4+F2Du3Rpc0 WwoYNMweDovpY5j+T1PKOuHcdhKjb65z1UvnoHRBzumw1bpCj7p76zW+DgiLl8rAId4K Ggn+bhCXIlQRpFL8Dd68bhlhV1D8IzoyZDMPFwOF50DnCOxBptJzVXB706DtICWrakAQ 9CeN5acxQICagXQEkFetSARW5f/CjC5zBtorAoC/e4xAtHkW90a0/NF7uhy7G/djBSKN MQOQ== X-Gm-Message-State: AOJu0YxKHBHLMskrPxkS2GV/FqcVHlqYEszNBRAB9wLlr8B1axpY113z lg8YzMFWlbFXtJ5zKK6o4xH7IXFQwqm7y1UxQZVLkt5B659KCTBF/c577WYuMdajHcFg0+brpEE k/W2Evt6PJnSH5t7/N/KF4rGDqJfKzCdCGDRb6lKqQwTGYv03T5QJJjmNMT41zxQu18pUE8SLeU +CESIGH+3fNKwOSjMEcfcLNxAncoJZ3uLpFHriTKoKAfFlQSw= X-Gm-Gg: AeBDietaj2ck+Zk4B3pRAEJv9vqyHae40DOWpDTnN9dO44S5uc6RNQyO+lDtm42+50J /W5ziwH7+V+UgrWDYAMusDPPMeE5yxJ7xPUtpZdreJESHdiXSEYl98aFPOvMY0qFBFsfECkjxQQ /1sNYxwghoQsaoaJHauIyp5v9QyJsp/Eg2XTVhkfRPcE6dCptVSyC6+sI/LKVCirE4b2Nl0K4m1 MFhnIaQGfZFcJ/2Bbh0dEYzhvwZuXydG15NSe8aBEO6mlMgU/6kDOpFPnUFzT1i568KiLJDky9M sMyIVsIddQ2dX02N1oZqcZqIvohsvOfVrBk94gn8/czEFm31n6GQSh0D8JLu6uZ2G6l6fyEHKNI Vz/cFfSnoxhOgF8Si X-Received: by 2002:a05:600c:c10b:b0:488:b043:5efd with SMTP id 5b1f17b1804b1-488b0436356mr77833495e9.13.1775557355093; Tue, 07 Apr 2026 03:22:35 -0700 (PDT) X-Received: by 2002:a05:600c:c10b:b0:488:b043:5efd with SMTP id 5b1f17b1804b1-488b0436356mr77832655e9.13.1775557354147; Tue, 07 Apr 2026 03:22:34 -0700 (PDT) Received: from localhost ([31.111.84.232]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-48899d1b12bsm154117475e9.5.2026.04.07.03.22.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 07 Apr 2026 03:22:33 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCH 3/3] gdb: improve error handling for thread-db thread adoption Date: Tue, 7 Apr 2026 11:22:29 +0100 Message-Id: <63e2a1079d44737c020efc5bc177da21feab0ce5.1775557188.git.aburgess@redhat.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: 38dwSpKPg26XwmFObIvDqo824KxeIrcTPL4UCFJQnuk_1775557356 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true X-Spam-Status: No, score=-11.9 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP, WEIRD_PORT autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org 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~patchwork=sourceware.org@sourceware.org This work started with a bug report against Fedora GDB. The bug link is included at the end of this message, but it isn't super informative and there was no follow up, so all we have is the original report. The bug was that GDB crashed with this backtrace: #4 dump_core at ../../gdb/utils.c:225 #5 internal_vproblem(internal_problem *, const char *, int, const char *, typedef __va_list_tag __va_list_tag *) at ../../gdb/utils.c:477 #6 internal_verror at ../../gdb/utils.c:503 #7 internal_error_loc at ../../gdbsupport/errors.cc:57 #8 report_exit_events_for at ../../gdb/linux-nat.c:331 #10 linux_nat_filter_event at ../../gdb/linux-nat.c:3063 #11 linux_nat_wait_1 at ../../gdb/linux-nat.c:3377 #12 linux_nat_target::wait at ../../gdb/linux-nat.c:3603 #13 thread_db_target::wait at ../../gdb/linux-thread-db.c:1401 #14 target_wait at ../../gdb/target.c:2582 #15 do_target_wait_1 at ../../gdb/infrun.c:4144 #16 operator() at ../../gdb/infrun.c:4206 #17 do_target_wait at ../../gdb/infrun.c:4225 #18 fetch_inferior_event at ../../gdb/infrun.c:4666 #19 gdb_wait_for_event at ../../gdbsupport/event-loop.cc:694 #20 gdb_do_one_event at ../../gdbsupport/event-loop.cc:216 #21 start_event_loop at ../../gdb/main.c:402 #22 captured_command_loop at ../../gdb/main.c:466 #23 captured_main at ../../gdb/main.c:1343 #24 gdb_main at ../../gdb/main.c:1362 Frame #8 is where things start going wrong, and the line in question is this gdb_assert: thread_info *thr = linux_target->find_thread (lp->ptid); gdb_assert (thr != nullptr); <---- This is line 331. So what we know is that while reporting a thread exit event GDB failed to find the thread_info for a thread. We can imagine many bugs that might cause this to occur, some of which could even be outside GDB. But without additional information I'm not inclined to start looking for bugs outside of GDB. So I started looking for ways that the bug could be triggered from within GDB. One way the bug could occur is if GDB fails to create a thread_info for a new thread. This led me to look at linux_nat_target::follow_clone, which led to looking at thread_db_notice_clone. In ::follow_clone GDB already has code to handle the case where thread_db_notice_clone fails to add a thread: if (!thread_db_notice_clone (inferior_ptid, new_lp->ptid)) { /* The process is not using thread_db. Add the LWP to GDB's list. */ add_thread (linux_target, new_lp->ptid); } But does this always do what we need? In thread_db_notice_clone, if the CHILD thread was not adopted by thread-db then the thread_from_lwp will return NULL, but we don't currently check this, instead we always return true from thread_db_notice_clone. This is an easy fix, we can just check the return value of thread_from_lwp in thread_db_notice_clone. Next, looking through thread_from_lwp, we can see several calls to `error`. If any of these trigger then GDB will throw an exception, in which case we'll unwind back through ::follow_clone without adding the thread to GDB's data structures. I think this can be fixed by using a FORWARD_SCOPE_EXIT in ::follow_clone which will add the thread to GDB's data structures. Now, if an exception triggers, we will still record the thread. Initially, I'd thought just adding the thread on the exception path would be enough, on x86-64 the target I initially tested on, I wasn't able to trigger the error cases, so I was writing code to cover this path "just in case". But when I started testing on AArch64 and PPC64le, I found that my same test case (more details below) was triggering the error path. What I found is that throwing an exception from thread_from_lwp was causing GDB to stop the inferior unnecessarily. GDB would see a CLONE event from the inferior, try to add the new thread to GDB, but this would result in the `error` path, and an exception being thrown. The exception was not handled anywhere, so GDB would drop back to the prompt, leaving the inferior stopped. This is despite the fallback code that I added above handling the failure of thread-db to adopt the thread. My solution for this is to convert the `error` calls into warnings, and just have thread_from_lwp return NULL if thread-db cannot adopt the thread. This potentially makes the use of FORWARD_SCOPE_EXIT in ::follow_clone unnecessary, I no longer expect any exceptions to be thrown from thread_db_notice_clone. However, I think maintaining the use of FORWARD_SCOPE_EXIT is still a good idea. If I've missed any exception routes, or any are added in the future, then this will ensure the threads are always added to GDB correctly. The testing for this change is a little weird. It involves creating a thread using a direct clone call, and manually setting the thread's TLS pointer to NULL. So long as we don't do anything that might require TLS access within the thread then this works on at least some target architectures (tested on x86-64), but the NULL TLS pointer is enough to prevent adoption of the thread by thread-db. We do already have some tests in gdb.threads/ that test using raw clone calls, so this isn't the first test in this area. Without this patch in place the new test will trigger the assertion that was the cause of the original bug report, but also triggers a couple of segfaults from within GDB, places where we assume we should have a thread_info available. With the patch in place the test works as expected. I also tested against gdbserver, and that works fine too, though I did need to perform a similar error to warning conversion as I have in GDB. With that done gdbserver testing works fine. There are some more warnings printed by gdbserver that we don't see when doing native GDB testing. The warnings can be found in the gdb.log after running with the native-gdbserver or native-extended-gdbserver boards, and look like this: gdbserver: PID mismatch! Expected 633347, got 633343 gdbserver: Cannot find thread after clone. gdbserver: PID mismatch! Expected 633347, got 633343 gdbserver: PID mismatch! Expected 633347, got 633343 These warnings are just a consequence of gdbserver not using thread-db to manage the threads. Maybe we could/should silence these warnings as gdbserver is still happily managing the threads, just outside of thread-db, but I don't plan to do anything about these right now. Tested on GNU/Linux on x86-64, AArch64, RISC-V, and PPC64le using unix, native-gdbserver, and native-extended-gdbserver boards. Bug: https://bugzilla.redhat.com/show_bug.cgi?id=2414004 --- gdb/linux-nat.c | 25 +- gdb/linux-thread-db.c | 18 +- gdb/testsuite/gdb.threads/clone-bad-tls.c | 193 +++++++++++++ gdb/testsuite/gdb.threads/clone-bad-tls.exp | 294 ++++++++++++++++++++ gdbserver/thread-db.cc | 14 +- 5 files changed, 525 insertions(+), 19 deletions(-) create mode 100644 gdb/testsuite/gdb.threads/clone-bad-tls.c create mode 100644 gdb/testsuite/gdb.threads/clone-bad-tls.exp diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c index 1d0a4609a3a..bdb948aebaf 100644 --- a/gdb/linux-nat.c +++ b/gdb/linux-nat.c @@ -1971,15 +1971,22 @@ linux_nat_target::follow_clone (ptid_t child_ptid) lwp_info *new_lp = add_lwp (child_ptid); new_lp->stopped = 1; - /* If the thread_db layer is active, let it record the user - level thread id and status, and add the thread to GDB's - list. */ - if (!thread_db_notice_clone (inferior_ptid, new_lp->ptid)) - { - /* The process is not using thread_db. Add the LWP to - GDB's list. */ - add_thread (linux_target, new_lp->ptid); - } + /* If the thread_db layer is active, let it record the user level thread + id and status, and add the thread to GDB's list. */ + { + /* If the thread_db layer fails to record the thread, including if it + throws an error, then we should make sure GDB always adds the thread + to its data structures otherwise lots of things can go wrong. For + example, GDB will not resume the thread, or if/when the thread + exits, GDB will be surprised and raise an assertion. */ + using scoped_add_thread = FORWARD_SCOPE_EXIT (add_thread); + scoped_add_thread add_thread_fallback (linux_target, new_lp->ptid); + + /* If the thread_db layer successfully adopts the thread then we no + longer need our fallback to add the thread for us. */ + if (thread_db_notice_clone (inferior_ptid, new_lp->ptid)) + add_thread_fallback.release (); + } /* We just created NEW_LP so it cannot yet contain STATUS. */ gdb_assert (new_lp->status == 0); diff --git a/gdb/linux-thread-db.c b/gdb/linux-thread-db.c index 1807352ed76..1ae9323108a 100644 --- a/gdb/linux-thread-db.c +++ b/gdb/linux-thread-db.c @@ -413,13 +413,19 @@ thread_from_lwp (thread_info *stopped, ptid_t ptid) err = info->td_ta_map_lwp2thr_p (info->thread_agent, ptid.lwp (), &th); if (err != TD_OK) - error (_("Cannot find user-level thread for LWP %ld: %s"), - ptid.lwp (), thread_db_err_str (err)); + { + warning (_("Cannot find user-level thread for LWP %ld: %s"), + ptid.lwp (), thread_db_err_str (err)); + return nullptr; + } err = info->td_thr_get_info_p (&th, &ti); if (err != TD_OK) - error (_("thread_get_info_callback: cannot get thread info: %s"), - thread_db_err_str (err)); + { + warning (_("thread_get_info_callback: cannot get thread info: %s"), + thread_db_err_str (err)); + return nullptr; + } /* Fill the cache. */ tp = stopped->inf->process_target ()->find_thread (ptid); @@ -450,8 +456,8 @@ thread_db_notice_clone (ptid_t parent, ptid_t child) thread_info *parent_info = thread_from_lwp (stopped, parent); gdb_assert (parent_info == stopped); - thread_from_lwp (stopped, child); - return true; + thread_info *child_info = thread_from_lwp (stopped, child); + return child_info != nullptr; } static void * diff --git a/gdb/testsuite/gdb.threads/clone-bad-tls.c b/gdb/testsuite/gdb.threads/clone-bad-tls.c new file mode 100644 index 00000000000..dfb3ff79c17 --- /dev/null +++ b/gdb/testsuite/gdb.threads/clone-bad-tls.c @@ -0,0 +1,193 @@ +/* This testcase is part of GDB, the GNU debugger. + + 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 . + + Test that GDB doesn't lose an event for a thread it didn't know + about, until an event is reported for it. */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Global synchronization variables. */ +pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +int ready = 0; + +#define STACK_SIZE 0x1000 + +/* Wrap futex syscall. See 'man 2 futex'. */ + +static int +futex (int *uaddr, int futex_op, int val, const struct timespec *timeout, + int *uaddr2, int val3) +{ + return syscall (SYS_futex, uaddr, futex_op, val, timeout, uaddr2, val3); +} + +/* Function to run in the raw clone thread. This just spins until the + integer flag pointed to by ARG is set to non-zero. */ + +static int +clone_fn (void *arg) +{ + int *thread_exit = (int *) arg; /* Break inside raw thread. */ + *thread_exit = 0; + + while (*thread_exit == 0) + ; +} + +/* A variable into which the kernel will write the child thread-id. This + will be cleared when the thread exits. This only gets used when + USE_FUTEX is defined. */ + +static int thread_tid; + +/* Create a thread using a raw clone call. */ + +void * +do_raw_clone () +{ + unsigned char *stack; + int res; + int clone_pid; + + /* This flag is shared with the raw thread. It is initially -1, then + set to 0 in the raw thread to show that the thread has started up. + This flag is then set to 1 by the main thread to indicate that the + raw thread should exit. Using a volatile for thread synchronisation + is not great, but this avoids having to make library calls from the + raw thread, which might trigger a need for TLS to be setup correctly + on some targets. */ + volatile int thread_exit = -1; + + stack = malloc (STACK_SIZE); + assert (stack != NULL); /* Break before raw thread created. */ + +#ifdef USE_FUTEX +#define TID_FLAGS (CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID) +#else +#define TID_FLAGS (0) +#endif + +#define CLONE_FLAGS (CLONE_THREAD | CLONE_SIGHAND | CLONE_VM \ + | CLONE_SETTLS | TID_FLAGS) + + clone_pid = clone (clone_fn, stack + STACK_SIZE, CLONE_FLAGS, + (void *) &thread_exit, &thread_tid, + NULL, &thread_tid); + + assert (clone_pid > 0); /* Immediately after the clone. */ + + while (thread_exit != 0) + usleep (1000); + + /* Trigger the clone thread to exit. */ + thread_exit = 1; /* Break after raw thread created. */ + +#ifdef USE_FUTEX + /* In this mode we rely on the futex to notify us when the thread has + exited. In a broken GDB we used to deadlock at this point as GDB + would fail to restart the raw thread, and so the kernel would never + wake this futex. */ + while (thread_tid != 0) + futex (&thread_tid, FUTEX_WAIT, clone_pid, NULL, NULL, 0); + + /* We do know that the raw thread has completed at this point, so we + could free its stack. We don't though, just to be consistent with the + no futex path. This doesn't really matter, this is just a small + test. */ +#else + /* There's no attempt to synchronise with the raw clone thread on this + path. In a broken GDB the raw thread might not be resumed, in which + case this timeout will expire. */ + sleep (2); + + /* We cannot be sure that the raw thread has finished by this point, so + we cannot free the stack. This isn't critical, this is just a small + test case. */ +#endif + + return NULL; /* Break after raw thread exits. */ +} + +/* Something for our pthread thread to do. This just blocks until the main + thread releases it, at which point this thread will exit. */ + +void * +worker_thread (void *arg) +{ + pthread_mutex_lock(&mutex); + + /* Let the main thread know we are live by clearing the ready flag. */ + ready = 0; + pthread_cond_signal(&cond); + + /* Now spin until the main thread sets this flag back to non-zero. */ + while (ready == 0) + { + /* The thread will block here until main signals 'cond' */ + pthread_cond_wait (&cond, &mutex); + } + + pthread_mutex_unlock (&mutex); + + return NULL; +} + +int +main (void) +{ + pthread_t thread_id; + volatile int flag = 0; + int res; + + /* The pthread will set the READY flag back to zero. */ + ready = 1; + + alarm (300); + + res = pthread_create (&thread_id, NULL, worker_thread, (void *)&flag); + assert (res == 0); + + /* Wait for the pthread to set READY to zero. */ + pthread_mutex_lock(&mutex); + while (ready == 1) + pthread_cond_wait (&cond, &mutex); + pthread_mutex_unlock (&mutex); + + /* Create a thread using a raw clone call. */ + do_raw_clone (); /* Break before do_raw_clone. */ + + /* Unblock the pthread. */ + pthread_mutex_lock (&mutex); + ready = 1; + pthread_cond_signal (&cond); + pthread_mutex_unlock (&mutex); + + /* Wait for the worker to finish. */ + pthread_join (thread_id, NULL); + + return 0; +} diff --git a/gdb/testsuite/gdb.threads/clone-bad-tls.exp b/gdb/testsuite/gdb.threads/clone-bad-tls.exp new file mode 100644 index 00000000000..2de16c63b6e --- /dev/null +++ b/gdb/testsuite/gdb.threads/clone-bad-tls.exp @@ -0,0 +1,294 @@ +# This testcase is part of GDB, the GNU debugger. + +# 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 . + +# This test creates a raw thread using a clone() call without going +# through the pthread library. Further, the thread that is created +# deliberately sets its TLS pointer to NULL. This used to cause +# problems for GDB as GDB would fail to recognize the new thread, +# which means no thread_info would be created, which would lead to +# segfaults and assertion failures. +# +# When running this test on a remote target we do see some warnings +# from gdbserver about failure to find the raw thread. This is +# because the thread is never owned by thread-db. In a GDB only world +# we don't warn about such threads, we just silently handle them. +# Maybe we should do the same in gdbserver? For now though, we just +# ignore the warnings. Functionally, gdbserver handles the raw thread +# just fine, it just gives a warning each time we try to look it up in +# thread-db (and fail). + +# This only works on targets with the Linux kernel, and the source +# makes use of the clone call, which has a different API on IA64. +require {!istarget "ia64-*-*"} +require {istarget "*-*-linux*"} + +standard_testfile + +# When debugging on a remote target GDB sees the thread as a full +# thread, so we get the 'Thread ...' type message. When using the +# native linux target within GDB, as this thread is not owned by +# thread-db we get a 'LWP ...' type message. Setup a global to be +# used in the test patterns below. +if {[gdb_protocol_is_remote]} { + set raw_thread_re "Thread $::decimal\\.$::decimal" +} else { + set raw_thread_re "LWP $::decimal" +} + +# Restart GDB using TESTFILE, the basename of an executable. Run to +# the function 'do_raw_clone', which is where we start all the tests. +# Then use BREAK_LINE_PATTERN to create a breakpoint on the matching +# line. +proc setup_for_test { testfile break_line_pattern } { + clean_restart $testfile + + # Run until the do_raw_clone function. By this point the pthread + # will have been created. + if {![runto do_raw_clone]} { + return + } + + gdb_breakpoint [gdb_get_line_number $break_line_pattern] +} + +# Use TESTFILE as the basename of the executable to run. Place a +# breakpoint after the creation of a raw thread, in the parent thread, +# not the raw thread. Run until the breakpoint is hit, check we see +# the raw thread announced, and that the thread shows up in the 'info +# threads' output. +proc_with_prefix stop_after_creating_raw_thread { testfile } { + # Start GDB. Run to do_raw_clone. Place a breakpoint after the + # raw thread has been created. + setup_for_test $testfile "Break after raw thread created." + + # Continue until the raw thread has been created. Check we see + # the raw thread announced, and that we hit the expected breakpoint. + set saw_breakpoint_line false + set saw_source_line false + set saw_new_thread_line false + gdb_test_multiple "continue" "" { + -re "^\\\[New $::raw_thread_re \\(id 3\\)\\\]\r\n" { + set saw_new_thread_line true + exp_continue + } + + -re "^Thread 1 \[^\r\n\]+ hit Breakpoint $::decimal, do_raw_clone \\(\\)\[^\r\n\]+\r\n" { + set saw_breakpoint_line true + exp_continue + } + + -re "^$::decimal\\s+\[^\r\n\]+Break after raw thread created\\.\[^\r\n\]+\r\n" { + set saw_source_line true + exp_continue + } + + -re "^$::gdb_prompt $" { + gdb_assert { $saw_breakpoint_line && $saw_source_line \ + && $saw_new_thread_line } $gdb_test_name + } + + -re "^\[^\r\n\]*\r\n" { + exp_continue + } + } + + # Ensure the raw thread shows up in the 'info threads' output. + gdb_test "info threads" \ + "\r\n\\s+3\\s+$::raw_thread_re \[^\r\n\]+ clone_fn \\(arg=$::hex\\) \[^\r\n\]+" + + gdb_test "thread 3" + gdb_test "bt" +} + +# Use TESTFILE as the basename of the executable to run. Place a +# breakpoint within the raw thread function. Run until the breakpoint +# is hit, check we see the raw thread announced, the switch to the raw +# thread, and that the thread shows up in the 'info threads' output. +proc_with_prefix stop_in_raw_thread { testfile } { + setup_for_test $testfile "Break inside raw thread." + + # Continue until the raw thread has been created. Check we see + # the raw thread announced, and that we hit the expected breakpoint. + set saw_breakpoint_line false + set saw_source_line false + set saw_new_thread_line false + set saw_thread_switch false + gdb_test_multiple "continue" "" { + -re "^\\\[New $::raw_thread_re \\(id 3\\)\\\]\r\n" { + set saw_new_thread_line true + exp_continue + } + + -re "^\\\[Switching to $::raw_thread_re\\\]\r\n" { + set saw_thread_switch true + exp_continue + } + + -re "^Thread 3 \[^\r\n\]+ hit Breakpoint $::decimal, clone_fn \\(arg=$::hex\\)\[^\r\n\]+\r\n" { + set saw_breakpoint_line true + exp_continue + } + + -re "^$::decimal\\s+\[^\r\n\]+Break inside raw thread\\.\[^\r\n\]+\r\n" { + set saw_source_line true + exp_continue + } + + -re "^$::gdb_prompt $" { + gdb_assert { $saw_breakpoint_line && $saw_source_line \ + && $saw_thread_switch && $saw_new_thread_line } \ + $gdb_test_name + } + + -re "^\[^\r\n\]*\r\n" { + exp_continue + } + } + + # Ensure the raw thread shows up in the 'info threads' output. + gdb_test "info threads" \ + "\r\n\\*\\s+3\\s+$::raw_thread_re \[^\r\n\]+ clone_fn \\(arg=$::hex\\) \[^\r\n\]+" +} + +# Use TESTFILE as the basename of the executable to run. Break before +# the raw thread is created, set scheduler-locking mode on to stop GDB +# setting the raw thread running, then step (using 'next') over the +# creation of the raw thread. Once we have stepped past the clone +# turn scheduler-locking off again and run until the inferior exits, +# we expect to see both the pthread and the raw thread exit. +# +# In broken GDB, in the delay build (no futex) when the inferior +# exits, the raw thread will also exit. GDB knows nothing about the +# raw thread, and an assertion is triggered. +# +# In broken GDB, in futex mode the inferior will deadlock waiting on +# the futex, this is because GDB doesn't know about the raw thread, +# and never set it running again. As such the futex condition +# variable is never cleared, and so the inferior never exits. +# +# This should all now be fixed, GDB should see the raw thread +# correctly, and the inferior should exit in both modes. +proc_with_prefix next_over_raw_thread_creation { testfile } { + setup_for_test $testfile "Break before raw thread created." + + gdb_continue_to_breakpoint "before raw thread created" + + gdb_test_no_output "set scheduler-locking on" + + set saw_thread_announced false + set reached_line_after_clone false + for { set i 0 } { $i < 10 } { incr i } { + gdb_test_multiple "next" "next, $i" { + -re "^\\\[New $::raw_thread_re \\(id 3\\)\\\]\r\n" { + set saw_thread_announced true + exp_continue + } + + -re "^$::decimal\\s+\[^\r\n\]+Immediately after the clone\\.\[^\r\n\]+\r\n" { + set reached_line_after_clone true + exp_continue + } + + -re "^$::gdb_prompt " { + # Nothing. + } + + -re "^\[^\r\n\]*\r\n" { + exp_continue + } + } + + if { $reached_line_after_clone } { + break + } + } + + gdb_assert { $reached_line_after_clone && $saw_thread_announced } \ + "have passed clone and seen raw thread" + + # Ensure the raw thread shows up in the 'info threads' output. + # Due to scheduler-locking the new thread will not have made any + # progress yet. Having 'clone ()' in the expected output might be + # risky; on some targets it's possible this could show up as some + # other function name. + gdb_test "info threads" \ + "\r\n\\s+3\\s+$::raw_thread_re \[^\r\n\]+ clone \\(\\) \[^\r\n\]+" + + gdb_test_no_output "set scheduler-locking off" + + # Run until the inferior exits. We want to do this because if GDB + # failed to track the raw thread, then when the inferior exits the + # raw thread will also exit, and this thread exit event used to + # trigger an assertion in GDB. + set saw_raw_thread_exit false + set saw_pthread_exit false + set saw_inferior_exit false + gdb_test_multiple "continue" "continue to exit" { + -re "^\\\[$::raw_thread_re \\(id 3\\) exited\\\]\r\n" { + set saw_raw_thread_exit true + exp_continue + } + + -re "^\\\[Thread \[^\r\n\]+ \\(id 2\\) exited\\\]\r\n" { + set saw_pthread_exit true + exp_continue + } + + -re "^\\\[Inferior 1 \[^\r\n\]+ exited normally\\\]\r\n" { + set saw_inferior_exit true + exp_continue + } + + -re "^$::gdb_prompt " { + # Remote targets don't send thread exit events for every + # thread when the entire inferior exits. Maybe GDB itself + # should synthesize these events? For now though just + # invert the state of the thread exit flags when testing + # with a remote protocol. + if {[gdb_protocol_is_remote]} { + set saw_raw_thread_exit [expr {!$saw_raw_thread_exit}] + set saw_pthread_exit [expr {!$saw_pthread_exit}] + } + + gdb_assert { $saw_raw_thread_exit && $saw_pthread_exit \ + && $saw_inferior_exit } $gdb_test_name + } + + -re "^\[^\r\n\]*\r\n" { + exp_continue + } + } +} + + +# Run the tests. +foreach_with_prefix mode { delay futex } { + set the_testfile $testfile-$mode + + set flags {debug pthreads} + if { $mode eq "futex" } { + lappend flags "additional_flags=-DUSE_FUTEX" + } + + if {[build_executable "failed to build" $the_testfile $srcfile $flags]} { + return + } + + stop_after_creating_raw_thread $the_testfile + stop_in_raw_thread $the_testfile + next_over_raw_thread_creation $the_testfile +} diff --git a/gdbserver/thread-db.cc b/gdbserver/thread-db.cc index 0bdcda2ced8..b15d5e472a0 100644 --- a/gdbserver/thread-db.cc +++ b/gdbserver/thread-db.cc @@ -178,14 +178,20 @@ find_one_thread (ptid_t ptid) td_err_e err = thread_db->td_ta_map_lwp2thr_p (thread_db->thread_agent, lwpid, &th); if (err != TD_OK) - error ("Cannot get thread handle for LWP %d: %s", - lwpid, thread_db_err_str (err)); + { + warning ("Cannot get thread handle for LWP %d: %s", + lwpid, thread_db_err_str (err)); + return 0; + } td_thrinfo_t ti; err = thread_db->td_thr_get_info_p (&th, &ti); if (err != TD_OK) - error ("Cannot get thread info for LWP %d: %s", - lwpid, thread_db_err_str (err)); + { + warning ("Cannot get thread info for LWP %d: %s", + lwpid, thread_db_err_str (err)); + return 0; + } threads_debug_printf ("Found thread %ld (LWP %d)", (unsigned long) ti.ti_tid, ti.ti_lid);