From patchwork Mon Apr 3 18:52:02 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Marchi X-Patchwork-Id: 67232 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 4BFA3385843A for ; Mon, 3 Apr 2023 18:53:47 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 4BFA3385843A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1680548027; bh=VR6B96UTlVGNG4OrVU+d97DvRHXa6r65rpgnGEjIPSc=; h=To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=Wg7BepYUf9Qwi7qyK3pJumIBKRXxViTDNYVkFPJTjD8r/+R+Nojrb0xfast3LnIbf bZJO8mBvLDPpri925uFKVrpK4lZZ/7Lba5zsAft/V+UckipDSHBNQdnp690EmzyGn8 0Aed35TmYc7LisrfSiBX8jxm2dHFr3M7TWTZEj4I= X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from simark.ca (simark.ca [158.69.221.121]) by sourceware.org (Postfix) with ESMTPS id 0ABAA3858C5E for ; Mon, 3 Apr 2023 18:52:20 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 0ABAA3858C5E Received: from localhost.localdomain (unknown [217.28.27.60]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPSA id 4A8F01E124; Mon, 3 Apr 2023 14:52:19 -0400 (EDT) To: gdb-patches@sourceware.org Cc: Simon Marchi , Pedro Alves Subject: [PATCH 1/7] gdb: pass execing and following inferior to inferior_execd observers Date: Mon, 3 Apr 2023 14:52:02 -0400 Message-Id: <20230403185208.197965-2-simon.marchi@efficios.com> X-Mailer: git-send-email 2.40.0 In-Reply-To: <20230403185208.197965-1-simon.marchi@efficios.com> References: <20230403185208.197965-1-simon.marchi@efficios.com> MIME-Version: 1.0 X-Spam-Status: No, score=-1173.3 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_NONE, KAM_DMARC_STATUS, SPF_HELO_PASS, SPF_SOFTFAIL, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Simon Marchi via Gdb-patches From: Simon Marchi Reply-To: Simon Marchi Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org Sender: "Gdb-patches" The upcoming patch to support exec in the amd-dbgapi target needs to detach amd-dbgapi from the inferior doing the exec and attach amd-dbgapi to the inferior continuing the execution. They may or may not be the same, depending on the `set follow-exec-mode` setting. But even if they are the same, we need to do the detach / attach dance. With the current observable signature, the observers only receive the inferior in which execution continues (the "following" inferior). Change the signature to pass both inferiors, and update all existing observers. Change-Id: I259d1ea09f70f43be739378d6023796f2fce2659 Reviewed-By: Pedro Alves --- gdb/infrun.c | 39 +++++++++++++++++++++------------------ gdb/jit.c | 20 ++++++++++++++------ gdb/linux-tdep.c | 10 +++++++++- gdb/observable.h | 8 ++++++-- gdb/solib.c | 3 ++- 5 files changed, 52 insertions(+), 28 deletions(-) diff --git a/gdb/infrun.c b/gdb/infrun.c index 87141117dfe3..c95a8e7ee1da 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -1293,7 +1293,8 @@ follow_exec (ptid_t ptid, const char *exec_file_target) previous incarnation of this process. */ no_shared_libraries (nullptr, 0); - struct inferior *inf = current_inferior (); + inferior *execing_inferior = current_inferior (); + inferior *following_inferior; if (follow_exec_mode_string == follow_exec_mode_new) { @@ -1304,19 +1305,19 @@ follow_exec (ptid_t ptid, const char *exec_file_target) inferior's pid. Having two inferiors with the same pid would confuse find_inferior_p(t)id. Transfer the terminal state and info from the old to the new inferior. */ - inferior *new_inferior = add_inferior_with_spaces (); - - swap_terminal_info (new_inferior, inf); - exit_inferior_silent (inf); + following_inferior = add_inferior_with_spaces (); - new_inferior->pid = pid; - target_follow_exec (new_inferior, ptid, exec_file_target); + swap_terminal_info (following_inferior, execing_inferior); + exit_inferior_silent (execing_inferior); - /* We continue with the new inferior. */ - inf = new_inferior; + following_inferior->pid = pid; } else { + /* follow-exec-mode is "same", we continue execution in the execing + inferior. */ + following_inferior = execing_inferior; + /* The old description may no longer be fit for the new image. E.g, a 64-bit process exec'ed a 32-bit process. Clear the old description; we'll read a new one below. No need to do @@ -1324,18 +1325,20 @@ follow_exec (ptid_t ptid, const char *exec_file_target) around (its description is later cleared/refetched on restart). */ target_clear_description (); - target_follow_exec (inf, ptid, exec_file_target); } - gdb_assert (current_inferior () == inf); - gdb_assert (current_program_space == inf->pspace); + target_follow_exec (following_inferior, ptid, exec_file_target); + + gdb_assert (current_inferior () == following_inferior); + gdb_assert (current_program_space == following_inferior->pspace); /* Attempt to open the exec file. SYMFILE_DEFER_BP_RESET is used because the proper displacement for a PIE (Position Independent Executable) main symbol file will only be computed by solib_create_inferior_hook below. breakpoint_re_set would fail to insert the breakpoints with the zero displacement. */ - try_open_exec_file (exec_file_host.get (), inf, SYMFILE_DEFER_BP_RESET); + try_open_exec_file (exec_file_host.get (), following_inferior, + SYMFILE_DEFER_BP_RESET); /* If the target can specify a description, read it. Must do this after flipping to the new executable (because the target supplied @@ -1345,7 +1348,7 @@ follow_exec (ptid_t ptid, const char *exec_file_target) registers. */ target_find_description (); - gdb::observers::inferior_execd.notify (inf); + gdb::observers::inferior_execd.notify (execing_inferior, following_inferior); breakpoint_re_set (); @@ -1622,15 +1625,15 @@ infrun_inferior_exit (struct inferior *inf) } static void -infrun_inferior_execd (inferior *inf) +infrun_inferior_execd (inferior *exec_inf, inferior *follow_inf) { /* If some threads where was doing a displaced step in this inferior at the moment of the exec, they no longer exist. Even if the exec'ing thread doing a displaced step, we don't want to to any fixup nor restore displaced stepping buffer bytes. */ - inf->displaced_step_state.reset (); + follow_inf->displaced_step_state.reset (); - for (thread_info *thread : inf->threads ()) + for (thread_info *thread : follow_inf->threads ()) thread->displaced_step_state.reset (); /* Since an in-line step is done with everything else stopped, if there was @@ -1638,7 +1641,7 @@ infrun_inferior_execd (inferior *inf) thread. */ clear_step_over_info (); - inf->thread_waiting_for_vfork_done = nullptr; + follow_inf->thread_waiting_for_vfork_done = nullptr; } /* If ON, and the architecture supports it, GDB will use displaced diff --git a/gdb/jit.c b/gdb/jit.c index e276b3417a04..e085d5623336 100644 --- a/gdb/jit.c +++ b/gdb/jit.c @@ -1147,7 +1147,10 @@ jit_prepend_unwinder (struct gdbarch *gdbarch) } } -/* Register any already created translations. */ +/* Looks for the descriptor and registration symbols and breakpoints + the registration function. If it finds both, it registers all the + already JITed code. If it has already found the symbols, then it + doesn't try again. */ static void jit_inferior_init (inferior *inf) @@ -1203,10 +1206,7 @@ jit_inferior_init (inferior *inf) } } -/* Looks for the descriptor and registration symbols and breakpoints - the registration function. If it finds both, it registers all the - already JITed code. If it has already found the symbols, then it - doesn't try again. */ +/* inferior_created observer. */ static void jit_inferior_created_hook (inferior *inf) @@ -1214,6 +1214,14 @@ jit_inferior_created_hook (inferior *inf) jit_inferior_init (inf); } +/* inferior_execd observer. */ + +static void +jit_inferior_execd_hook (inferior *exec_inf, inferior *follow_inf) +{ + jit_inferior_init (follow_inf); +} + /* Exported routine to call to re-set the jit breakpoints, e.g. when a program is rerun. */ @@ -1304,7 +1312,7 @@ _initialize_jit () &maintenanceinfolist); gdb::observers::inferior_created.attach (jit_inferior_created_hook, "jit"); - gdb::observers::inferior_execd.attach (jit_inferior_created_hook, "jit"); + gdb::observers::inferior_execd.attach (jit_inferior_execd_hook, "jit"); gdb::observers::inferior_exit.attach (jit_inferior_exit_hook, "jit"); gdb::observers::breakpoint_deleted.attach (jit_breakpoint_deleted, "jit"); diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c index 1fc9cb6faee9..b5eee5e108ce 100644 --- a/gdb/linux-tdep.c +++ b/gdb/linux-tdep.c @@ -244,6 +244,14 @@ invalidate_linux_cache_inf (struct inferior *inf) linux_inferior_data.clear (inf); } +/* inferior_execd observer. */ + +static void +linux_inferior_execd (inferior *exec_inf, inferior *follow_inf) +{ + invalidate_linux_cache_inf (follow_inf); +} + /* Fetch the linux cache info for INF. This function always returns a valid INFO pointer. */ @@ -2789,7 +2797,7 @@ _initialize_linux_tdep () "linux-tdep"); gdb::observers::inferior_appeared.attach (invalidate_linux_cache_inf, "linux-tdep"); - gdb::observers::inferior_execd.attach (invalidate_linux_cache_inf, + gdb::observers::inferior_execd.attach (linux_inferior_execd, "linux-tdep"); add_setshow_boolean_cmd ("use-coredump-filter", class_files, diff --git a/gdb/observable.h b/gdb/observable.h index efd0446e1689..00955cbc876b 100644 --- a/gdb/observable.h +++ b/gdb/observable.h @@ -90,8 +90,12 @@ extern observable<> executable_changed; information on the inferior has been printed. */ extern observable inferior_created; -/* The inferior INF has exec'ed a new executable file. */ -extern observable inferior_execd; +/* The inferior EXEC_INF has exec'ed a new executable file. + + Execution continues in FOLLOW_INF, which may or may not be the same as + EXEC_INF, depending on "set follow-exec-mode". */ +extern observable + inferior_execd; /* The status of process record for inferior inferior in gdb has changed. The process record is started if STARTED is true, and diff --git a/gdb/solib.c b/gdb/solib.c index 09bee497fd6e..16147830ef2c 100644 --- a/gdb/solib.c +++ b/gdb/solib.c @@ -1744,7 +1744,8 @@ _initialize_solib () { gdb::observers::free_objfile.attach (remove_user_added_objfile, "solib"); - gdb::observers::inferior_execd.attach ([] (inferior *inf) + gdb::observers::inferior_execd.attach ([] (inferior *exec_inf, + inferior *follow_inf) { solib_create_inferior_hook (0); }, "solib"); From patchwork Mon Apr 3 18:52:03 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Marchi X-Patchwork-Id: 67226 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 569B438582BC for ; Mon, 3 Apr 2023 18:52:47 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 569B438582BC DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1680547967; bh=Wrwh+4jqe2S3vYx8uf8g5Xw2fTwLn3ARjbpO55bm1mw=; h=To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=i7t/guFx4GMBU/6vVUyAjwXM3Jynf/lAxDH1idif/TPcyjIE30xhI2gIu9fVCmeeS MnJALRiOiuH3leEPRhL3T3jdK7jQYvXPWYn+vUexez+S7GkSVq0InPCb+0pX16Aqju +0xwhmnz7ZmAkQGDzugdodibiOyKthfi0K6NYqzs= X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from simark.ca (simark.ca [158.69.221.121]) by sourceware.org (Postfix) with ESMTPS id 4B1623858C5F for ; Mon, 3 Apr 2023 18:52:20 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 4B1623858C5F Received: from localhost.localdomain (unknown [217.28.27.60]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPSA id AD3471E15D; Mon, 3 Apr 2023 14:52:19 -0400 (EDT) To: gdb-patches@sourceware.org Cc: Simon Marchi , Pedro Alves Subject: [PATCH 2/7] gdb: add inferior_forked observable Date: Mon, 3 Apr 2023 14:52:03 -0400 Message-Id: <20230403185208.197965-3-simon.marchi@efficios.com> X-Mailer: git-send-email 2.40.0 In-Reply-To: <20230403185208.197965-1-simon.marchi@efficios.com> References: <20230403185208.197965-1-simon.marchi@efficios.com> MIME-Version: 1.0 X-Spam-Status: No, score=-1173.2 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_NONE, KAM_DMARC_STATUS, SPF_HELO_PASS, SPF_SOFTFAIL, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Simon Marchi via Gdb-patches From: Simon Marchi Reply-To: Simon Marchi Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org Sender: "Gdb-patches" In the upcoming patch to support fork in the amd-dbgapi target, the amd-dbgapi target will need to be notified of fork events through an observer, to attach itself (attach in the amd-dbgapi sense, not ptrace sense) to the new inferior / process. The reason that this can't be done through target_ops::follow_fork is that the amd-dbgapi target isn't pushed on the inferior's target stack right away. It attaches itself to the process and only pushes itself on its target stack if and when the inferior initializes the ROCm runtime. If an inferior that is not using the ROCm runtime forks, we want to be notified of it, so we can attach to the child, and catch if the child starts using the ROCm runtime. So, add a new observable and notify it in follow_fork_inferior. It will be used later in this series. Change-Id: I67fced5a9cba6d5da72b9c7ea1c8397644ca1d54 Reviewed-By: Pedro Alves --- gdb/infrun.c | 2 ++ gdb/observable.c | 1 + gdb/observable.h | 9 +++++++++ 3 files changed, 12 insertions(+) diff --git a/gdb/infrun.c b/gdb/infrun.c index c95a8e7ee1da..11a788467a8a 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -624,6 +624,8 @@ holding the child stopped. Try \"set detach-on-fork\" or \ target_follow_fork (child_inf, child_ptid, fork_kind, follow_child, detach_fork); + gdb::observers::inferior_forked.notify (parent_inf, child_inf, fork_kind); + /* 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. */ gdb_assert (current_inferior () == parent_inf); diff --git a/gdb/observable.c b/gdb/observable.c index 28249a5ad015..49de89c25e04 100644 --- a/gdb/observable.c +++ b/gdb/observable.c @@ -44,6 +44,7 @@ DEFINE_OBSERVABLE (target_changed); DEFINE_OBSERVABLE (executable_changed); DEFINE_OBSERVABLE (inferior_created); DEFINE_OBSERVABLE (inferior_execd); +DEFINE_OBSERVABLE (inferior_forked); DEFINE_OBSERVABLE (record_changed); DEFINE_OBSERVABLE (solib_loaded); DEFINE_OBSERVABLE (solib_unloaded); diff --git a/gdb/observable.h b/gdb/observable.h index 00955cbc876b..3066cf68f314 100644 --- a/gdb/observable.h +++ b/gdb/observable.h @@ -21,6 +21,7 @@ #define OBSERVABLE_H #include "gdbsupport/observable.h" +#include "target/waitstatus.h" struct bpstat; struct so_list; @@ -97,6 +98,14 @@ extern observable inferior_created; extern observable inferior_execd; +/* The inferior PARENT_INF has forked. If we are setting up an inferior for + 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. */ +extern observable inferior_forked; + /* The status of process record for inferior inferior in gdb has changed. The process record is started if STARTED is true, and the process record is stopped if STARTED is false. From patchwork Mon Apr 3 18:52:04 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Marchi X-Patchwork-Id: 67229 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id E5793385022D for ; Mon, 3 Apr 2023 18:53:18 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org E5793385022D DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1680547998; bh=lcACIbyZXGhoG9zxqFuExfr6pSyMF5NTm2ULV60ci3Q=; h=To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=oHfquHDW4rwYb4Y57Xe8tykn6bXoSuFoU3alrioV+GOnBj+QxhL+wWyngTpQkPcbz euvQUYp/I1jwX5sp4cC1SC0+R1BgK6hCIgti1PbcaaFlyRUjjgiCCkJMeKDSYoDtwL 2e1LCkG9DmHHM1Ci5U/tqUF5/ewNwIIHxUp5ytnM= X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from simark.ca (simark.ca [158.69.221.121]) by sourceware.org (Postfix) with ESMTPS id A3FC63858C62 for ; Mon, 3 Apr 2023 18:52:20 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org A3FC63858C62 Received: from localhost.localdomain (unknown [217.28.27.60]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPSA id 1895E1E223; Mon, 3 Apr 2023 14:52:19 -0400 (EDT) To: gdb-patches@sourceware.org Cc: Simon Marchi , Pedro Alves Subject: [PATCH 3/7] gdb: remove regcache::target Date: Mon, 3 Apr 2023 14:52:04 -0400 Message-Id: <20230403185208.197965-4-simon.marchi@efficios.com> X-Mailer: git-send-email 2.40.0 In-Reply-To: <20230403185208.197965-1-simon.marchi@efficios.com> References: <20230403185208.197965-1-simon.marchi@efficios.com> MIME-Version: 1.0 X-Spam-Status: No, score=-1173.2 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_NONE, KAM_DMARC_STATUS, SPF_HELO_PASS, SPF_SOFTFAIL, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Simon Marchi via Gdb-patches From: Simon Marchi Reply-To: Simon Marchi Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org Sender: "Gdb-patches" The regcache class takes a process_stratum_target and then exposes it through regcache::target. But it doesn't use it itself, suggesting it doesn't really make sense to put it there. The only user of regcache::target is record_btrace_target::fetch_registers, but it might as well just get it from the current target stack. This simplifies a little bit a patch later in this series. Change-Id: I8878d875805681c77f469ac1a2bf3a508559a62d Reviewed-By: Pedro Alves --- gdb/record-btrace.c | 3 ++- gdb/regcache.c | 1 - gdb/regcache.h | 5 ----- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c index 2d88e4d20bf6..358d8de089f8 100644 --- a/gdb/record-btrace.c +++ b/gdb/record-btrace.c @@ -1548,7 +1548,8 @@ record_btrace_target::fetch_registers (struct regcache *regcache, int regno) /* Thread-db may ask for a thread's registers before GDB knows about the thread. We forward the request to the target beneath in this case. */ - thread_info *tp = find_thread_ptid (regcache->target (), regcache->ptid ()); + thread_info *tp = find_thread_ptid (current_inferior ()->process_target (), + regcache->ptid ()); if (tp != nullptr) replay = tp->btrace.replay; diff --git a/gdb/regcache.c b/gdb/regcache.c index af76fab1a34f..cfa8a3d78335 100644 --- a/gdb/regcache.c +++ b/gdb/regcache.c @@ -1622,7 +1622,6 @@ get_thread_arch_aspace_regcache_and_check (process_stratum_target *target, = get_thread_arch_aspace_regcache (target, ptid, arch, aspace); SELF_CHECK (regcache != NULL); - SELF_CHECK (regcache->target () == target); SELF_CHECK (regcache->ptid () == ptid); SELF_CHECK (regcache->arch () == arch); SELF_CHECK (regcache->aspace () == aspace); diff --git a/gdb/regcache.h b/gdb/regcache.h index b9ffab9950d2..2bd2f57b8332 100644 --- a/gdb/regcache.h +++ b/gdb/regcache.h @@ -416,11 +416,6 @@ class regcache : public detached_regcache this->m_ptid = ptid; } - process_stratum_target *target () const - { - return m_target; - } - /* Dump the contents of a register from the register cache to the target debug. */ void debug_print_register (const char *func, int regno); From patchwork Mon Apr 3 18:52:05 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Marchi X-Patchwork-Id: 67227 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id C62F53853D3E for ; Mon, 3 Apr 2023 18:53:00 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org C62F53853D3E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1680547980; bh=67P3+44IkIiZDGJ7YxAsDtis192iRpfPMagkRyYchxI=; h=To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=Tcdb3hv1tI2sA8OxFKMbnpgR3My6R1yovaWZuod8IrSqJLY7ueia9mq4kJ+nu/Bli p0TCBSAxexhdsTE3+mpF5DXKJ17VNCn/Tv8heFtpUE5H751H51dqHOEA9NYii1dxtk VygEGUbLfyZJ8//0ch5PjJZAP1WlZiV9CTmwvYFo= X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from simark.ca (simark.ca [158.69.221.121]) by sourceware.org (Postfix) with ESMTPS id E2FA63858C66 for ; Mon, 3 Apr 2023 18:52:20 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org E2FA63858C66 Received: from localhost.localdomain (unknown [217.28.27.60]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPSA id 6D2CF1E224; Mon, 3 Apr 2023 14:52:20 -0400 (EDT) To: gdb-patches@sourceware.org Cc: Simon Marchi , Pedro Alves Subject: [PATCH 4/7] gdb: add maybe_switch_inferior function Date: Mon, 3 Apr 2023 14:52:05 -0400 Message-Id: <20230403185208.197965-5-simon.marchi@efficios.com> X-Mailer: git-send-email 2.40.0 In-Reply-To: <20230403185208.197965-1-simon.marchi@efficios.com> References: <20230403185208.197965-1-simon.marchi@efficios.com> MIME-Version: 1.0 X-Spam-Status: No, score=-1173.3 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_NONE, KAM_DMARC_STATUS, SPF_HELO_PASS, SPF_SOFTFAIL, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Simon Marchi via Gdb-patches From: Simon Marchi Reply-To: Simon Marchi Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org Sender: "Gdb-patches" Add the maybe_switch_inferior function, which ensures that the given inferior is the current one. Return an instantiated scoped_restore_current_thread object only we actually needed to switch inferior. Returning a scoped_restore_current_thread requires it to be move-constructible, so give it a move constructor. Change-Id: I1231037102ed6166f2530399e8257ad937fb0569 Reviewed-By: Pedro Alves --- gdb/gdbthread.h | 2 ++ gdb/inferior.c | 15 +++++++++++++++ gdb/inferior.h | 7 +++++++ gdb/thread.c | 14 ++++++++++++++ 4 files changed, 38 insertions(+) diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h index 848daa94410a..731c5e159e9f 100644 --- a/gdb/gdbthread.h +++ b/gdb/gdbthread.h @@ -858,6 +858,8 @@ class scoped_restore_current_thread scoped_restore_current_thread (); ~scoped_restore_current_thread (); + scoped_restore_current_thread (scoped_restore_current_thread &&rhs); + DISABLE_COPY_AND_ASSIGN (scoped_restore_current_thread); /* Cancel restoring on scope exit. */ diff --git a/gdb/inferior.c b/gdb/inferior.c index a1e3c79d8a20..f6ed942c5053 100644 --- a/gdb/inferior.c +++ b/gdb/inferior.c @@ -672,6 +672,21 @@ switch_to_inferior_no_thread (inferior *inf) set_current_program_space (inf->pspace); } +/* See regcache.h. */ + +gdb::optional +maybe_switch_inferior (inferior *inf) +{ + gdb::optional maybe_restore_thread; + if (inf != current_inferior ()) + { + maybe_restore_thread.emplace (); + switch_to_inferior_no_thread (inf); + } + + return maybe_restore_thread; +} + static void inferior_command (const char *args, int from_tty) { diff --git a/gdb/inferior.h b/gdb/inferior.h index 72034cc4ffbc..ab981b7b4b27 100644 --- a/gdb/inferior.h +++ b/gdb/inferior.h @@ -340,6 +340,13 @@ extern void set_current_inferior (inferior *); selected. */ extern void switch_to_inferior_no_thread (inferior *inf); +/* Ensure INF is the current inferior. + + If the current inferior was changed, return an RAII object that will + restore the original current context. */ +extern gdb::optional maybe_switch_inferior + (inferior *inf); + /* Info about an inferior's target description. There's one of these for each inferior. */ diff --git a/gdb/thread.c b/gdb/thread.c index 25d97cd60727..506f8481e17b 100644 --- a/gdb/thread.c +++ b/gdb/thread.c @@ -1403,6 +1403,20 @@ scoped_restore_current_thread::scoped_restore_current_thread () } } +scoped_restore_current_thread::scoped_restore_current_thread + (scoped_restore_current_thread &&rhs) + : m_dont_restore (std::move (rhs.m_dont_restore)), + m_thread (std::move (rhs.m_thread)), + m_inf (std::move (rhs.m_inf)), + m_selected_frame_id (std::move (rhs.m_selected_frame_id)), + m_selected_frame_level (std::move (rhs.m_selected_frame_level)), + m_was_stopped (std::move (rhs.m_was_stopped)), + m_lang (std::move (rhs.m_lang)) +{ + /* Deactivate the rhs. */ + rhs.m_dont_restore = true; +} + /* See gdbthread.h. */ int From patchwork Mon Apr 3 18:52:06 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Marchi X-Patchwork-Id: 67230 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 20666384842D for ; Mon, 3 Apr 2023 18:53:31 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 20666384842D DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1680548011; bh=AhQAG6CS/RaaQP8yAtUxuTo91ysH2fjuS5lrMtCutf0=; h=To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=v5hXiZSikXBY6AgAANkR8UW8xI+uRKVRVv/CorO/Im5MBCrqZ4UFz8NYbmnMmqRMo /1XWp6c+1DcwcnFFL/wMyHlqcIAmiLApNf6GilKlFdOqYermGxcrfV7fLCmRnxKfRu W8zBYeiH69U0SKo3gi6/sMSDDiVVARnYa2F2GGjU= X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from simark.ca (simark.ca [158.69.221.121]) by sourceware.org (Postfix) with ESMTPS id 821323858C00 for ; Mon, 3 Apr 2023 18:52:21 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 821323858C00 Received: from localhost.localdomain (unknown [217.28.27.60]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPSA id D3E4D1E225; Mon, 3 Apr 2023 14:52:20 -0400 (EDT) To: gdb-patches@sourceware.org Cc: Simon Marchi , Pedro Alves Subject: [PATCH 5/7] gdb: make regcache::raw_update switch to right inferior Date: Mon, 3 Apr 2023 14:52:06 -0400 Message-Id: <20230403185208.197965-6-simon.marchi@efficios.com> X-Mailer: git-send-email 2.40.0 In-Reply-To: <20230403185208.197965-1-simon.marchi@efficios.com> References: <20230403185208.197965-1-simon.marchi@efficios.com> MIME-Version: 1.0 X-Spam-Status: No, score=-1173.4 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_NONE, KAM_DMARC_STATUS, SPF_HELO_PASS, SPF_SOFTFAIL, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Simon Marchi via Gdb-patches From: Simon Marchi Reply-To: Simon Marchi Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org Sender: "Gdb-patches" With the following patch, which teaches the amd-dbgapi target to handle inferiors that fork, we end up with target stacks in the following state, when an inferior that does not use the GPU forks an inferior that eventually uses the GPU. inf 1 inf 2 ----- ----- amd-dbgapi linux-nat linux-nat exec exec When a GPU thread from inferior 2 hits a breakpoint, the following sequence of events would happen, if it was not for the current patch. - we start with inferior 1 as current - do_target_wait_1 makes inferior 2 current, does a target_wait, which returns a stop event for an amd-dbgapi wave (thread). - do_target_wait's scoped_restore_current_thread restores inferior 1 as current - fetch_inferior_event calls switch_to_target_no_thread with linux-nat as the process target, since linux-nat is officially the process target of inferior 2. This makes inferior 1 the current inferior, as it's the first inferior with that target. - In handle_signal_stop, we have: ecs->event_thread->suspend.stop_pc = regcache_read_pc (get_thread_regcache (ecs->event_thread)); context_switch (ecs); regcache_read_pc executes while inferior 1 is still the current one (because it's before the `context_switch`). This is a problem, because the regcache is for a ptid managed by the amd-dbgapi target (e.g. (12345, 1, 1)), a ptid that does not make sense for the linux-nat target. The fetch_registers target call goes directly to the linux-nat target, which gets confused. - We would then get an error like: Couldn't get extended state status: No such process. ... since linux-nat tries to do a ptrace call on tid 1. GDB should switch to the inferior the ptid belongs to before doing the target call to fetch registers, to make sure the call hits the right target stack (it should be handled by the amd-dbgapi target in this case). In fact the following patch does this change, and it would be enough to fix this specific problem. However, I propose to change regcache to make it switch to the right inferior, if needed, before doing target calls. That makes the interface as a whole more independent of the global context. My first attempt at doing this was to find an inferior using the process stratum target and the ptid that regcache already knows about: gdb::optional restore_thread; inferior *inf = find_inferior_ptid (this->target (), this->ptid ()); if (inf != current_inferior ()) { restore_thread.emplace (); switch_to_inferior_no_thread (inf); } However, this caused some failures in fork-related tests and gdbserver boards. When we detach a fork child, we may create a regcache for the child, but there is no corresponding inferior. For instance, to restore the PC after a displaced step over the fork syscall. So find_inferior_ptid would return nullptr, and switch_to_inferior_no_thread would hit a failed assertion. So, this patch adds to regcache the information "the inferior to switch to to makes target calls". In typical cases, it will be the inferior that matches the regcache's ptid. But in some cases, like the detached fork child one, it will be another inferior (in this example, it will be the fork parent inferior). The problem that we witnessed was in regcache::raw_update specifically, but I looked for other regcache methods doing target calls, and added the same inferior switching code to raw_write too. In the regcache constructor and in get_thread_arch_aspace_regcache, "inf_for_target_calls" replaces the process_stratum_target parameter. We suppose that the process stratum target that would be passed otherwise is the same that is in inf_for_target_calls's target stack, so we don't need to pass both in parallel. The process stratum target is still used as a key in the `target_pid_ptid_regcache_map` map, but that's it. There is one spot that needs to be updated outside of the regcache code, which is the path that handles the "restore PC after a displaced step in a fork child we're about to detach" case mentioned above. regcache_test_data needs to be changed to include full-fledged mock contexts (because there now needs to be inferiors, not just targets). Change-Id: Id088569ce106e1f194d9ae7240ff436f11c5e123 Reviewed-By: Pedro Alves --- gdb/infrun.c | 2 +- gdb/regcache.c | 89 +++++++++++++++++++++++++++++++------------------- gdb/regcache.h | 17 +++++++--- 3 files changed, 70 insertions(+), 38 deletions(-) diff --git a/gdb/infrun.c b/gdb/infrun.c index 11a788467a8a..f32e037f3649 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -5805,7 +5805,7 @@ handle_inferior_event (struct execution_control_state *ecs) list yet at this point. */ child_regcache - = get_thread_arch_aspace_regcache (parent_inf->process_target (), + = get_thread_arch_aspace_regcache (parent_inf, ecs->ws.child_ptid (), gdbarch, parent_inf->aspace); diff --git a/gdb/regcache.c b/gdb/regcache.c index cfa8a3d78335..56292fbd4bff 100644 --- a/gdb/regcache.c +++ b/gdb/regcache.c @@ -208,11 +208,12 @@ reg_buffer::reg_buffer (gdbarch *gdbarch, bool has_pseudo) } } -regcache::regcache (process_stratum_target *target, gdbarch *gdbarch, +regcache::regcache (inferior *inf_for_target_calls, gdbarch *gdbarch, const address_space *aspace_) /* The register buffers. A read/write register cache can only hold [0 .. gdbarch_num_regs). */ - : detached_regcache (gdbarch, false), m_aspace (aspace_), m_target (target) + : detached_regcache (gdbarch, false), m_aspace (aspace_), + m_inf_for_target_calls (inf_for_target_calls) { m_ptid = minus_one_ptid; } @@ -348,14 +349,17 @@ using target_pid_ptid_regcache_map static target_pid_ptid_regcache_map regcaches; struct regcache * -get_thread_arch_aspace_regcache (process_stratum_target *target, +get_thread_arch_aspace_regcache (inferior *inf_for_target_calls, ptid_t ptid, gdbarch *arch, struct address_space *aspace) { - gdb_assert (target != nullptr); + gdb_assert (inf_for_target_calls != nullptr); + + process_stratum_target *proc_target = inf_for_target_calls->process_target (); + gdb_assert (proc_target != nullptr); /* Find the map for this target. */ - pid_ptid_regcache_map &pid_ptid_regc_map = regcaches[target]; + pid_ptid_regcache_map &pid_ptid_regc_map = regcaches[proc_target]; /* Find the map for this pid. */ ptid_regcache_map &ptid_regc_map = pid_ptid_regc_map[ptid.pid ()]; @@ -369,7 +373,7 @@ get_thread_arch_aspace_regcache (process_stratum_target *target, } /* It does not exist, create it. */ - regcache *new_regcache = new regcache (target, arch, aspace); + regcache *new_regcache = new regcache (inf_for_target_calls, arch, aspace); new_regcache->set_ptid (ptid); /* Work around a problem with g++ 4.8 (PR96537): Call the regcache_up constructor explictly instead of implicitly. */ @@ -383,10 +387,11 @@ get_thread_arch_regcache (process_stratum_target *target, ptid_t ptid, struct gdbarch *gdbarch) { scoped_restore_current_inferior restore_current_inferior; - set_current_inferior (find_inferior_ptid (target, ptid)); + inferior *inf = find_inferior_ptid (target, ptid); + set_current_inferior (inf); address_space *aspace = target_thread_address_space (ptid); - return get_thread_arch_aspace_regcache (target, ptid, gdbarch, aspace); + return get_thread_arch_aspace_regcache (inf, ptid, gdbarch, aspace); } static process_stratum_target *current_thread_target; @@ -591,6 +596,9 @@ regcache::raw_update (int regnum) if (get_register_status (regnum) == REG_UNKNOWN) { + gdb::optional maybe_restore_thread + = maybe_switch_inferior (m_inf_for_target_calls); + target_fetch_registers (this, regnum); /* A number of targets can't access the whole set of raw @@ -842,6 +850,9 @@ regcache::raw_write (int regnum, const gdb_byte *buf) m_descr->sizeof_register[regnum]) == 0)) return; + gdb::optional maybe_restore_thread + = maybe_switch_inferior (m_inf_for_target_calls); + target_prepare_to_store (this); raw_supply (regnum, buf); @@ -1610,16 +1621,16 @@ regcache_count (process_stratum_target *target, ptid_t ptid) /* Wrapper around get_thread_arch_aspace_regcache that does some self checks. */ static void -get_thread_arch_aspace_regcache_and_check (process_stratum_target *target, +get_thread_arch_aspace_regcache_and_check (inferior *inf_for_target_calls, ptid_t ptid) { /* We currently only test with a single gdbarch. Any gdbarch will do, so use the current inferior's gdbarch. Also use the current inferior's address space. */ - gdbarch *arch = current_inferior ()->gdbarch; - address_space *aspace = current_inferior ()->aspace; - regcache *regcache - = get_thread_arch_aspace_regcache (target, ptid, arch, aspace); + gdbarch *arch = inf_for_target_calls->gdbarch; + address_space *aspace = inf_for_target_calls->aspace; + regcache *regcache = get_thread_arch_aspace_regcache (inf_for_target_calls, + ptid, arch, aspace); SELF_CHECK (regcache != NULL); SELF_CHECK (regcache->ptid () == ptid); @@ -1633,6 +1644,9 @@ get_thread_arch_aspace_regcache_and_check (process_stratum_target *target, struct regcache_test_data { regcache_test_data () + /* The specific arch doesn't matter. */ + : test_ctx_1 (current_inferior ()->gdbarch), + test_ctx_2 (current_inferior ()->gdbarch) { /* Ensure the regcaches container is empty at the start. */ registers_changed (); @@ -1644,8 +1658,8 @@ struct regcache_test_data registers_changed (); } - test_target_ops test_target1; - test_target_ops test_target2; + scoped_mock_context test_ctx_1; + scoped_mock_context test_ctx_2; }; using regcache_test_data_up = std::unique_ptr; @@ -1670,12 +1684,12 @@ populate_regcaches_for_test () for (long lwp : { 1, 2, 3 }) { get_thread_arch_aspace_regcache_and_check - (&data->test_target1, ptid_t (pid, lwp)); + (&data->test_ctx_1.mock_inferior, ptid_t (pid, lwp)); expected_regcache_size++; SELF_CHECK (regcaches_size () == expected_regcache_size); get_thread_arch_aspace_regcache_and_check - (&data->test_target2, ptid_t (pid, lwp)); + (&data->test_ctx_2.mock_inferior, ptid_t (pid, lwp)); expected_regcache_size++; SELF_CHECK (regcaches_size () == expected_regcache_size); } @@ -1693,7 +1707,8 @@ get_thread_arch_aspace_regcache_test () size_t regcaches_size_before = regcaches_size (); /* Test that getting an existing regcache doesn't create a new one. */ - get_thread_arch_aspace_regcache_and_check (&data->test_target1, ptid_t (2, 2)); + get_thread_arch_aspace_regcache_and_check (&data->test_ctx_1.mock_inferior, + ptid_t (2, 2)); SELF_CHECK (regcaches_size () == regcaches_size_before); } @@ -1715,12 +1730,14 @@ registers_changed_ptid_target_test () { regcache_test_data_up data = populate_regcaches_for_test (); - registers_changed_ptid (&data->test_target1, minus_one_ptid); + registers_changed_ptid (&data->test_ctx_1.mock_target, minus_one_ptid); SELF_CHECK (regcaches_size () == 6); /* Check that we deleted the regcache for the right target. */ - SELF_CHECK (regcache_count (&data->test_target1, ptid_t (2, 2)) == 0); - SELF_CHECK (regcache_count (&data->test_target2, ptid_t (2, 2)) == 1); + SELF_CHECK (regcache_count (&data->test_ctx_1.mock_target, + ptid_t (2, 2)) == 0); + SELF_CHECK (regcache_count (&data->test_ctx_2.mock_target, + ptid_t (2, 2)) == 1); } /* Test marking regcaches of a specific (target, pid) as changed. */ @@ -1730,13 +1747,15 @@ registers_changed_ptid_target_pid_test () { regcache_test_data_up data = populate_regcaches_for_test (); - registers_changed_ptid (&data->test_target1, ptid_t (2)); + registers_changed_ptid (&data->test_ctx_1.mock_target, ptid_t (2)); SELF_CHECK (regcaches_size () == 9); /* Regcaches from target1 should not exist, while regcaches from target2 should exist. */ - SELF_CHECK (regcache_count (&data->test_target1, ptid_t (2, 2)) == 0); - SELF_CHECK (regcache_count (&data->test_target2, ptid_t (2, 2)) == 1); + SELF_CHECK (regcache_count (&data->test_ctx_1.mock_target, + ptid_t (2, 2)) == 0); + SELF_CHECK (regcache_count (&data->test_ctx_2.mock_target, + ptid_t (2, 2)) == 1); } /* Test marking regcaches of a specific (target, ptid) as changed. */ @@ -1746,12 +1765,14 @@ registers_changed_ptid_target_ptid_test () { regcache_test_data_up data = populate_regcaches_for_test (); - registers_changed_ptid (&data->test_target1, ptid_t (2, 2)); + registers_changed_ptid (&data->test_ctx_1.mock_target, ptid_t (2, 2)); SELF_CHECK (regcaches_size () == 11); /* Check that we deleted the regcache for the right target. */ - SELF_CHECK (regcache_count (&data->test_target1, ptid_t (2, 2)) == 0); - SELF_CHECK (regcache_count (&data->test_target2, ptid_t (2, 2)) == 1); + SELF_CHECK (regcache_count (&data->test_ctx_1.mock_target, + ptid_t (2, 2)) == 0); + SELF_CHECK (regcache_count (&data->test_ctx_2.mock_target, + ptid_t (2, 2)) == 1); } class target_ops_no_register : public test_target_ops @@ -1812,9 +1833,9 @@ target_ops_no_register::xfer_partial (enum target_object object, class readwrite_regcache : public regcache { public: - readwrite_regcache (process_stratum_target *target, + readwrite_regcache (inferior *inf_for_target_calls, struct gdbarch *gdbarch) - : regcache (target, gdbarch, nullptr) + : regcache (inf_for_target_calls, gdbarch, nullptr) {} }; @@ -1861,7 +1882,8 @@ cooked_read_test (struct gdbarch *gdbarch) break; } - readwrite_regcache readwrite (&mockctx.mock_target, gdbarch); + readwrite_regcache readwrite (&mockctx.mock_inferior, gdbarch); + readwrite.set_ptid (mockctx.mock_ptid); gdb::def_vector buf (register_size (gdbarch, nonzero_regnum)); readwrite.raw_read (nonzero_regnum, buf.data ()); @@ -1978,7 +2000,8 @@ cooked_write_test (struct gdbarch *gdbarch) /* Create a mock environment. A process_stratum target pushed. */ scoped_mock_context ctx (gdbarch); - readwrite_regcache readwrite (&ctx.mock_target, gdbarch); + readwrite_regcache readwrite (&ctx.mock_inferior, gdbarch); + readwrite.set_ptid (ctx.mock_ptid); const int num_regs = gdbarch_num_cooked_regs (gdbarch); for (auto regnum = 0; regnum < num_regs; regnum++) @@ -2093,9 +2116,9 @@ regcache_thread_ptid_changed () gdb_assert (regcaches.empty ()); /* Populate the regcaches container. */ - get_thread_arch_aspace_regcache (&target1.mock_target, old_ptid, arch, + get_thread_arch_aspace_regcache (&target1.mock_inferior, old_ptid, arch, nullptr); - get_thread_arch_aspace_regcache (&target2.mock_target, old_ptid, arch, + get_thread_arch_aspace_regcache (&target2.mock_inferior, old_ptid, arch, nullptr); gdb_assert (regcaches.size () == 2); diff --git a/gdb/regcache.h b/gdb/regcache.h index 2bd2f57b8332..57ddac465f09 100644 --- a/gdb/regcache.h +++ b/gdb/regcache.h @@ -29,6 +29,7 @@ struct gdbarch; struct address_space; class thread_info; struct process_stratum_target; +struct inferior; extern struct regcache *get_current_regcache (void); extern struct regcache *get_thread_regcache (process_stratum_target *target, @@ -40,7 +41,7 @@ extern struct regcache *get_thread_regcache (thread_info *thread); extern struct regcache *get_thread_arch_regcache (process_stratum_target *targ, ptid_t, struct gdbarch *); extern struct regcache *get_thread_arch_aspace_regcache - (process_stratum_target *target, ptid_t, + (inferior *inf_for_target_calls, ptid_t, struct gdbarch *, struct address_space *); extern enum register_status @@ -421,7 +422,7 @@ class regcache : public detached_regcache void debug_print_register (const char *func, int regno); protected: - regcache (process_stratum_target *target, gdbarch *gdbarch, + regcache (inferior *inf_for_target_calls, gdbarch *gdbarch, const address_space *aspace); private: @@ -448,13 +449,21 @@ class regcache : public detached_regcache makes sense, like PC or SP). */ const address_space * const m_aspace; + /* The inferior to switch to, to make target calls. + + This may not be the inferior of thread M_PTID. For instance, this + regcache might be for a fork child we are about to detach, so there will + never be an inferior for that thread / process. Nevertheless, we need to + be able to switch to the target stack that can handle register reads / + writes for this regcache, and that's what this inferior is for. */ + inferior *m_inf_for_target_calls; + /* If this is a read-write cache, which thread's registers is it connected to? */ - process_stratum_target *m_target; ptid_t m_ptid; friend struct regcache * - get_thread_arch_aspace_regcache (process_stratum_target *target, ptid_t ptid, + get_thread_arch_aspace_regcache (inferior *inf_for_target_calls, ptid_t ptid, struct gdbarch *gdbarch, struct address_space *aspace); }; From patchwork Mon Apr 3 18:52:07 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Marchi X-Patchwork-Id: 67228 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id CCCC1385C301 for ; Mon, 3 Apr 2023 18:53:08 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org CCCC1385C301 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1680547988; bh=1w7BOu4+GqPkNTT5AY9YwqDjwRdQPRHXaAxRnhF7CNc=; h=To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=M/tKy2V7chaDmW2nAU3pBLkCKeJ+W+5nrxZ1rTXs9R5fHu90Jo2sLFJ493UiNTtPj vokRletbhBXuVpYwvjXw8sZvL2NQ1jsKRfY9oTSIA0iucw3uqmUI+3hXA4AfRZnl/3 GwfAvONaCwNnVmJH3DSoiUPqTaZ96bLyOb/yQnms= X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from simark.ca (simark.ca [158.69.221.121]) by sourceware.org (Postfix) with ESMTPS id C85183858C27 for ; Mon, 3 Apr 2023 18:52:21 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org C85183858C27 Received: from localhost.localdomain (unknown [217.28.27.60]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPSA id 0E29E1E226; Mon, 3 Apr 2023 14:52:21 -0400 (EDT) To: gdb-patches@sourceware.org Cc: Simon Marchi , Pedro Alves Subject: [PATCH 6/7] gdb: switch to right inferior in fetch_inferior_event Date: Mon, 3 Apr 2023 14:52:07 -0400 Message-Id: <20230403185208.197965-7-simon.marchi@efficios.com> X-Mailer: git-send-email 2.40.0 In-Reply-To: <20230403185208.197965-1-simon.marchi@efficios.com> References: <20230403185208.197965-1-simon.marchi@efficios.com> MIME-Version: 1.0 X-Spam-Status: No, score=-1173.4 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_NONE, KAM_DMARC_STATUS, SPF_HELO_PASS, SPF_SOFTFAIL, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Simon Marchi via Gdb-patches From: Simon Marchi Reply-To: Simon Marchi Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org Sender: "Gdb-patches" The problem explained and fixed in the previous patch could have also been fixed by this patch. But I think it's good change anyhow, that could prevent future bugs, so here it is. fetch_inferior_event switches to an arbitrary (in practice, the first) inferior of the process target of the inferior used to fetch the event. The idea is that the event handling code will need to do some target calls, so we want to switch to an inferior that has target target. However, you can have two inferiors that share a process target, but with one inferior having an additional target on top: inf 1 inf 2 ----- ----- another target process target process target exec exec Let's say inferior 2 is selected by do_target_wait and returns an event that is really synthetized by "another target". This "another target" could be a thread or record stratum target (in the case explained by the previous patch, it was the arch stratum target, but it's because the amd-dbgapi abuses the arch layer). fetch_inferior_event will then switch to the first inferior with "process target", so inferior 1. handle_signal_stop then tries to fetch the thread's registers: ecs->event_thread->set_stop_pc (regcache_read_pc (get_thread_regcache (ecs->event_thread))); This will try to get the thread's register by calling into the current target stack, the stack of inferior 1. This is problematic because "another target" might have a special fetch_registers implementation. I think it would be a good idea to switch to the inferior for which the even was reported, not just some inferior of the same process target. This will ensure that any target call done before we eventually call context_switch will be done on the full target stack that reported the event. Not all events are associated to an inferior though. For instance, TARGET_WAITKIND_NO_RESUMED. In those cases, some targets return null_ptid, some return minus_one_ptid (ideally the expected return value should be clearly defined / documented). So, if the ptid returned is either of these, switch to an arbitrary inferior with that process target, as before. Change-Id: I1ffc8c1095125ab591d0dc79ea40025b1d7454af Reviewed-By: Pedro Alves --- gdb/infrun.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/gdb/infrun.c b/gdb/infrun.c index f32e037f3649..851c01f66130 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -4358,9 +4358,13 @@ fetch_inferior_event () gdb_assert (ecs.ws.kind () != TARGET_WAITKIND_IGNORE); - /* Switch to the target that generated the event, so we can do - target calls. */ - switch_to_target_no_thread (ecs.target); + /* Switch to the inferior that generated the event, so we can do + target calls. If the event was not associated to a ptid, */ + if (ecs.ptid != null_ptid + && ecs.ptid != minus_one_ptid) + switch_to_inferior_no_thread (find_inferior_ptid (ecs.target, ecs.ptid)); + else + switch_to_target_no_thread (ecs.target); if (debug_infrun) print_target_wait_results (minus_one_ptid, ecs.ptid, ecs.ws); From patchwork Mon Apr 3 18:52:08 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Marchi X-Patchwork-Id: 67231 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 470D6385B529 for ; Mon, 3 Apr 2023 18:53:37 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 470D6385B529 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1680548017; bh=kKz7e5myBFK+lK9U8EdMItj1X73x0cAy9oxzzLDZOa4=; h=To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=AsekfhwK2goWNiYgLQnmMPmcVyyEC9E3vT+BkLQaY+6cPaIZIBa0OaYJXHlGlKSs2 5x0EpjjLj1LWjuCyoWQSVh9ffDxe9O2ln8FSITXvMGPJ8cBUEQFrXW8w0y5t90WU/1 6l28EswtsTwGB2qIV9UDlhugPIH+XjWCEjBOvEaM= X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from simark.ca (simark.ca [158.69.221.121]) by sourceware.org (Postfix) with ESMTPS id B53F13858C20 for ; Mon, 3 Apr 2023 18:52:21 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org B53F13858C20 Received: from localhost.localdomain (unknown [217.28.27.60]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPSA id 637801E0D2; Mon, 3 Apr 2023 14:52:21 -0400 (EDT) To: gdb-patches@sourceware.org Cc: Simon Marchi , Pedro Alves Subject: [PATCH 7/7] gdb/amdgpu: add follow fork and exec support Date: Mon, 3 Apr 2023 14:52:08 -0400 Message-Id: <20230403185208.197965-8-simon.marchi@efficios.com> X-Mailer: git-send-email 2.40.0 In-Reply-To: <20230403185208.197965-1-simon.marchi@efficios.com> References: <20230403185208.197965-1-simon.marchi@efficios.com> MIME-Version: 1.0 X-Spam-Status: No, score=-1173.4 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_NONE, KAM_DMARC_STATUS, KAM_SHORT, SPF_HELO_PASS, SPF_SOFTFAIL, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Simon Marchi via Gdb-patches From: Simon Marchi Reply-To: Simon Marchi Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org Sender: "Gdb-patches" Prior to this patch, it's not possible for GDB to debug GPU code in fork children or after an exec. The amd-dbgapi target attaches to processes when an inferior appears due to a "run" or "attach" command, but not after a fork or exec. This patch adds support for that, such that it's possible to for an inferior to fork and for GDB to debug the GPU code in the child. To achieve that, use the inferior_forked and inferior_execd observers. In the case of fork, we have nothing to do if `child_inf` is nullptr, meaning that GDB won't debug the child. We also don't attach if the inferior has vforked. We are already attached to the parent's address space, which is shared with the child, so trying to attach would cause problems. And anyway, the inferior can't do anything other than exec or exit, it certainly won't start GPU kernels before exec'ing. In the case of exec, we detach from the exec'ing inferior and attach to the following inferior. This works regardless of whether they are the same or not. If they are the same, meaning the execution continues in the existing inferior, we need to do a detach/attach anyway, as amd-dbgapi needs to be aware of the new address space created by the exec. Note that we use observers and not target_ops::follow_{fork,exec} here. When the amd-dbgapi target is compiled in, it will attach (in the amd_dbgapi_process_attach sense, not the ptrace sense) to native inferiors when they appear, but won't push itself on the inferior's target stack just yet. It only pushes itself if the inferior initializes the ROCm runtime. So, if a non-GPU-using inferior calls fork, an amd_dbgapi_target::follow_fork method would not get called. Same for exec. A previous version of the code had the amd-dbgapi target pushed all the time, in which case we could use the target methods. But we prefer having the target pushed only when necessary, it's less intrusive when doing native debugging that doesn't involve the GPU. Change-Id: I5819c151c371120da8bab2fa9cbfa8769ba1d6f9 Reviewed-By: Pedro Alves --- gdb/amd-dbgapi-target.c | 39 ++++++++ .../fork-exec-gpu-to-non-gpu-execee.cpp | 27 ++++++ .../fork-exec-gpu-to-non-gpu-execer.cpp | 55 ++++++++++++ .../gdb.rocm/fork-exec-gpu-to-non-gpu.exp | 89 +++++++++++++++++++ .../fork-exec-non-gpu-to-gpu-execee.cpp | 36 ++++++++ .../fork-exec-non-gpu-to-gpu-execer.cpp | 46 ++++++++++ .../gdb.rocm/fork-exec-non-gpu-to-gpu.exp | 88 ++++++++++++++++++ 7 files changed, 380 insertions(+) create mode 100644 gdb/testsuite/gdb.rocm/fork-exec-gpu-to-non-gpu-execee.cpp create mode 100644 gdb/testsuite/gdb.rocm/fork-exec-gpu-to-non-gpu-execer.cpp create mode 100644 gdb/testsuite/gdb.rocm/fork-exec-gpu-to-non-gpu.exp create mode 100644 gdb/testsuite/gdb.rocm/fork-exec-non-gpu-to-gpu-execee.cpp create mode 100644 gdb/testsuite/gdb.rocm/fork-exec-non-gpu-to-gpu-execer.cpp create mode 100644 gdb/testsuite/gdb.rocm/fork-exec-non-gpu-to-gpu.exp diff --git a/gdb/amd-dbgapi-target.c b/gdb/amd-dbgapi-target.c index f5161038c51d..61b9805abca0 100644 --- a/gdb/amd-dbgapi-target.c +++ b/gdb/amd-dbgapi-target.c @@ -1343,6 +1343,17 @@ attach_amd_dbgapi (inferior *inf) return; } + /* dbgapi can't attach to a vfork child (a process born from a vfork that + hasn't exec'ed yet) while we are still attached to the parent. It would + not be useful for us to attach to vfork children anyway, because vfork + children are very restricted in what they can do (see vfork(2)) and aren't + going to launch some GPU programs that we need to debug. To avoid this + problem, we don't push the amd-dbgapi target / attach dbgapi in vfork + children. If a vfork child execs, we'll try enabling the amd-dbgapi target + through the inferior_execd observer. */ + if (inf->vfork_parent != nullptr) + return; + auto *info = get_amd_dbgapi_inferior_info (inf); /* Are we already attached? */ @@ -1655,6 +1666,32 @@ amd_dbgapi_target_inferior_created (inferior *inf) attach_amd_dbgapi (inf); } +/* inferior_execd observer. */ + +static void +amd_dbgapi_inferior_execd (inferior *exec_inf, inferior *follow_inf) +{ + /* The inferior has EXEC'd and the process image has changed. The dbgapi is + attached to the old process image, so we need to detach and re-attach to + the new process image. */ + detach_amd_dbgapi (exec_inf); + attach_amd_dbgapi (follow_inf); +} + +/* inferior_forked observer. */ + +static void +amd_dbgapi_inferior_forked (inferior *parent_inf, inferior *child_inf, + target_waitkind fork_kind) +{ + if (child_inf != nullptr && fork_kind != TARGET_WAITKIND_VFORKED) + { + scoped_restore_current_thread restore_thread; + switch_to_thread (*child_inf->threads ().begin ()); + attach_amd_dbgapi (child_inf); + } +} + /* inferior_exit observer. This covers normal exits, but also detached inferiors (including detached @@ -1924,6 +1961,8 @@ _initialize_amd_dbgapi_target () gdb::observers::inferior_created.attach (amd_dbgapi_target_inferior_created, amd_dbgapi_target_inferior_created_observer_token, "amd-dbgapi"); + gdb::observers::inferior_execd.attach (amd_dbgapi_inferior_execd, "amd-dbgapi"); + gdb::observers::inferior_forked.attach (amd_dbgapi_inferior_forked, "amd-dbgapi"); gdb::observers::inferior_exit.attach (amd_dbgapi_inferior_exited, "amd-dbgapi"); gdb::observers::inferior_pre_detach.attach (amd_dbgapi_inferior_pre_detach, "amd-dbgapi"); diff --git a/gdb/testsuite/gdb.rocm/fork-exec-gpu-to-non-gpu-execee.cpp b/gdb/testsuite/gdb.rocm/fork-exec-gpu-to-non-gpu-execee.cpp new file mode 100644 index 000000000000..eacfcd86faa8 --- /dev/null +++ b/gdb/testsuite/gdb.rocm/fork-exec-gpu-to-non-gpu-execee.cpp @@ -0,0 +1,27 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2021-2023 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 . */ + +static void +break_here_execee (void) +{} + +int +main (void) +{ + break_here_execee (); + return 0; +} diff --git a/gdb/testsuite/gdb.rocm/fork-exec-gpu-to-non-gpu-execer.cpp b/gdb/testsuite/gdb.rocm/fork-exec-gpu-to-non-gpu-execer.cpp new file mode 100644 index 000000000000..1a731aeca517 --- /dev/null +++ b/gdb/testsuite/gdb.rocm/fork-exec-gpu-to-non-gpu-execer.cpp @@ -0,0 +1,55 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2021-2023 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 . */ + +#include +#include + +__global__ static void +kernel1 () +{} + +__device__ static void +break_here_execer () +{ +} + +__global__ static void +kernel2 () +{ + break_here_execer (); +} + +int +main () +{ + /* Launch a first kernel to make sure the runtime is active by the time we + call fork. */ + kernel1<<<1, 1>>> (); + + /* fork + exec while the runtime is active. */ + if (FORK () == 0) + { + int ret = execl (EXECEE, EXECEE, NULL); + perror ("exec"); + abort (); + } + + kernel2<<<1, 1>>> (); + + hipDeviceSynchronize (); + return 0; +} diff --git a/gdb/testsuite/gdb.rocm/fork-exec-gpu-to-non-gpu.exp b/gdb/testsuite/gdb.rocm/fork-exec-gpu-to-non-gpu.exp new file mode 100644 index 000000000000..852294b7067b --- /dev/null +++ b/gdb/testsuite/gdb.rocm/fork-exec-gpu-to-non-gpu.exp @@ -0,0 +1,89 @@ +# Copyright 2021-2023 Free Software Foundation, Inc. + +# This file is part of GDB. + +# 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 . + +# Verify handling of a GPU program that does a (v)fork + exec to execute +# a non-GPU program. + +load_lib rocm.exp + +require allow_hipcc_tests + +standard_testfile -execer.cpp -execee.cpp + +set srcfile_execer "$srcfile" +set srcfile_execee "$srcfile2" +set binfile_execee "$binfile-execee" + +# Compile two versions of execer, one that uses fork and one that uses vfork. +foreach_with_prefix fork_func { fork vfork } { + set opts [list debug hip additional_flags=-DFORK=$fork_func \ + additional_flags=-DEXECEE="${::binfile_execee}"] + if {[build_executable "failed to prepare" ${::binfile}-execer-${fork_func} \ + $srcfile_execer $opts]} { + return + } +} + +if {[build_executable "failed to prepare" $binfile_execee $srcfile_execee \ + {debug}]} { + return +} + +proc do_test { detach-on-fork follow-fork-mode fork_func } { + # In this case, the parent can't execute, as it's blocked in + # vfork. Skip it. + if { ${detach-on-fork} == "off" + && ${follow-fork-mode} == "parent" + && ${fork_func} == "vfork" } { + return + } + + with_rocm_gpu_lock { + clean_restart ${::binfile}-execer-${fork_func} + + gdb_test_no_output "set detach-on-fork ${detach-on-fork}" + gdb_test_no_output "set follow-fork-mode ${follow-fork-mode}" + + if { ${follow-fork-mode} == "parent" } { + runto break_here_execer allow-pending message + gdb_continue_to_end "continue parent to end" "continue" 1 + + if { ${detach-on-fork} == "off" } { + gdb_test "inferior 2" "Switching to inferior 2 .*" + gdb_continue_to_end "continue child to end" "continue" 1 + } + } elseif { ${follow-fork-mode} == "child" } { + runto break_here_execee allow-pending message + gdb_continue_to_end "continue child to end" "continue" 1 + + if { ${detach-on-fork} == "off" } { + gdb_test "inferior 1" "Switching to inferior 1 .*" + gdb_continue_to_end "continue parent to end" "continue" 1 + } + } else { + error "unexpected follow-fork-mode value: ${follow-fork-mode}" + } + } +} + +foreach_with_prefix detach-on-fork { on off } { + foreach_with_prefix follow-fork-mode { parent child } { + foreach_with_prefix fork_func { fork vfork } { + do_test ${detach-on-fork} ${follow-fork-mode} $fork_func + } + } +} diff --git a/gdb/testsuite/gdb.rocm/fork-exec-non-gpu-to-gpu-execee.cpp b/gdb/testsuite/gdb.rocm/fork-exec-non-gpu-to-gpu-execee.cpp new file mode 100644 index 000000000000..2de8fe20a0d6 --- /dev/null +++ b/gdb/testsuite/gdb.rocm/fork-exec-non-gpu-to-gpu-execee.cpp @@ -0,0 +1,36 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2021-2023 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 . */ + +#include + +__device__ static void +break_here_execee () +{} + +__global__ void +kernel () +{ + break_here_execee (); +} + +int +main () +{ + kernel<<<1, 1>>> (); + hipDeviceSynchronize (); + return 0; +} diff --git a/gdb/testsuite/gdb.rocm/fork-exec-non-gpu-to-gpu-execer.cpp b/gdb/testsuite/gdb.rocm/fork-exec-non-gpu-to-gpu-execer.cpp new file mode 100644 index 000000000000..3ee07949273a --- /dev/null +++ b/gdb/testsuite/gdb.rocm/fork-exec-non-gpu-to-gpu-execer.cpp @@ -0,0 +1,46 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2021-2023 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 . */ + +#include +#include +#include +#include + +static void +break_here_execer () +{} + +int +main () +{ + /* FORK is defined to fork or vfork by the test. */ + int pid = FORK (); + if (pid != 0) + { + /* Parent. */ + break_here_execer (); + } + else + { + /* EXECEE is defined by the test. */ + int ret = execl (EXECEE, EXECEE, NULL); + perror ("exec"); + abort (); + } + + return 0; +} diff --git a/gdb/testsuite/gdb.rocm/fork-exec-non-gpu-to-gpu.exp b/gdb/testsuite/gdb.rocm/fork-exec-non-gpu-to-gpu.exp new file mode 100644 index 000000000000..e372db5a32e6 --- /dev/null +++ b/gdb/testsuite/gdb.rocm/fork-exec-non-gpu-to-gpu.exp @@ -0,0 +1,88 @@ +# Copyright 2021-2023 Free Software Foundation, Inc. + +# This file is part of GDB. + +# 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 . + +# Verify that we can debug a GPU program in a child after a (v)fork + exec. + +load_lib rocm.exp + +require allow_hipcc_tests + +standard_testfile -execer.cpp -execee.cpp + +set srcfile_execer "$srcfile" +set srcfile_execee "$srcfile2" +set binfile_execee "$binfile-execee" + +# Compile two versions of execer, one that uses fork and one that uses vfork. +foreach_with_prefix fork_func { fork vfork } { + set opts [list additional_flags=-DFORK=$fork_func \ + additional_flags=-DEXECEE="${::binfile_execee}"] + if {[build_executable "failed to prepare" ${::binfile}-execer-${fork_func} \ + $srcfile_execer $opts]} { + return + } +} + +if {[build_executable "failed to prepare" $binfile_execee $srcfile_execee \ + {debug hip}]} { + return +} + +proc do_test { detach-on-fork follow-fork-mode fork_func } { + # In this case, the parent can't execute, as it's blocked in + # vfork. Skip it. + if { ${detach-on-fork} == "off" + && ${follow-fork-mode} == "parent" + && ${fork_func} == "vfork" } { + return + } + + with_rocm_gpu_lock { + clean_restart ${::binfile}-execer-${fork_func} + + gdb_test_no_output "set detach-on-fork ${detach-on-fork}" + gdb_test_no_output "set follow-fork-mode ${follow-fork-mode}" + + if { ${follow-fork-mode} == "parent" } { + runto break_here_execer allow-pending message + gdb_continue_to_end "continue parent to end" "continue" 1 + + if { ${detach-on-fork} == "off" } { + gdb_test "inferior 2" "Switching to inferior 2 .*" + gdb_continue_to_end "continue child to end" "continue" 1 + } + } elseif { ${follow-fork-mode} == "child" } { + runto break_here_execee allow-pending message + gdb_continue_to_end "continue child to end" "continue" 1 + + if { ${detach-on-fork} == "off" } { + gdb_test "inferior 1" "Switching to inferior 1 .*" + gdb_continue_to_end "continue parent to end" "continue" 1 + } + } else { + error "unexpected follow-fork-mode value: ${follow-fork-mode}" + } + } +} + +foreach_with_prefix detach-on-fork { on off } { + foreach_with_prefix follow-fork-mode { parent child } { + foreach_with_prefix fork_func { fork vfork } { + do_test ${detach-on-fork} ${follow-fork-mode} $fork_func + } + } +}