Skip to content

Commit

Permalink
8313251: Add NativeLibraryLoad event
Browse files Browse the repository at this point in the history
Reviewed-by: jbechberger, egahlin, dholmes
  • Loading branch information
MBaesken committed Aug 4, 2023
1 parent c4b8574 commit 5d23295
Show file tree
Hide file tree
Showing 9 changed files with 218 additions and 2 deletions.
21 changes: 21 additions & 0 deletions src/hotspot/os/aix/os_aix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -1114,13 +1117,25 @@ 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) {
Events::log_dll_message(nullptr, "Loaded shared library %s", filename);
// 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
Expand All @@ -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;
}
Expand Down
32 changes: 31 additions & 1 deletion src/hotspot/os/bsd/os_bsd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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
Expand All @@ -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;
}

Expand All @@ -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);

Expand Down
16 changes: 16 additions & 0 deletions src/hotspot/os/linux/os_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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;
}
Expand Down
35 changes: 34 additions & 1 deletion src/hotspot/os/windows/os_windows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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;
}

Expand All @@ -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;
}

Expand All @@ -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;
}

Expand Down Expand Up @@ -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;
}

Expand All @@ -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;
}
Expand Down
7 changes: 7 additions & 0 deletions src/hotspot/share/jfr/metadata/metadata.xml
Original file line number Diff line number Diff line change
Expand Up @@ -939,6 +939,13 @@
<Field type="ulong" contentType="address" name="topAddress" label="Top Address" description="Ending address of the module, if available" />
</Event>

<Event name="NativeLibraryLoad" category="Java Virtual Machine, Runtime" label="Native Library Load" thread="false" stackTrace="true" startTime="true"

This comment has been minimized.

Copy link
@mgronlun

mgronlun Sep 1, 2023

Why were the events declared without thread information but including a stack trace?

This comment has been minimized.

Copy link
@MBaesken

MBaesken Sep 1, 2023

Author Member

I found the stacktrace useful, because e.g. in the os::dl_load cases that were instrumented I wanted to see where the call is really coming from, this is sometimes helpful to understand what is going on.
Regarding the thread information, I was just not so sure about the usefulness in this case, but maybe there are good arguments to set it to true as well .

description="Information about a dynamic library or other native image load operation">
<Field type="string" name="name" label="Name" />
<Field type="boolean" name="success" label="Success" description="Success or failure of the load operation" />
<Field type="string" name="errorMessage" label="Error Message" description="In case of a load error, error description" />
</Event>

<Event name="ModuleRequire" category="Java Virtual Machine, Runtime, Modules" label="Module Require" thread="false" period="everyChunk"
description="A directed edge representing a dependency">
<Field type="Module" name="source" label="Source Module" />
Expand Down
6 changes: 6 additions & 0 deletions src/jdk.jfr/share/conf/jfr/default.jfc
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,12 @@
<setting name="period">everyChunk</setting>
</event>

<event name="jdk.NativeLibraryLoad">
<setting name="enabled">true</setting>
<setting name="stackTrace">true</setting>
<setting name="threshold">0 ms</setting>
</event>

<event name="jdk.ModuleRequire">
<setting name="enabled">true</setting>
<setting name="period">endChunk</setting>
Expand Down
6 changes: 6 additions & 0 deletions src/jdk.jfr/share/conf/jfr/profile.jfc
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,12 @@
<setting name="period">everyChunk</setting>
</event>

<event name="jdk.NativeLibraryLoad">
<setting name="enabled">true</setting>
<setting name="stackTrace">true</setting>
<setting name="threshold">0 ms</setting>
</event>

<event name="jdk.ModuleRequire">
<setting name="enabled">true</setting>
<setting name="period">endChunk</setting>
Expand Down
96 changes: 96 additions & 0 deletions test/jdk/jdk/jfr/event/runtime/TestNativeLibraryLoadEvent.java
Original file line number Diff line number Diff line change
@@ -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<String> 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<String> 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<String> libs = new ArrayList<String>();
String[] names = { "instrument" };
for (String name : names) {
libs.add(String.format(libTemplate, name));
}
return libs;
}

}
1 change: 1 addition & 0 deletions test/lib/jdk/test/lib/jfr/EventNames.java
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down

3 comments on commit 5d23295

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MBaesken
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/backport jdk21u

@openjdk
Copy link

@openjdk openjdk bot commented on 5d23295 Aug 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MBaesken the backport was successfully created on the branch MBaesken-backport-5d232959 in my personal fork of openjdk/jdk21u. To create a pull request with this backport targeting openjdk/jdk21u:master, just click the following link:

➡️ Create pull request

The title of the pull request is automatically filled in correctly and below you find a suggestion for the pull request body:

Hi all,

This pull request contains a backport of commit 5d232959 from the openjdk/jdk repository.

The commit being backported was authored by Matthias Baesken on 4 Aug 2023 and was reviewed by Johannes Bechberger, Erik Gahlin and David Holmes.

Thanks!

If you need to update the source branch of the pull then run the following commands in a local clone of your personal fork of openjdk/jdk21u:

$ git fetch https://github.com/openjdk-bots/jdk21u.git MBaesken-backport-5d232959:MBaesken-backport-5d232959
$ git checkout MBaesken-backport-5d232959
# make changes
$ git add paths/to/changed/files
$ git commit --message 'Describe additional changes made'
$ git push https://github.com/openjdk-bots/jdk21u.git MBaesken-backport-5d232959

Please sign in to comment.