From 5d232959c2d98b632a5c48c89f369f7e80c8b68f Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Fri, 4 Aug 2023 07:03:25 +0000 Subject: [PATCH] 8313251: Add NativeLibraryLoad event Reviewed-by: jbechberger, egahlin, dholmes --- src/hotspot/os/aix/os_aix.cpp | 21 ++++ src/hotspot/os/bsd/os_bsd.cpp | 32 ++++++- src/hotspot/os/linux/os_linux.cpp | 16 ++++ src/hotspot/os/windows/os_windows.cpp | 35 ++++++- src/hotspot/share/jfr/metadata/metadata.xml | 7 ++ src/jdk.jfr/share/conf/jfr/default.jfc | 6 ++ src/jdk.jfr/share/conf/jfr/profile.jfc | 6 ++ .../runtime/TestNativeLibraryLoadEvent.java | 96 +++++++++++++++++++ test/lib/jdk/test/lib/jfr/EventNames.java | 1 + 9 files changed, 218 insertions(+), 2 deletions(-) create mode 100644 test/jdk/jdk/jfr/event/runtime/TestNativeLibraryLoadEvent.java diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index fef735ca101..e657431f125 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -79,6 +79,9 @@ #include "utilities/events.hpp" #include "utilities/growableArray.hpp" #include "utilities/vmError.hpp" +#if INCLUDE_JFR +#include "jfr/jfrEvents.hpp" +#endif // put OS-includes here (sorted alphabetically) #ifdef AIX_XLC_GE_17 @@ -1114,6 +1117,11 @@ void *os::dll_load(const char *filename, char *ebuf, int ebuflen) { return nullptr; } +#if INCLUDE_JFR + EventNativeLibraryLoad event; + event.set_name(filename); +#endif + // RTLD_LAZY is currently not implemented. The dl is loaded immediately with all its dependants. void * result= ::dlopen(filename, RTLD_LAZY); if (result != nullptr) { @@ -1121,6 +1129,13 @@ void *os::dll_load(const char *filename, char *ebuf, int ebuflen) { // Reload dll cache. Don't do this in signal handling. LoadedLibraries::reload(); log_info(os)("shared library load of %s was successful", filename); + +#if INCLUDE_JFR + event.set_success(true); + event.set_errorMessage(nullptr); + event.commit(); +#endif + return result; } else { // error analysis when dlopen fails @@ -1134,6 +1149,12 @@ void *os::dll_load(const char *filename, char *ebuf, int ebuflen) { } Events::log_dll_message(nullptr, "Loading shared library %s failed, %s", filename, error_report); log_info(os)("shared library load of %s failed, %s", filename, error_report); + +#if INCLUDE_JFR + event.set_success(false); + event.set_errorMessage(error_report); + event.commit(); +#endif } return nullptr; } diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index 79ea61c2536..6e0fca59e91 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -979,11 +979,21 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) { #else log_info(os)("attempting shared library load of %s", filename); +#if INCLUDE_JFR + EventNativeLibraryLoad event; + event.set_name(filename); +#endif + void * result= ::dlopen(filename, RTLD_LAZY); if (result != nullptr) { Events::log_dll_message(nullptr, "Loaded shared library %s", filename); // Successful loading log_info(os)("shared library load of %s was successful", filename); +#if INCLUDE_JFR + event.set_success(true); + event.set_errorMessage(nullptr); + event.commit(); +#endif return result; } @@ -998,6 +1008,11 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) { } Events::log_dll_message(nullptr, "Loading shared library %s failed, %s", filename, error_report); log_info(os)("shared library load of %s failed, %s", filename, error_report); +#if INCLUDE_JFR + event.set_success(false); + event.set_errorMessage(error_report); + event.commit(); +#endif return nullptr; #endif // STATIC_BUILD @@ -1008,11 +1023,22 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) { return os::get_default_process_handle(); #else log_info(os)("attempting shared library load of %s", filename); + +#if INCLUDE_JFR + EventNativeLibraryLoad event; + event.set_name(filename); +#endif + void * result= ::dlopen(filename, RTLD_LAZY); if (result != nullptr) { Events::log_dll_message(nullptr, "Loaded shared library %s", filename); // Successful loading log_info(os)("shared library load of %s was successful", filename); +#if INCLUDE_JFR + event.set_success(true); + event.set_errorMessage(nullptr); + event.commit(); +#endif return result; } @@ -1029,7 +1055,11 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) { } Events::log_dll_message(nullptr, "Loading shared library %s failed, %s", filename, error_report); log_info(os)("shared library load of %s failed, %s", filename, error_report); - +#if INCLUDE_JFR + event.set_success(false); + event.set_errorMessage(error_report); + event.commit(); +#endif int diag_msg_max_length=ebuflen-strlen(ebuf); char* diag_msg_buf=ebuf+strlen(ebuf); diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 5e5aac601e9..9dbe0428919 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -1795,6 +1795,12 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) { void * os::Linux::dlopen_helper(const char *filename, char *ebuf, int ebuflen) { void * result = ::dlopen(filename, RTLD_LAZY); + +#if INCLUDE_JFR + EventNativeLibraryLoad event; + event.set_name(filename); +#endif + if (result == nullptr) { const char* error_report = ::dlerror(); if (error_report == nullptr) { @@ -1806,9 +1812,19 @@ void * os::Linux::dlopen_helper(const char *filename, char *ebuf, } Events::log_dll_message(nullptr, "Loading shared library %s failed, %s", filename, error_report); log_info(os)("shared library load of %s failed, %s", filename, error_report); +#if INCLUDE_JFR + event.set_success(false); + event.set_errorMessage(error_report); + event.commit(); +#endif } else { Events::log_dll_message(nullptr, "Loaded shared library %s", filename); log_info(os)("shared library load of %s was successful", filename); +#if INCLUDE_JFR + event.set_success(true); + event.set_errorMessage(nullptr); + event.commit(); +#endif } return result; } diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 1333d651b03..445b8589893 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -1528,13 +1528,21 @@ static int _print_module(const char* fname, address base_address, // same architecture as Hotspot is running on void * os::dll_load(const char *name, char *ebuf, int ebuflen) { log_info(os)("attempting shared library load of %s", name); - +#if INCLUDE_JFR + EventNativeLibraryLoad event; + event.set_name(name); +#endif void * result = LoadLibrary(name); if (result != nullptr) { Events::log_dll_message(nullptr, "Loaded shared library %s", name); // Recalculate pdb search path if a DLL was loaded successfully. SymbolEngine::recalc_search_path(); log_info(os)("shared library load of %s was successful", name); +#if INCLUDE_JFR + event.set_success(true); + event.set_errorMessage(nullptr); + event.commit(); +#endif return result; } DWORD errcode = GetLastError(); @@ -1548,6 +1556,11 @@ void * os::dll_load(const char *name, char *ebuf, int ebuflen) { if (errcode == ERROR_MOD_NOT_FOUND) { strncpy(ebuf, "Can't find dependent libraries", ebuflen - 1); ebuf[ebuflen - 1] = '\0'; +#if INCLUDE_JFR + event.set_success(false); + event.set_errorMessage(ebuf); + event.commit(); +#endif return nullptr; } @@ -1558,6 +1571,11 @@ void * os::dll_load(const char *name, char *ebuf, int ebuflen) { // else call os::lasterror to obtain system error message int fd = ::open(name, O_RDONLY | O_BINARY, 0); if (fd < 0) { +#if INCLUDE_JFR + event.set_success(false); + event.set_errorMessage("open on dll file did not work"); + event.commit(); +#endif return nullptr; } @@ -1584,6 +1602,11 @@ void * os::dll_load(const char *name, char *ebuf, int ebuflen) { ::close(fd); if (failed_to_get_lib_arch) { // file i/o error - report os::lasterror(...) msg +#if INCLUDE_JFR + event.set_success(false); + event.set_errorMessage("failed to get lib architecture"); + event.commit(); +#endif return nullptr; } @@ -1628,6 +1651,11 @@ void * os::dll_load(const char *name, char *ebuf, int ebuflen) { // If the architecture is right // but some other error took place - report os::lasterror(...) msg if (lib_arch == running_arch) { +#if INCLUDE_JFR + event.set_success(false); + event.set_errorMessage("lib architecture matches, but other error occured"); + event.commit(); +#endif return nullptr; } @@ -1641,6 +1669,11 @@ void * os::dll_load(const char *name, char *ebuf, int ebuflen) { "Can't load this .dll (machine code=0x%x) on a %s-bit platform", lib_arch, running_arch_str); } +#if INCLUDE_JFR + event.set_success(false); + event.set_errorMessage(ebuf); + event.commit(); +#endif return nullptr; } diff --git a/src/hotspot/share/jfr/metadata/metadata.xml b/src/hotspot/share/jfr/metadata/metadata.xml index 47245923da4..70715294a5e 100644 --- a/src/hotspot/share/jfr/metadata/metadata.xml +++ b/src/hotspot/share/jfr/metadata/metadata.xml @@ -939,6 +939,13 @@ + + + + + + diff --git a/src/jdk.jfr/share/conf/jfr/default.jfc b/src/jdk.jfr/share/conf/jfr/default.jfc index 5743b64285b..ba3eb50e53f 100644 --- a/src/jdk.jfr/share/conf/jfr/default.jfc +++ b/src/jdk.jfr/share/conf/jfr/default.jfc @@ -694,6 +694,12 @@ everyChunk + + true + true + 0 ms + + true endChunk diff --git a/src/jdk.jfr/share/conf/jfr/profile.jfc b/src/jdk.jfr/share/conf/jfr/profile.jfc index 816408a4baf..5563b690569 100644 --- a/src/jdk.jfr/share/conf/jfr/profile.jfc +++ b/src/jdk.jfr/share/conf/jfr/profile.jfc @@ -694,6 +694,12 @@ everyChunk + + true + true + 0 ms + + true endChunk diff --git a/test/jdk/jdk/jfr/event/runtime/TestNativeLibraryLoadEvent.java b/test/jdk/jdk/jfr/event/runtime/TestNativeLibraryLoadEvent.java new file mode 100644 index 00000000000..89c7877b6d4 --- /dev/null +++ b/test/jdk/jdk/jfr/event/runtime/TestNativeLibraryLoadEvent.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2023, 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 + * 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. + */ + +package jdk.jfr.event.runtime; + +import static jdk.test.lib.Asserts.assertTrue; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; +import jdk.test.lib.Platform; +import jdk.test.lib.jfr.EventNames; +import jdk.test.lib.jfr.Events; + +/** + * @test + * @bug 8313251 + * @key jfr + * @requires vm.hasJFR + * @library /test/lib + * @run main/othervm jdk.jfr.event.runtime.TestNativeLibraryLoadEvent + */ +public class TestNativeLibraryLoadEvent { + + private final static String EVENT_NAME = EventNames.NativeLibraryLoad; + + public static void main(String[] args) throws Throwable { + try (Recording recording = new Recording()) { + recording.enable(EVENT_NAME); + recording.start(); + System.loadLibrary("instrument"); + recording.stop(); + + List expectedLibs = getExpectedLibs(); + for (RecordedEvent event : Events.fromRecording(recording)) { + System.out.println("Event:" + event); + String lib = Events.assertField(event, "name").notEmpty().getValue(); + Events.assertField(event, "success"); + for (String expectedLib : new ArrayList<>(expectedLibs)) { + if (lib.contains(expectedLib)) { + expectedLibs.remove(expectedLib); + } + } + } + assertTrue(expectedLibs.isEmpty(), "Missing libraries:" + expectedLibs.stream().collect(Collectors.joining(", "))); + } + } + + private static List getExpectedLibs() throws Throwable { + String libTemplate = null; + if (Platform.isWindows()) { + libTemplate = "%s.dll"; + } else if (Platform.isOSX()) { + libTemplate = "lib%s.dylib"; + } else if (Platform.isLinux()) { + libTemplate = "lib%s.so"; + } else if (Platform.isAix()) { + libTemplate = "lib%s.so"; + } + + if (libTemplate == null) { + throw new Exception("Unsupported OS"); + } + + List libs = new ArrayList(); + String[] names = { "instrument" }; + for (String name : names) { + libs.add(String.format(libTemplate, name)); + } + return libs; + } + +} diff --git a/test/lib/jdk/test/lib/jfr/EventNames.java b/test/lib/jdk/test/lib/jfr/EventNames.java index 10c7ee20a01..f0978d189d7 100644 --- a/test/lib/jdk/test/lib/jfr/EventNames.java +++ b/test/lib/jdk/test/lib/jfr/EventNames.java @@ -183,6 +183,7 @@ public class EventNames { public static final String ThreadContextSwitchRate = PREFIX + "ThreadContextSwitchRate"; public static final String InitialEnvironmentVariable = PREFIX + "InitialEnvironmentVariable"; public static final String NativeLibrary = PREFIX + "NativeLibrary"; + public static final String NativeLibraryLoad = PREFIX + "NativeLibraryLoad"; public static final String PhysicalMemory = PREFIX + "PhysicalMemory"; public static final String NetworkUtilization = PREFIX + "NetworkUtilization"; public static final String ProcessStart = PREFIX + "ProcessStart";