From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id T7/jIVCvT2oGoQAAWB0awg (envelope-from ) for ; Thu, 09 Jul 2026 10:25:20 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=simark.ca; s=mail; t=1783607120; bh=nMckHTMCsybu1MVsRWM+EdVgWql/IBUkOVmdE27PXOI=; h=Date:Subject:To:Cc:References:From:In-Reply-To:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=vyJHwoN0w1YoWV9JWOaIzT2UvM+jbaRb/97dIhvgmHWVYVFcf19Ete+S/9NI9TL++ PmyoFVtARwbQmBxsJRpYvG+pKY/1YRFj5iTz4SQse0s5g3rpmCWzqjOjupo3visE/j xqOCWgBbt2IiMMO8EEAvyU1X8LA5prlOHeaGBJpc= Received: by simark.ca (Postfix, from userid 112) id 777F61E0A3; Thu, 09 Jul 2026 10:25:20 -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.4 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED autolearn=ham autolearn_force=no version=4.0.1 Authentication-Results: simark.ca; dkim=pass (1024-bit key; unprotected) header.d=simark.ca header.i=@simark.ca header.a=rsa-sha256 header.s=mail header.b=kdOzPN7Q; dkim-atps=neutral Received: from vm01.sourceware.org (vm01.sourceware.org [38.145.34.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 9D9A81E070 for ; Thu, 09 Jul 2026 10:25:19 -0400 (EDT) Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 6BE2C4BA23DE for ; Thu, 9 Jul 2026 14:25:12 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 6BE2C4BA23DE Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=simark.ca header.i=@simark.ca header.a=rsa-sha256 header.s=mail header.b=kdOzPN7Q Received: from simark.ca (simark.ca [158.69.221.121]) by sourceware.org (Postfix) with ESMTPS id 284FE4BA2E12 for ; Thu, 9 Jul 2026 14:24:48 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 284FE4BA2E12 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=simark.ca Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=simark.ca ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 284FE4BA2E12 Authentication-Results: sourceware.org; arc=none smtp.remote-ip=158.69.221.121 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1783607088; cv=none; b=VO+5nzoBWx22TGstE+5v4vmTlvThY7W9XIBpkgbvGIHoDXYKvmNovnr22HbbPmW78kqB5MZAQsSOKTnu4pM+wWQmGL7WQRMiV+CDjdeguS94NG3+FZLgvc9/fhrVvffCxuK+vAixf7IkAAxb2O4fI0vgPlPcGk1439IS9lIqNr8= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1783607088; c=relaxed/simple; bh=nMckHTMCsybu1MVsRWM+EdVgWql/IBUkOVmdE27PXOI=; h=DKIM-Signature:Message-ID:Date:MIME-Version:Subject:To:From; b=EnAW8lShINX6pFhhgR4cpQ6Jge3Q2GcFpmCujL20z0pNnCqRCPYm1NJ2RTV2Tby+N0bBEhWdUVXAJv3ZJ6IVLZQDN7HN6CLrnAxVkjU1CkCWAyUqk9URuzSSCXmFcXiotLqQqqt49Tfakz+DDUqTLk0XP3xlNNlQPNoG5tinC9A= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=simark.ca header.i=@simark.ca header.a=rsa-sha256 header.s=mail header.b=kdOzPN7Q DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 284FE4BA2E12 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=simark.ca; s=mail; t=1783607086; bh=nMckHTMCsybu1MVsRWM+EdVgWql/IBUkOVmdE27PXOI=; h=Date:Subject:To:Cc:References:From:In-Reply-To:From; b=kdOzPN7QC1cTi8Pb/YLAXY8zPAkcAFep1bsWsc2aTR4d1JhTR8JjOD7X2xbSr7YE+ hNiit4y/LpfSPbBlQyRQyQEQQG3OVwNns1eIwM1UQrB+qUangkr0GBjQkZgz9mWKS3 PAtGFzw16PVuL6XEmxj3snZbDKDwaUO3q8brY+mM= Received: by simark.ca (Postfix) id 41D7E1E070; Thu, 09 Jul 2026 10:24:46 -0400 (EDT) Message-ID: <590655c1-abed-4a16-b8cc-762f1d8e6093@simark.ca> Date: Thu, 9 Jul 2026 10:24:45 -0400 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: [PATCH v1 02/10] gdb: rely on the first alive thread TPID when reading Linux procfs files To: Matthieu Longo , gdb-patches@sourceware.org Cc: Luis Machado , Luis Machado , Andrew Burgess , Yury Khrustalev , Pedro Alves , Tom Tromey References: <20260707154900.94542-1-matthieu.longo@arm.com> <20260707154900.94542-3-matthieu.longo@arm.com> Content-Language: en-US From: Simon Marchi In-Reply-To: <20260707154900.94542-3-matthieu.longo@arm.com> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit 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 On 2026-07-07 11:48, Matthieu Longo wrote: > On Linux, /proc/ is keyed by the thread-group leader PID. When > the leader has exited, some /proc//... entries become unavailable > even though another thread is still alive. This can happen, for instance, > when the main thread calls pthread_exit() and another thread continues > the execution (existing test: gcore-stale-thread). > > This causes GDB to fail to read procfs entries such as cmdline, cwd, > exe, maps, and smaps when it uses 'current_inferior ()->pid' after the > thread-group leader has exited. > > Fix this by adding inferior::first_alive_thread(), which returns the > PTID of the first non-exited thread of the inferior. Use its LWP ID > when accessing procfs entries that only need a representative live LWP > belonging to the process. > > Update linux_info_proc, linux_process_address_in_memtag_page, and > linux_find_memory_regions_full to use this live-thread LWP ID instead > of the inferior PID when constructing procfs paths. First comment, can we have a test for this? I think it would be straightforward to write. This is an improvement, but I can still imagine some cases it would fail. A thread could have exited, gdb (or gdbserver) could have reaped it status already, but the information might not have made it all the way to the core yet. So the "first alive thread" you select might not actually be alive on the system. I can't think of a way to fix that problem generally, especially in the remote case. If GDB checks in advance "is this thread alive" and then tries to access is, I feel like there will always be a TOCTOU problem. I'm not opposed to merging a simple fix like this that takes care of the most obvious cases (the main thread has exited, all threads are stopped, and it obviously doesn't work). But I think we should capture the shortcomings we know about as comments in the code. Then, I wondered if everything we access through /proc is going to give the same response when we access them through another thread than the leader. I asked ChatGPT for a summary: Entry Scope Notes ----------------- ---------------- -------------------------------------- cmdline Process-wide Same for all threads; comes from the shared address space (mm_struct). cwd Per-thread Usually shared, but can differ if threads use unshare(CLONE_FS). environ Process-wide Same for all threads; comes from the shared address space (mm_struct). exe Process-wide Same executable for all threads. maps Process-wide Describes the shared address space (mm_struct); same for all threads. status Mixed Contains both per-thread fields (Pid, State, SigPnd, etc.) and thread-group fields (VmSize, Threads, etc.). stat Per-thread Describes the specific task (/proc//stat). smaps Process-wide Same mappings as maps; based on the shared address space. coredump_filter Process-wide Stored in the shared memory descriptor; same for all threads. For most of the info it should be fine, as they are shared between all threads. For cwd, it's shared unless some threads call `unshared(CLONE_FS)`, I don't know if it's common to do that. For stat and status it looks a bit odd, because we print "process ", and then the line right below it (Process with a capital P), which comes from /proc//stat, gives a different number. (gdb) info proc stat process 1989928 Process: 1991838 Exec file: a.out State: t Parent process: 1989898 Process group: 1989928 Session id: 126340 ... In any case, we could perhaps improve the "process " line that we print to indicate which thread we obtained the information from, in the "auto-select a thread" case. Finally, linux_fill_prpsinfo still uses the ptid.pid(): pid = inferior_ptid.pid (); xsnprintf (filename, sizeof (filename), "/proc/%d/cmdline", (int) pid); Should it be changed too? And linux_address_in_shadow_stack_mem_range too? Perhaps it would be useful to have a function "read me a whole file from /proc" that takes an `inferior *` and returns a string, encapsulating the logic of finding a thread to read from. > diff --git a/gdb/inferior.h b/gdb/inferior.h > index 9c031035a23..305b1d31830 100644 > --- a/gdb/inferior.h > +++ b/gdb/inferior.h > @@ -513,6 +513,15 @@ class inferior : public refcounted_object, > /* Find (non-exited) thread PTID of this inferior. */ > thread_info *find_thread (ptid_t ptid); > > + /* Return the first (non-exited) thread PTID of this inferior. > + > + This method should be used in place of current_inferior ()->pid for any > + features relying only on the PID like the reading of procfs files. > + On Linux, /proc/ is keyed by the thread-group leader PID. When the > + leader has exited, some /proc//... entries become unavailable even > + though another thread is still alive. */ > + ptid_t first_alive_thread () const; I think this comment is too specific to Linux and the problem at hand in particular for this location. It should just say "return the first non-exited thread of the inferior" or something like that. Function any_thread_of_inferior already does more or less what you want, but it prefers the currently selected thread, which might not be what we want (we perhaps want to prefer the leader). That function could be renamed to any_non_exited_thread_of_inferior to be clearer. I would prefer if you renamed first_alive_thread to first_non_exited_thread, that's the terminology we use elsewhere. "live" makes me think of the "target_thread_alive" target function, which actually pokes the target to see if the thread is alive right now, that's different. Simon