From: Matthieu Longo <matthieu.longo@arm.com>
To: Simon Marchi <simark@simark.ca>, gdb-patches@sourceware.org
Cc: Luis Machado <luis.machado@amd.com>,
Luis Machado <luis.machado.foss@gmail.com>,
Andrew Burgess <aburgess@redhat.com>,
Yury Khrustalev <yury.khrustalev@arm.com>,
Pedro Alves <pedro@palves.net>, Tom Tromey <tom@tromey.com>
Subject: Re: [PATCH v1 02/10] gdb: rely on the first alive thread TPID when reading Linux procfs files
Date: Tue, 14 Jul 2026 16:47:08 +0100 [thread overview]
Message-ID: <33309d7c-ecd0-470b-9ece-f767b425fcbd@arm.com> (raw)
In-Reply-To: <590655c1-abed-4a16-b8cc-762f1d8e6093@simark.ca>
On 09/07/2026 15:24, Simon Marchi wrote:
>
>
> On 2026-07-07 11:48, Matthieu Longo wrote:
>> On Linux, /proc/<pid> is keyed by the thread-group leader PID. When
>> the leader has exited, some /proc/<pid>/... 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.
>
Fixed in the next revision.
> 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.
>
I proposed this comment:
/* Return the first non-exited thread of this inferior.
This is only a best-effort choice of a thread that is expected to still
exist in the target. A thread may have exited after GDB last updated its
thread list, or GDB/gdbserver may have observed the exit but not yet
propagated it through all layers. Therefore the returned thread is not
guaranteed to still be alive when it is later accessed. This avoids the
common case where the current thread has exited, but callers must still be
prepared for the selected thread to no longer exist. */
ptid_t first_non_exited_thread () const;
> 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/<tid>/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
> <pid>", and then the line right below it (Process with a capital P),
> which comes from /proc/<tid>/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 <pid>" line that we
> print to indicate which thread we obtained the information from, in the
> "auto-select a thread" case.
>
Indeed it might be confusing, but still better than nothing at all.
I propose the following change to the line printing the process ID.
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index 86532e1e0d3..b11473fd22d 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -875,7 +875,14 @@ linux_info_proc (struct gdbarch *gdbarch, const char *args,
if (args && args[0])
error (_("Too many parameters: %s"), args);
- gdb_printf (_("process %d\n"), ptid.pid ());
+ thread_info *thr = inferior_thread ();
+ if (thr->ptid == ptid)
+ gdb_printf (_("process %d\n"), ptid.pid ());
+ else
+ gdb_printf (_("process %d [Note: information where gathered from LWP %ld " \
+ "as the thread-group leader (LWP=%ld) already exited.]\n"),
+ thr->ptid.pid (), ptid.lwp (), thr->ptid.lwp ());
+
if (cmdline_f)
{
xsnprintf (filename, sizeof filename, "/proc/%ld/cmdline", ptid.lwp ());
Output before the thread-group leader exists:
process 814
Output for any info proc commands after the thread-group leader exited:
process 814 [Note: information where gathered from LWP 816 as the thread-group leader (LWP=814)
already exited.]
> 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?
>
Yes, it should. Fixed in the next revision.
> And linux_address_in_shadow_stack_mem_range too?
>
Fixed in the revision.
> 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.
>
Please have a look at patch 5/10. There might be something to do there.
For now, I will try to keep the change to the minimum needed.
>> 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/<pid> is keyed by the thread-group leader PID. When the
>> + leader has exited, some /proc/<pid>/... 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.
>
See previous comment above.
> 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.
>
Fixed in the next revision.
> I would prefer if you renamed first_alive_thread to
> first_non_exited_thread, that's the terminology we use elsewhere.
Fixed in the next revision.
> "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
Matthieu
next prev parent reply other threads:[~2026-07-14 15:48 UTC|newest]
Thread overview: 66+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-07 15:48 [PATCH v1 00/10] gdb: bugfix 31207 and various refactoring in linux-tdep Matthieu Longo
2026-07-07 15:48 ` [PATCH v1 01/10] gdb/linux-tdep: change linux_fill_prpsinfo to return bool Matthieu Longo
2026-07-09 6:26 ` Thiago Jung Bauermann
2026-07-09 12:23 ` Simon Marchi
2026-07-27 14:38 ` Matthieu Longo
2026-07-07 15:48 ` [PATCH v1 02/10] gdb: rely on the first alive thread TPID when reading Linux procfs files Matthieu Longo
2026-07-09 6:29 ` Thiago Jung Bauermann
2026-07-13 9:11 ` Matthieu Longo
2026-07-09 14:24 ` Simon Marchi
2026-07-14 15:47 ` Matthieu Longo [this message]
2026-07-07 15:48 ` [PATCH v1 03/10] target_fileio_read_stralloc: add an optional length parameter Matthieu Longo
2026-07-09 6:30 ` Thiago Jung Bauermann
2026-07-13 15:26 ` Matthieu Longo
2026-07-24 2:50 ` Thiago Jung Bauermann
2026-07-27 14:52 ` Matthieu Longo
2026-07-29 1:57 ` Thiago Jung Bauermann
2026-07-21 21:28 ` Luis
2026-07-27 14:48 ` Matthieu Longo
2026-07-27 14:53 ` Matthieu Longo
2026-07-07 15:48 ` [PATCH v1 04/10] gdb support: add gdb::replace algorithm for iterators and ranges Matthieu Longo
2026-07-09 6:30 ` Thiago Jung Bauermann
2026-07-10 21:21 ` Kevin Buettner
2026-07-13 15:51 ` Matthieu Longo
2026-07-21 21:33 ` Luis
2026-07-27 14:58 ` Matthieu Longo
2026-07-07 15:48 ` [PATCH v1 05/10] gdb: introduce helper class file_reader_t Matthieu Longo
2026-07-09 6:33 ` Thiago Jung Bauermann
2026-07-13 17:17 ` Matthieu Longo
2026-07-10 21:43 ` Kevin Buettner
2026-07-13 16:31 ` Matthieu Longo
2026-07-13 15:50 ` Schimpe, Christina
2026-07-13 17:12 ` Matthieu Longo
2026-07-22 16:36 ` Joos, Christina
2026-07-27 15:13 ` Matthieu Longo
2026-07-07 15:48 ` [PATCH v1 06/10] gdb/linux-tdep: migrate linux_info_proc to file_reader_t Matthieu Longo
2026-07-09 6:35 ` Thiago Jung Bauermann
2026-07-13 17:20 ` Matthieu Longo
2026-07-21 21:43 ` Luis
2026-07-27 17:11 ` Matthieu Longo
2026-07-07 15:48 ` [PATCH v1 07/10] gdb/linux-tdep: migrate linux_find_memory_regions_full " Matthieu Longo
2026-07-09 6:36 ` Thiago Jung Bauermann
2026-07-14 8:40 ` Matthieu Longo
2026-07-24 2:51 ` Thiago Jung Bauermann
2026-07-21 21:47 ` Luis
2026-07-27 17:14 ` Matthieu Longo
2026-07-07 15:48 ` [PATCH v1 08/10] gdb/linux-tdep: migrate parse_smaps_data " Matthieu Longo
2026-07-09 6:41 ` Thiago Jung Bauermann
2026-07-14 8:49 ` Matthieu Longo
2026-07-24 2:52 ` Thiago Jung Bauermann
2026-07-21 21:49 ` Luis
2026-07-27 17:17 ` Matthieu Longo
2026-07-07 15:48 ` [PATCH v1 09/10] gdb/linux-tdep: parse ProtectionKey in /proc/PID/smaps Matthieu Longo
2026-07-09 6:42 ` Thiago Jung Bauermann
2026-07-14 9:12 ` Matthieu Longo
2026-07-14 9:29 ` Matthieu Longo
2026-07-24 2:58 ` Thiago Jung Bauermann
2026-07-24 10:27 ` Yury Khrustalev
2026-07-25 6:40 ` Thiago Jung Bauermann
2026-07-27 8:22 ` Yury Khrustalev
2026-07-29 1:10 ` Thiago Jung Bauermann
2026-07-21 21:57 ` Luis
2026-07-27 17:54 ` Matthieu Longo
2026-07-07 15:49 ` [PATCH v1 10/10] gdb/linux: add helpers to read AT_HWCAP3 and AT_HWCAP4 Matthieu Longo
2026-07-09 6:44 ` Thiago Jung Bauermann
2026-07-21 21:58 ` Luis
2026-07-27 17:32 ` Matthieu Longo
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=33309d7c-ecd0-470b-9ece-f767b425fcbd@arm.com \
--to=matthieu.longo@arm.com \
--cc=aburgess@redhat.com \
--cc=gdb-patches@sourceware.org \
--cc=luis.machado.foss@gmail.com \
--cc=luis.machado@amd.com \
--cc=pedro@palves.net \
--cc=simark@simark.ca \
--cc=tom@tromey.com \
--cc=yury.khrustalev@arm.com \
/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