From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id KQD2E58fJ2rmmzwAWB0awg (envelope-from ) for ; Mon, 08 Jun 2026 16:01:35 -0400 Received: by simark.ca (Postfix, from userid 112) id 4E2511E091; Mon, 08 Jun 2026 16:01:35 -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.3 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham autolearn_force=no version=4.0.1 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 5B3941E091 for ; Mon, 08 Jun 2026 16:01:33 -0400 (EDT) Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 11FFF445759B for ; Mon, 8 Jun 2026 20:01:26 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 11FFF445759B Received: from simark.ca (simark.ca [158.69.221.121]) by sourceware.org (Postfix) with ESMTPS id DF98D4A9E07D for ; Mon, 8 Jun 2026 20:01:01 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org DF98D4A9E07D Authentication-Results: sourceware.org; dmarc=fail (p=none dis=none) header.from=efficios.com Authentication-Results: sourceware.org; spf=fail smtp.mailfrom=efficios.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org DF98D4A9E07D 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=1780948862; cv=none; b=OmF9NyaI8xqtNRMCBBK6OExmSP9SPooam9qo+kGVfysoj4k/5m7iVDoVVP4hkedwEsPb6wZtzwOCUuJ0JGHp1TZy0ewX70rO5yQX5mGiezJ4ZgMRB0vZy4xq11QKYygyboCUbIJ8DTibnOsmFA+VF/atK+gJveCIu8V9Xzd2XM4= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1780948862; c=relaxed/simple; bh=X0zbMRXy/hif1nflq7MSNoAraDl9euyy/SNveY8xsIU=; h=From:To:Subject:Date:Message-ID:MIME-Version; b=E+MDHKlAzLzDIKw6fj+1abH49d+ZTjovjjnmGICwxFJ8yPd6dNBYGjPsVQsALC8ds56/xzEujKxVsStiYE3Pu3pQf4he4kLf4j9adnP+KIjyeoVC9zOjW1fOxz//8cO7c4GEd2taVfChW94jUYU8GAmvf1m+TjgsuX5KVndMzvA= ARC-Authentication-Results: i=1; sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org DF98D4A9E07D Received: by simark.ca (Postfix) id 75A4B1E091; Mon, 08 Jun 2026 16:01:01 -0400 (EDT) From: Simon Marchi To: gdb-patches@sourceware.org Cc: Simon Marchi Subject: [PATCH RESEND v2 01/10] gdb/solib-rocm: assert that host ops isn't rocm_solib_ops Date: Mon, 8 Jun 2026 16:00:25 -0400 Message-ID: <20260608200100.666134-2-simon.marchi@efficios.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260608200100.666134-1-simon.marchi@efficios.com> References: <20260608200100.666134-1-simon.marchi@efficios.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 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 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. 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 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_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 (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 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_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