8315706: com/sun/tools/attach/warnings/DynamicLoadWarningTest.java real fix for failure on AIX

Reviewed-by: dholmes, mbaesken
This commit is contained in:
Joachim Kern 2023-09-18 11:57:48 +00:00 committed by Matthias Baesken
parent ecce2afc1a
commit 21c2dac159
7 changed files with 110 additions and 12 deletions

@ -3043,3 +3043,32 @@ void os::print_memory_mappings(char* addr, size_t bytes, outputStream* st) {}
void os::jfr_report_memory_info() {}
#endif // INCLUDE_JFR
// Simulate the library search algorithm of dlopen() (in os::dll_load)
int os::Aix::stat64x_via_LIBPATH(const char* path, struct stat64x* stat) {
if (path[0] == '/' ||
(path[0] == '.' && (path[1] == '/' ||
(path[1] == '.' && path[2] == '/')))) {
return stat64x(path, stat);
}
const char* env = getenv("LIBPATH");
if (env == nullptr || *env == 0)
return -1;
int ret = -1;
size_t libpathlen = strlen(env);
char* libpath = NEW_C_HEAP_ARRAY(char, libpathlen + 1, mtServiceability);
char* combined = NEW_C_HEAP_ARRAY(char, libpathlen + strlen(path) + 1, mtServiceability);
char *saveptr, *token;
strcpy(libpath, env);
for (token = strtok_r(libpath, ":", &saveptr); token != nullptr; token = strtok_r(nullptr, ":", &saveptr)) {
sprintf(combined, "%s/%s", token, path);
if (0 == (ret = stat64x(combined, stat)))
break;
}
FREE_C_HEAP_ARRAY(char*, combined);
FREE_C_HEAP_ARRAY(char*, libpath);
return ret;
}

@ -1,6 +1,6 @@
/*
* Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2016 SAP SE. All rights reserved.
* Copyright (c) 2013, 2023 SAP SE. 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
@ -174,6 +174,9 @@ class os::Aix {
static bool platform_print_native_stack(outputStream* st, const void* context, char *buf, int buf_size, address& lastpc);
static void* resolve_function_descriptor(void* p);
// Simulate the library search algorithm of dlopen() (in os::dll_load)
static int stat64x_via_LIBPATH(const char* path, struct stat64x* stat);
};
#endif // OS_AIX_OS_AIX_HPP

@ -74,6 +74,10 @@ JvmtiAgent::JvmtiAgent(const char* name, const char* options, bool is_absolute_p
_options(copy_string(options)),
_os_lib(nullptr),
_os_lib_path(nullptr),
#ifdef AIX
_inode(0),
_device(0),
#endif
_jplis(nullptr),
_loaded(false),
_absolute_path(is_absolute_path),
@ -118,6 +122,24 @@ const char* JvmtiAgent::os_lib_path() const {
return _os_lib_path;
}
#ifdef AIX
void JvmtiAgent::set_inode(ino64_t inode) {
_inode = inode;
}
void JvmtiAgent::set_device(dev64_t device) {
_device = device;
}
ino64_t JvmtiAgent::inode() const {
return _inode;
}
dev64_t JvmtiAgent::device() const {
return _device;
}
#endif
bool JvmtiAgent::is_loaded() const {
return _loaded;
}
@ -272,6 +294,20 @@ static bool load_agent_from_executable(JvmtiAgent* agent, const char* on_load_sy
return os::find_builtin_agent(agent, &on_load_symbols[0], num_symbol_entries);
}
#ifdef AIX
// save the inode and device of the library's file as a signature. This signature can be used
// in the same way as the library handle as a signature on other platforms.
static void save_library_signature(JvmtiAgent* agent, const char* name) {
struct stat64x libstat;
if (0 == os::Aix::stat64x_via_LIBPATH(name, &libstat)) {
agent->set_inode(libstat.st_ino);
agent->set_device(libstat.st_dev);
} else {
assert(false, "stat64x failed");
}
}
#endif
// Load the library from the absolute path of the agent, if available.
static void* load_agent_from_absolute_path(JvmtiAgent* agent, bool vm_exit_on_error) {
DEBUG_ONLY(assert_preload(agent);)
@ -281,6 +317,7 @@ static void* load_agent_from_absolute_path(JvmtiAgent* agent, bool vm_exit_on_er
if (library == nullptr && vm_exit_on_error) {
vm_exit(agent, " in absolute path, with error: ", nullptr);
}
AIX_ONLY(if (library != nullptr) save_library_signature(agent, agent->name());)
return library;
}
@ -293,11 +330,13 @@ static void* load_agent_from_relative_path(JvmtiAgent* agent, bool vm_exit_on_er
// Try to load the agent from the standard dll directory
if (os::dll_locate_lib(&buffer[0], sizeof buffer, Arguments::get_dll_dir(), name)) {
library = os::dll_load(&buffer[0], &ebuf[0], sizeof ebuf);
AIX_ONLY(if (library != nullptr) save_library_signature(agent, &buffer[0]);)
}
if (library == nullptr && os::dll_build_name(&buffer[0], sizeof buffer, name)) {
// Try the library path directory.
library = os::dll_load(&buffer[0], &ebuf[0], sizeof ebuf);
if (library != nullptr) {
AIX_ONLY(save_library_signature(agent, &buffer[0]);)
return library;
}
if (vm_exit_on_error) {
@ -515,7 +554,11 @@ static bool invoke_Agent_OnAttach(JvmtiAgent* agent, outputStream* st) {
agent->set_os_lib_path(&buffer[0]);
agent->set_os_lib(library);
agent->set_loaded();
#ifdef AIX
previously_loaded = JvmtiAgentList::is_dynamic_lib_loaded(agent->device(), agent->inode());
#else
previously_loaded = JvmtiAgentList::is_dynamic_lib_loaded(library);
#endif
}
// Print warning if agent was not previously loaded and EnableDynamicAgentLoading not enabled on the command line.

@ -43,6 +43,10 @@ class JvmtiAgent : public CHeapObj<mtServiceability> {
const char* _options;
void* _os_lib;
const char* _os_lib_path;
#ifdef AIX
ino64_t _inode;
dev64_t _device;
#endif
const void* _jplis;
bool _loaded;
bool _absolute_path;
@ -80,6 +84,12 @@ class JvmtiAgent : public CHeapObj<mtServiceability> {
void initialization_end();
const Ticks& initialization_time() const;
const Tickspan& initialization_duration() const;
#ifdef AIX
void set_inode(ino64_t inode);
void set_device(dev64_t device);
unsigned long inode() const;
unsigned long device() const;
#endif
bool load(outputStream* st = nullptr);
void unload();

@ -243,6 +243,19 @@ bool JvmtiAgentList::is_dynamic_lib_loaded(void* os_lib) {
}
return false;
}
#ifdef AIX
bool JvmtiAgentList::is_dynamic_lib_loaded(dev64_t device, ino64_t inode) {
JvmtiAgentList::Iterator it = JvmtiAgentList::agents();
while (it.has_next()) {
JvmtiAgent* const agent = it.next();
if (!agent->is_static_lib() && device != 0 && inode != 0 &&
agent->device() == device && agent->inode() == inode) {
return true;
}
}
return false;
}
#endif
static bool match(JvmtiEnv* env, const JvmtiAgent* agent, const void* os_module_address) {
assert(env != nullptr, "invariant");

@ -78,6 +78,9 @@ class JvmtiAgentList : AllStatic {
static bool is_static_lib_loaded(const char* name);
static bool is_dynamic_lib_loaded(void* os_lib);
#ifdef AIX
static bool is_dynamic_lib_loaded(dev64_t device, ino64_t inode);
#endif
static JvmtiAgent* lookup(JvmtiEnv* env, void* f_ptr);

@ -123,18 +123,15 @@ class DynamicLoadWarningTest {
.whenRunning(loadJvmtiAgent1)
.stderrShouldNotContain(JVMTI_AGENT_WARNING);
// test behavior on platforms that can detect if an agent library was previously loaded
if (!Platform.isAix()) {
// start loadJvmtiAgent1 via the command line, then dynamically load loadJvmtiAgent1
test().withOpts("-agentpath:" + jvmtiAgentPath1)
.whenRunning(loadJvmtiAgent1)
.stderrShouldNotContain(JVMTI_AGENT_WARNING);
// start loadJvmtiAgent1 via the command line, then dynamically load loadJvmtiAgent1
test().withOpts("-agentpath:" + jvmtiAgentPath1)
.whenRunning(loadJvmtiAgent1)
.stderrShouldNotContain(JVMTI_AGENT_WARNING);
// dynamically load loadJvmtiAgent1 twice, should be one warning
test().whenRunning(loadJvmtiAgent1)
.whenRunning(loadJvmtiAgent1)
.stderrShouldContain(JVMTI_AGENT_WARNING, 1);
}
// dynamically load loadJvmtiAgent1 twice, should be one warning
test().whenRunning(loadJvmtiAgent1)
.whenRunning(loadJvmtiAgent1)
.stderrShouldContain(JVMTI_AGENT_WARNING, 1);
}
/**