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? */
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
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");
--- /dev/null
+/* 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 <http://www.gnu.org/licenses/>. */
+
+static void
+break_here_execee (void)
+{}
+
+int
+main (void)
+{
+ break_here_execee ();
+ return 0;
+}
--- /dev/null
+/* 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 <http://www.gnu.org/licenses/>. */
+
+#include <hip/hip_runtime.h>
+#include <unistd.h>
+
+__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;
+}
--- /dev/null
+# 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 <http://www.gnu.org/licenses/>.
+
+# 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
+ }
+ }
+}
--- /dev/null
+/* 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 <http://www.gnu.org/licenses/>. */
+
+#include <hip/hip_runtime.h>
+
+__device__ static void
+break_here_execee ()
+{}
+
+__global__ void
+kernel ()
+{
+ break_here_execee ();
+}
+
+int
+main ()
+{
+ kernel<<<1, 1>>> ();
+ hipDeviceSynchronize ();
+ return 0;
+}
--- /dev/null
+/* 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 <http://www.gnu.org/licenses/>. */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+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;
+}
--- /dev/null
+# 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 <http://www.gnu.org/licenses/>.
+
+# 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
+ }
+ }
+}