diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.h b/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.h index 42a6212510c..a8aafb228ef 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.h +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/libproc_impl.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -95,6 +95,10 @@ struct core_data { // part of the class sharing workaround int classes_jsa_fd; // file descriptor of class share archive uintptr_t dynamic_addr; // address of dynamic section of a.out + + uintptr_t vdso_addr; // address of vDSO + off64_t vdso_offset; // offset of vDSO in core + size_t vdso_size; // size of vDSO uintptr_t ld_base_addr; // base address of ld.so size_t num_maps; // number of maps. map_info* maps; // maps in a linked list diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c b/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c index 899d42152d1..e378a8657f4 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/ps_core.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,9 @@ #include #include #include +#include +#include +#include #include "libproc_impl.h" #include "ps_core_common.h" #include "proc_service.h" @@ -285,6 +288,8 @@ static bool core_handle_note(struct ps_prochandle* ph, ELF_PHDR* note_phdr) { // We will adjust it in read_exec_segments(). ph->core->dynamic_addr = auxv->a_un.a_val; break; + } else if (auxv->a_type == AT_SYSINFO_EHDR) { + ph->core->vdso_addr = auxv->a_un.a_val; } auxv++; } @@ -350,6 +355,10 @@ static bool read_core_segments(struct ps_prochandle* ph, ELF_EHDR* core_ehdr) { print_error("failed to add map info\n"); goto err; } + if (core_php->p_vaddr == ph->core->vdso_addr) { + ph->core->vdso_offset = core_php->p_offset; + ph->core->vdso_size = core_php->p_memsz; + } } break; } @@ -687,9 +696,40 @@ static bool read_shared_lib_info(struct ps_prochandle* ph) { // it will fail later. } - if (lib_name[0] != '\0') { - // ignore empty lib names - lib_fd = pathmap_open(lib_name); + if (lib_name[0] != '\0') { // ignore empty lib names + if (strcmp("linux-vdso.so.1", lib_name) == 0 || + strcmp("linux-vdso64.so.1", lib_name) == 0) { + struct utsname uts; + uname(&uts); + + const char *vdso_name +#ifdef _LP64 + = "vdso64.so"; +#else + = "vdso32.so"; +#endif + + // Check vDSO binary at first (for referring debuginfo if possible). + char vdso_path[PATH_MAX]; + snprintf(vdso_path, sizeof(vdso_path), "/lib/modules/%s/vdso/%s", uts.release, vdso_name); + if (access(vdso_path, F_OK) == 0) { + print_debug("replace vDSO: %s -> %s\n", lib_name, vdso_path); + strcpy(lib_name, vdso_path); + lib_fd = pathmap_open(lib_name); + } else { + // Copy vDSO memory segment to temporal memory from core + // if vDSO binary is not available. + lib_fd = memfd_create("[vdso] in core", 0); + off64_t ofs = ph->core->vdso_offset; + if (sendfile64(lib_fd, ph->core->core_fd, &ofs, ph->core->vdso_size) == -1) { + print_debug("can't copy vDSO (%d)\n", errno); + close(lib_fd); + lib_fd = -1; + } + } + } else { + lib_fd = pathmap_open(lib_name); + } if (lib_fd < 0) { print_debug("can't open shared object %s\n", lib_name); diff --git a/test/hotspot/jtreg/serviceability/sa/LingeredAppWithVDSOCall.java b/test/hotspot/jtreg/serviceability/sa/LingeredAppWithVDSOCall.java new file mode 100644 index 00000000000..d893ddf6f89 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/sa/LingeredAppWithVDSOCall.java @@ -0,0 +1,61 @@ + +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2026, NTT DATA + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.lang.invoke.MethodHandle; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.ValueLayout; + +import jdk.test.lib.Asserts; +import jdk.test.lib.apps.LingeredApp; + + +public class LingeredAppWithVDSOCall extends LingeredApp { + + private static final MethodHandle gettimeofday; + + static { + var desc = FunctionDescriptor.of(ValueLayout.JAVA_INT, // return + ValueLayout.JAVA_LONG, // tv + ValueLayout.JAVA_LONG); // tz + var linker = Linker.nativeLinker(); + var gettimeofdayPtr = linker.defaultLookup().findOrThrow("gettimeofday"); + gettimeofday = linker.downcallHandle(gettimeofdayPtr, desc); + } + + private static void crashAtGettimeofday(long tvAddr, long tzAddr) { + try { + gettimeofday.invoke(tvAddr, tzAddr); + } catch (Throwable t) { + throw new RuntimeException(t); + } + Asserts.fail("gettimeofday() didn't crash"); + } + + public static void main(String[] args) { + setCrasher(() -> crashAtGettimeofday(100L, 200L)); + LingeredApp.main(args); + } +} diff --git a/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedWithVDSOCallCore.java b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedWithVDSOCallCore.java new file mode 100644 index 00000000000..f55ec716f84 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/sa/TestJhsdbJstackMixedWithVDSOCallCore.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2026, NTT DATA + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import jdk.test.lib.JDKToolFinder; +import jdk.test.lib.JDKToolLauncher; +import jdk.test.lib.SA.SATestUtils; +import jdk.test.lib.Utils; +import jdk.test.lib.apps.LingeredApp; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.util.CoreUtils; + +/** + * @test + * @bug 8376269 + * @requires (os.family == "linux") & (vm.hasSA) + * @requires os.arch == "amd64" + * @library /test/lib + * @run driver TestJhsdbJstackMixedWithVDSOCallCore + */ +public class TestJhsdbJstackMixedWithVDSOCallCore { + + private static void runJstackMixed(String coreFileName) throws Exception { + JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jhsdb"); + launcher.addVMArgs(Utils.getTestJavaOpts()); + launcher.addToolArg("jstack"); + launcher.addToolArg("--mixed"); + launcher.addToolArg("--exe"); + launcher.addToolArg(JDKToolFinder.getTestJDKTool("java")); + launcher.addToolArg("--core"); + launcher.addToolArg(coreFileName); + + ProcessBuilder pb = SATestUtils.createProcessBuilder(launcher); + Process jhsdb = pb.start(); + OutputAnalyzer out = new OutputAnalyzer(jhsdb); + + jhsdb.waitFor(); + + System.out.println(out.getStdout()); + System.err.println(out.getStderr()); + + out.shouldContain("vdso_gettimeofday"); + } + + public static void main(String... args) throws Throwable { + var app = new LingeredAppWithVDSOCall(); + app.setForceCrash(true); + LingeredApp.startApp(app, CoreUtils.getAlwaysPretouchArg(true)); + app.waitAppTerminate(); + + String crashOutput = app.getOutput().getStdout(); + String coreFileName = CoreUtils.getCoreFileLocation(crashOutput, app.getPid()); + runJstackMixed(coreFileName); + } +} diff --git a/test/lib/jdk/test/lib/apps/LingeredApp.java b/test/lib/jdk/test/lib/apps/LingeredApp.java index 13008e68c54..38ad9ae5b0e 100644 --- a/test/lib/jdk/test/lib/apps/LingeredApp.java +++ b/test/lib/jdk/test/lib/apps/LingeredApp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -122,6 +122,12 @@ public class LingeredApp { this.forceCrash = forceCrash; } + private static Runnable crasher; + + public static void setCrasher(Runnable runnable) { + crasher = runnable; + } + native private static int crash(); /** @@ -628,8 +634,12 @@ public class LingeredApp { synchronized(steadyStateObj) { startSteadyStateThread(steadyStateObj); if (forceCrash) { - System.loadLibrary("LingeredApp"); // location of native crash() method - crash(); + if (crasher == null) { + System.loadLibrary("LingeredApp"); // location of native crash() method + crash(); + } else { + crasher.run(); + } } while (Files.exists(path)) { // Touch the lock to indicate our readiness