From: Lancelot SIX <lancelot.six@amd.com>
To: Simon Marchi <simon.marchi@efficios.com>, <gdb-patches@sourceware.org>
Subject: Re: [PATCH v2 1/10] gdb/solib-rocm: assert that host ops isn't rocm_solib_ops
Date: Mon, 6 Jul 2026 18:08:02 +0100 [thread overview]
Message-ID: <6gbkcfk4obf6kj7klfyrxumeatic3fnv3ppdiliu5xonlqecmj@5iy76y22ekzc> (raw)
In-Reply-To: <20260608200100.666134-2-simon.marchi@efficios.com>
On Mon, Jun 08, 2026 at 04:00:25PM -0400, Simon Marchi wrote:
> In some fork cases, the rocm_solib_target_inferior_created observer gets
> called while the child inferior (passed as a parameter) already has a
> rocm_solib_ops installed. Since we unconditionally wrap the existing
> solib_ops with a new rocm_solib_ops, we can end up with a chain of
> multiple rocm_solib_ops, like:
>
> rocm_solib_ops -> rocm_solib_ops -> svr4_solib_ops
>
> I don't think it is technically harmful as of now (unless the process
> does a ton of forks and the rocm_solib_ops accumulate), but it is for
> sure useless. Add an assert for this in the rocm_solib_ops constructor,
> which reveals the cases where this happens.
>
> When a fork happens with follow-fork-mode == child and detach-on-fork
> on, infrun's follow_fork_inferior function directly moves the program
> space from the parent the child inferior, as an optimization. Coming
> into rocm_solib_target_inferior_created, the inferior's pspace
> unexpectedly already has a rocm_solib_ops pushed.
>
> Fix this locally by using an inferior_forked observer. In the scenario
> described above, remove the rocm_solib_ops and restore the host
> solib_ops as the program space's solib_ops, to make it look as if infrun
> didn't do this trick. This requires adding two parameters to the
> inferior_forked observer (detach_on_fork and follow_child).
>
> This should probably be done by infrun directly at some point. The
> logic being that it's fine to do an optimization, but it should look as
> if it didn't occur. If infrun created a brand new pspace for the child,
> there wouldn't be a rocm_solib_ops there already. But I prefer a local
> fix for now.
>
> Finally, there are also the vfork cases, where the child inferior shares
> the program space with its parent, and therefore the child's program
> space already has a rocm_solib_ops installed. Address this case by
> returning early (the `inf->vfork_parent != nullptr` check), because
> there is nothing we want to do for a vfork child anyway.
Hi Simon,
Sorry for the very delayed reply. Given our previous discussions on
list (on the V1), this LGTM, thanks.
Approved-by: Lancelot Six <lancelot.six@amd.com> (amdgpu)
This of course only covers the amdgpu bits.
Best,
Lancelot
>
> Change-Id: I2e76d111e96f1e01b6799b04da9cdd6f6e2984c9
> ---
> gdb/amd-dbgapi-target.c | 3 ++-
> gdb/infrun.c | 3 ++-
> gdb/observable.h | 8 ++++++--
> gdb/solib-rocm.c | 31 +++++++++++++++++++++++++++++++
> 4 files changed, 41 insertions(+), 4 deletions(-)
>
> diff --git a/gdb/amd-dbgapi-target.c b/gdb/amd-dbgapi-target.c
> index d44f03d0b80a..6b2314f7de79 100644
> --- a/gdb/amd-dbgapi-target.c
> +++ b/gdb/amd-dbgapi-target.c
> @@ -2335,7 +2335,8 @@ amd_dbgapi_inferior_execd (inferior *exec_inf, inferior *follow_inf)
>
> static void
> amd_dbgapi_inferior_forked (inferior *parent_inf, inferior *child_inf,
> - target_waitkind fork_kind)
> + target_waitkind fork_kind, bool detach_on_fork,
> + bool follow_child)
> {
> if (child_inf != nullptr)
> {
> diff --git a/gdb/infrun.c b/gdb/infrun.c
> index 22a056084861..2edd6e0445b3 100644
> --- a/gdb/infrun.c
> +++ b/gdb/infrun.c
> @@ -699,7 +699,8 @@ holding the child stopped. Try \"set %ps\" or \"%ps\".\n"),
> target_follow_fork (child_inf, child_ptid, fork_kind, follow_child,
> detach_fork);
>
> - gdb::observers::inferior_forked.notify (parent_inf, child_inf, fork_kind);
> + gdb::observers::inferior_forked.notify (parent_inf, child_inf, fork_kind,
> + detach_fork, follow_child);
>
> /* target_follow_fork must leave the parent as the current inferior. If we
> want to follow the child, we make it the current one below. */
> diff --git a/gdb/observable.h b/gdb/observable.h
> index 9f1c33ba7100..979e9d1c3ace 100644
> --- a/gdb/observable.h
> +++ b/gdb/observable.h
> @@ -92,9 +92,13 @@ extern observable<inferior */* exec_inf */, inferior */* follow_inf */>
> the child (because we follow only the child or we follow both), CHILD_INF
> is the child inferior. Otherwise, CHILD_INF is nullptr.
>
> - FORK_KIND is TARGET_WAITKIND_FORKED or TARGET_WAITKIND_VFORKED. */
> + FORK_KIND is TARGET_WAITKIND_FORKED or TARGET_WAITKIND_VFORKED.
> +
> + DETACH_ON_FORK and FOLLOW_CHILD represent the "detach-on-fork" and
> + "follow-fork-mode" settings. */
> extern observable<inferior */* parent_inf */, inferior */* child_inf */,
> - target_waitkind /* fork_kind */> inferior_forked;
> + target_waitkind /* fork_kind */, bool /* detach_on_fork */,
> + bool /* follow_child */> inferior_forked;
>
> /* The shared library specified by SOLIB has been loaded. Note that
> when gdb calls this observer, the library's symbols probably
> diff --git a/gdb/solib-rocm.c b/gdb/solib-rocm.c
> index 34cb2bb9e57c..dcaa0ee980a3 100644
> --- a/gdb/solib-rocm.c
> +++ b/gdb/solib-rocm.c
> @@ -165,8 +165,14 @@ struct rocm_solib_ops : public solib_ops
> explicit rocm_solib_ops (program_space *pspace, solib_ops_up host_ops)
> : solib_ops (pspace), m_host_ops (std::move (host_ops))
> {
> + gdb_assert (m_host_ops != nullptr);
> + gdb_assert (dynamic_cast<rocm_solib_ops *> (m_host_ops.get ()) == nullptr);
> }
>
> + /* Release the host solib_ops. */
> + solib_ops_up release_host_ops ()
> + { return std::move (m_host_ops); }
> +
> /* The methods implemented by rocm_solib_ops. */
> owning_intrusive_list<solib> current_sos () const override;
> void create_inferior_hook (int from_tty) const override;
> @@ -820,6 +826,10 @@ rocm_update_solib_list ()
> static void
> rocm_solib_target_inferior_created (inferior *inf)
> {
> + /* A vfork child shares its pspace with its parent, do not touch anything. */
> + if (inf->vfork_parent != nullptr)
> + return;
> +
> get_solib_info (inf)->solib_list.clear ();
>
> auto prev_ops = inf->pspace->release_solib_ops ();
> @@ -851,6 +861,24 @@ rocm_solib_target_inferior_execd (inferior *exec_inf, inferior *follow_inf)
> get_solib_info (exec_inf)->solib_list.clear ();
> }
>
> +static void
> +rocm_solib_target_inferior_forked (inferior *parent_inf, inferior *child_inf,
> + target_waitkind fork_kind,
> + bool detach_on_fork, bool follow_child)
> +{
> + if (detach_on_fork && follow_child && fork_kind == TARGET_WAITKIND_FORKED)
> + {
> + /* In this particular configuration, infrun's follow_fork_inferior
> + function moves the parent pspace to the child directly. Remove the
> + existing rocm_solib_ops from the child and restore the host solib_ops,
> + to make it look like a brand new pspace. */
> + auto rocm_ops_holder = child_inf->pspace->release_solib_ops ();
> + auto rocm_ops
> + = gdb::checked_static_cast<rocm_solib_ops *> (rocm_ops_holder.get ());
> + child_inf->pspace->set_solib_ops (rocm_ops->release_host_ops ());
> + }
> +}
> +
> INIT_GDB_FILE (rocm_solib)
> {
> /* The dependency on the amd-dbgapi exists because solib-rocm's
> @@ -864,4 +892,7 @@ INIT_GDB_FILE (rocm_solib)
> gdb::observers::inferior_execd.attach
> (rocm_solib_target_inferior_execd, "solib-rocm",
> { &get_amd_dbgapi_target_inferior_execd_observer_token () });
> +
> + gdb::observers::inferior_forked.attach
> + (rocm_solib_target_inferior_forked, "solib-rocm");
> }
> --
> 2.54.0
next prev parent reply other threads:[~2026-07-06 17:10 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-08 20:00 [PATCH RESEND v2 00/10] Multiple solib_ops in a program_space Simon Marchi
2026-06-08 20:00 ` [PATCH RESEND v2 01/10] gdb/solib-rocm: assert that host ops isn't rocm_solib_ops Simon Marchi
2026-07-06 17:08 ` Lancelot SIX [this message]
2026-06-08 20:00 ` [PATCH RESEND v2 02/10] gdb/solib-rocm: pass reference to cache to rocm_code_object_stream_file Simon Marchi
2026-06-08 20:00 ` [PATCH RESEND v2 03/10] gdb/solib-rocm: add cached_target_fd to manage cached fd lifetime Simon Marchi
2026-07-06 17:08 ` [PATCH v2 3/10] " Lancelot SIX
2026-07-07 20:48 ` Simon Marchi
2026-06-08 20:00 ` [PATCH RESEND v2 04/10] gdb: de-constify some methods of solib_ops Simon Marchi
2026-07-06 17:09 ` [PATCH v2 4/10] " Lancelot SIX
2026-06-08 20:00 ` [PATCH RESEND v2 05/10] gdb/solib-rocm: move per-inferior data to rocm_solib_ops Simon Marchi
2026-07-06 17:09 ` [PATCH v2 5/10] " Lancelot SIX
2026-07-08 16:08 ` Simon Marchi
2026-06-08 20:00 ` [PATCH RESEND v2 06/10] gdb/solib-rocm: save inferior in rocm_solib_ops Simon Marchi
2026-07-06 17:10 ` [PATCH v2 6/10] " Lancelot SIX
2026-06-08 20:00 ` [PATCH RESEND v2 07/10] gdb/solib: add remove_solib function Simon Marchi
2026-06-08 20:00 ` [PATCH RESEND v2 08/10] gdb: add objfile -> solib backlink Simon Marchi
2026-06-08 20:00 ` [PATCH RESEND v2 09/10] gdb: change default objfile iteration order to start with current objfile Simon Marchi
2026-06-08 20:00 ` [PATCH RESEND v2 10/10] gdb: multiple solib_ops per program space Simon Marchi
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=6gbkcfk4obf6kj7klfyrxumeatic3fnv3ppdiliu5xonlqecmj@5iy76y22ekzc \
--to=lancelot.six@amd.com \
--cc=gdb-patches@sourceware.org \
--cc=simon.marchi@efficios.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