8320890: [AIX] Find a better way to mimic dl handle equality
Reviewed-by: stuefe, mdoerr
This commit is contained in:
parent
e5aed6be7a
commit
b8ae4a8c09
@ -1118,7 +1118,9 @@ void *os::dll_load(const char *filename, char *ebuf, int ebuflen) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!filename || strlen(filename) == 0) {
|
if (!filename || strlen(filename) == 0) {
|
||||||
::strncpy(ebuf, "dll_load: empty filename specified", ebuflen - 1);
|
if (ebuf != nullptr && ebuflen > 0) {
|
||||||
|
::strncpy(ebuf, "dll_load: empty filename specified", ebuflen - 1);
|
||||||
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1133,8 +1135,9 @@ void *os::dll_load(const char *filename, char *ebuf, int ebuflen) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void* result;
|
void* result;
|
||||||
|
const char* error_report = nullptr;
|
||||||
JFR_ONLY(NativeLibraryLoadEvent load_event(filename, &result);)
|
JFR_ONLY(NativeLibraryLoadEvent load_event(filename, &result);)
|
||||||
result = ::dlopen(filename, dflags);
|
result = Aix_dlopen(filename, dflags, &error_report);
|
||||||
if (result != nullptr) {
|
if (result != nullptr) {
|
||||||
Events::log_dll_message(nullptr, "Loaded shared library %s", filename);
|
Events::log_dll_message(nullptr, "Loaded shared library %s", filename);
|
||||||
// Reload dll cache. Don't do this in signal handling.
|
// Reload dll cache. Don't do this in signal handling.
|
||||||
@ -1143,7 +1146,6 @@ void *os::dll_load(const char *filename, char *ebuf, int ebuflen) {
|
|||||||
return result;
|
return result;
|
||||||
} else {
|
} else {
|
||||||
// error analysis when dlopen fails
|
// error analysis when dlopen fails
|
||||||
const char* error_report = ::dlerror();
|
|
||||||
if (error_report == nullptr) {
|
if (error_report == nullptr) {
|
||||||
error_report = "dlerror returned no error description";
|
error_report = "dlerror returned no error description";
|
||||||
}
|
}
|
||||||
@ -3026,31 +3028,3 @@ void os::jfr_report_memory_info() {}
|
|||||||
|
|
||||||
#endif // INCLUDE_JFR
|
#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;
|
|
||||||
}
|
|
||||||
|
@ -175,8 +175,6 @@ class os::Aix {
|
|||||||
static bool platform_print_native_stack(outputStream* st, const void* context, char *buf, int buf_size, address& lastpc);
|
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);
|
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
|
#endif // OS_AIX_OS_AIX_HPP
|
||||||
|
@ -21,6 +21,12 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
// needs to be defined first, so that the implicit loaded xcoff.h header defines
|
||||||
|
// the right structures to analyze the loader header of 64 Bit executable files
|
||||||
|
// this is needed for rtv_linkedin_libpath() to get the linked (burned) in library
|
||||||
|
// search path of an XCOFF executable
|
||||||
|
#define __XCOFF64__
|
||||||
|
#include <xcoff.h>
|
||||||
|
|
||||||
#include "asm/assembler.hpp"
|
#include "asm/assembler.hpp"
|
||||||
#include "compiler/disassembler.hpp"
|
#include "compiler/disassembler.hpp"
|
||||||
@ -891,3 +897,275 @@ bool AixMisc::query_stack_bounds_for_current_thread(stackbounds_t* out) {
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// variables needed to emulate linux behavior in os::dll_load() if library is loaded twice
|
||||||
|
static pthread_mutex_t g_handletable_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
struct TableLocker {
|
||||||
|
TableLocker() { pthread_mutex_lock(&g_handletable_mutex); }
|
||||||
|
~TableLocker() { pthread_mutex_unlock(&g_handletable_mutex); }
|
||||||
|
};
|
||||||
|
struct handletableentry{
|
||||||
|
void* handle;
|
||||||
|
ino64_t inode;
|
||||||
|
dev64_t devid;
|
||||||
|
uint refcount;
|
||||||
|
};
|
||||||
|
constexpr unsigned init_num_handles = 128;
|
||||||
|
static unsigned max_handletable = 0;
|
||||||
|
static unsigned g_handletable_used = 0;
|
||||||
|
// We start with an empty array. At first use we will dynamically allocate memory for 128 entries.
|
||||||
|
// If this table is full we dynamically reallocate a memory reagion of double size, and so on.
|
||||||
|
static struct handletableentry* p_handletable = nullptr;
|
||||||
|
|
||||||
|
// get the library search path burned in to the executable file during linking
|
||||||
|
// If the libpath cannot be retrieved return an empty path
|
||||||
|
static const char* rtv_linkedin_libpath() {
|
||||||
|
constexpr int bufsize = 4096;
|
||||||
|
static char buffer[bufsize];
|
||||||
|
static const char* libpath = 0;
|
||||||
|
|
||||||
|
// we only try to retrieve the libpath once. After that try we
|
||||||
|
// let libpath point to buffer, which then contains a valid libpath
|
||||||
|
// or an empty string
|
||||||
|
if (libpath != nullptr) {
|
||||||
|
return libpath;
|
||||||
|
}
|
||||||
|
|
||||||
|
// retrieve the path to the currently running executable binary
|
||||||
|
// to open it
|
||||||
|
snprintf(buffer, 100, "/proc/%ld/object/a.out", (long)getpid());
|
||||||
|
FILE* f = nullptr;
|
||||||
|
struct xcoffhdr the_xcoff;
|
||||||
|
struct scnhdr the_scn;
|
||||||
|
struct ldhdr the_ldr;
|
||||||
|
constexpr size_t xcoffsz = FILHSZ + _AOUTHSZ_EXEC;
|
||||||
|
STATIC_ASSERT(sizeof(the_xcoff) == xcoffsz);
|
||||||
|
STATIC_ASSERT(sizeof(the_scn) == SCNHSZ);
|
||||||
|
STATIC_ASSERT(sizeof(the_ldr) == LDHDRSZ);
|
||||||
|
// read the generic XCOFF header and analyze the substructures
|
||||||
|
// to find the burned in libpath. In any case of error perform the assert
|
||||||
|
if (nullptr == (f = fopen(buffer, "r")) ||
|
||||||
|
xcoffsz != fread(&the_xcoff, 1, xcoffsz, f) ||
|
||||||
|
the_xcoff.filehdr.f_magic != U64_TOCMAGIC ||
|
||||||
|
0 != fseek(f, (FILHSZ + the_xcoff.filehdr.f_opthdr + (the_xcoff.aouthdr.o_snloader -1)*SCNHSZ), SEEK_SET) ||
|
||||||
|
SCNHSZ != fread(&the_scn, 1, SCNHSZ, f) ||
|
||||||
|
0 != strcmp(the_scn.s_name, ".loader") ||
|
||||||
|
0 != fseek(f, the_scn.s_scnptr, SEEK_SET) ||
|
||||||
|
LDHDRSZ != fread(&the_ldr, 1, LDHDRSZ, f) ||
|
||||||
|
0 != fseek(f, the_scn.s_scnptr + the_ldr.l_impoff, SEEK_SET) ||
|
||||||
|
0 == fread(buffer, 1, bufsize, f)) {
|
||||||
|
buffer[0] = 0;
|
||||||
|
assert(false, "could not retrieve burned in library path from executables loader section");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f) {
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
libpath = buffer;
|
||||||
|
|
||||||
|
return libpath;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simulate the library search algorithm of dlopen() (in os::dll_load)
|
||||||
|
static bool search_file_in_LIBPATH(const char* path, struct stat64x* stat) {
|
||||||
|
if (path == nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
char* path2 = os::strdup(path);
|
||||||
|
// if exist, strip off trailing (shr_64.o) or similar
|
||||||
|
char* substr;
|
||||||
|
if (path2[strlen(path2) - 1] == ')' && (substr = strrchr(path2, '('))) {
|
||||||
|
*substr = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ret = false;
|
||||||
|
// If FilePath contains a slash character, FilePath is used directly,
|
||||||
|
// and no directories are searched.
|
||||||
|
// But if FilePath does not start with / or . we have to prepend it with ./
|
||||||
|
if (strchr(path2, '/')) {
|
||||||
|
stringStream combined;
|
||||||
|
if (*path2 == '/' || *path2 == '.') {
|
||||||
|
combined.print("%s", path2);
|
||||||
|
} else {
|
||||||
|
combined.print("./%s", path2);
|
||||||
|
}
|
||||||
|
ret = (0 == stat64x(combined.base(), stat));
|
||||||
|
os::free(path2);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* env = getenv("LIBPATH");
|
||||||
|
if (env == nullptr) {
|
||||||
|
// no LIBPATH, try with LD_LIBRARY_PATH
|
||||||
|
env = getenv("LD_LIBRARY_PATH");
|
||||||
|
}
|
||||||
|
|
||||||
|
stringStream Libpath;
|
||||||
|
if (env == nullptr) {
|
||||||
|
// no LIBPATH or LD_LIBRARY_PATH given -> try only with burned in libpath
|
||||||
|
Libpath.print("%s", rtv_linkedin_libpath());
|
||||||
|
} else if (*env == 0) {
|
||||||
|
// LIBPATH or LD_LIBRARY_PATH given but empty -> try first with burned
|
||||||
|
// in libpath and with current working directory second
|
||||||
|
Libpath.print("%s:.", rtv_linkedin_libpath());
|
||||||
|
} else {
|
||||||
|
// LIBPATH or LD_LIBRARY_PATH given with content -> try first with
|
||||||
|
// LIBPATH or LD_LIBRARY_PATH and second with burned in libpath.
|
||||||
|
// No check against current working directory
|
||||||
|
Libpath.print("%s:%s", env, rtv_linkedin_libpath());
|
||||||
|
}
|
||||||
|
|
||||||
|
char* libpath = os::strdup(Libpath.base());
|
||||||
|
|
||||||
|
char *saveptr, *token;
|
||||||
|
for (token = strtok_r(libpath, ":", &saveptr); token != nullptr; token = strtok_r(nullptr, ":", &saveptr)) {
|
||||||
|
stringStream combined;
|
||||||
|
combined.print("%s/%s", token, path2);
|
||||||
|
if ((ret = (0 == stat64x(combined.base(), stat))))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
os::free(libpath);
|
||||||
|
os::free(path2);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// specific AIX versions for ::dlopen() and ::dlclose(), which handles the struct g_handletable
|
||||||
|
// This way we mimic dl handle equality for a library
|
||||||
|
// opened a second time, as it is implemented on other platforms.
|
||||||
|
void* Aix_dlopen(const char* filename, int Flags, const char** error_report) {
|
||||||
|
assert(error_report != nullptr, "error_report is nullptr");
|
||||||
|
void* result;
|
||||||
|
struct stat64x libstat;
|
||||||
|
|
||||||
|
if (false == search_file_in_LIBPATH(filename, &libstat)) {
|
||||||
|
// file with filename does not exist
|
||||||
|
#ifdef ASSERT
|
||||||
|
result = ::dlopen(filename, Flags);
|
||||||
|
assert(result == nullptr, "dll_load: Could not stat() file %s, but dlopen() worked; Have to improve stat()", filename);
|
||||||
|
#endif
|
||||||
|
*error_report = "Could not load module .\nSystem error: No such file or directory";
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
unsigned i = 0;
|
||||||
|
TableLocker lock;
|
||||||
|
// check if library belonging to filename is already loaded.
|
||||||
|
// If yes use stored handle from previous ::dlopen() and increase refcount
|
||||||
|
for (i = 0; i < g_handletable_used; i++) {
|
||||||
|
if ((p_handletable + i)->handle &&
|
||||||
|
(p_handletable + i)->inode == libstat.st_ino &&
|
||||||
|
(p_handletable + i)->devid == libstat.st_dev) {
|
||||||
|
(p_handletable + i)->refcount++;
|
||||||
|
result = (p_handletable + i)->handle;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i == g_handletable_used) {
|
||||||
|
// library not yet loaded. Check if there is space left in array
|
||||||
|
// to store new ::dlopen() handle
|
||||||
|
if (g_handletable_used == max_handletable) {
|
||||||
|
// No place in array anymore; increase array.
|
||||||
|
unsigned new_max = MAX2(max_handletable * 2, init_num_handles);
|
||||||
|
struct handletableentry* new_tab = (struct handletableentry*)::realloc(p_handletable, new_max * sizeof(struct handletableentry));
|
||||||
|
assert(new_tab != nullptr, "no more memory for handletable");
|
||||||
|
if (new_tab == nullptr) {
|
||||||
|
*error_report = "dlopen: no more memory for handletable";
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
max_handletable = new_max;
|
||||||
|
p_handletable = new_tab;
|
||||||
|
}
|
||||||
|
// Library not yet loaded; load it, then store its handle in handle table
|
||||||
|
result = ::dlopen(filename, Flags);
|
||||||
|
if (result != nullptr) {
|
||||||
|
g_handletable_used++;
|
||||||
|
(p_handletable + i)->handle = result;
|
||||||
|
(p_handletable + i)->inode = libstat.st_ino;
|
||||||
|
(p_handletable + i)->devid = libstat.st_dev;
|
||||||
|
(p_handletable + i)->refcount = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// error analysis when dlopen fails
|
||||||
|
*error_report = ::dlerror();
|
||||||
|
if (*error_report == nullptr) {
|
||||||
|
*error_report = "dlerror returned no error description";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool os::pd_dll_unload(void* libhandle, char* ebuf, int ebuflen) {
|
||||||
|
unsigned i = 0;
|
||||||
|
bool res = false;
|
||||||
|
|
||||||
|
if (ebuf && ebuflen > 0) {
|
||||||
|
ebuf[0] = '\0';
|
||||||
|
ebuf[ebuflen - 1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
TableLocker lock;
|
||||||
|
// try to find handle in array, which means library was loaded by os::dll_load() call
|
||||||
|
for (i = 0; i < g_handletable_used; i++) {
|
||||||
|
if ((p_handletable + i)->handle == libhandle) {
|
||||||
|
// handle found, decrease refcount
|
||||||
|
assert((p_handletable + i)->refcount > 0, "Sanity");
|
||||||
|
(p_handletable + i)->refcount--;
|
||||||
|
if ((p_handletable + i)->refcount > 0) {
|
||||||
|
// if refcount is still >0 then we have to keep library and just return true
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// refcount == 0, so we have to ::dlclose() the lib
|
||||||
|
// and delete the entry from the array.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we reach this point either the libhandle was found with refcount == 0, or the libhandle
|
||||||
|
// was not found in the array at all. In both cases we have to ::dlclose the lib and perform
|
||||||
|
// the error handling. In the first case we then also have to delete the entry from the array
|
||||||
|
// while in the second case we simply have to nag.
|
||||||
|
res = (0 == ::dlclose(libhandle));
|
||||||
|
if (!res) {
|
||||||
|
// error analysis when dlopen fails
|
||||||
|
const char* error_report = ::dlerror();
|
||||||
|
if (error_report == nullptr) {
|
||||||
|
error_report = "dlerror returned no error description";
|
||||||
|
}
|
||||||
|
if (ebuf != nullptr && ebuflen > 0) {
|
||||||
|
snprintf(ebuf, ebuflen - 1, "%s", error_report);
|
||||||
|
}
|
||||||
|
assert(false, "os::pd_dll_unload() ::dlclose() failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < g_handletable_used) {
|
||||||
|
if (res) {
|
||||||
|
// First case: libhandle was found (with refcount == 0) and ::dlclose successful,
|
||||||
|
// so delete entry from array
|
||||||
|
g_handletable_used--;
|
||||||
|
// If the entry was the last one of the array, the previous g_handletable_used--
|
||||||
|
// is sufficient to remove the entry from the array, otherwise we move the last
|
||||||
|
// entry of the array to the place of the entry we want to remove and overwrite it
|
||||||
|
if (i < g_handletable_used) {
|
||||||
|
*(p_handletable + i) = *(p_handletable + g_handletable_used);
|
||||||
|
(p_handletable + g_handletable_used)->handle = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Second case: libhandle was not found (library was not loaded by os::dll_load())
|
||||||
|
// therefore nag
|
||||||
|
assert(false, "os::pd_dll_unload() library was not loaded by os::dll_load()");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the dll cache
|
||||||
|
LoadedLibraries::reload();
|
||||||
|
|
||||||
|
return res;
|
||||||
|
} // end: os::pd_dll_unload()
|
||||||
|
|
||||||
|
@ -115,4 +115,6 @@ class AixMisc {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void* Aix_dlopen(const char* filename, int Flags, const char** error_report);
|
||||||
|
|
||||||
#endif // OS_AIX_PORTING_AIX_HPP
|
#endif // OS_AIX_PORTING_AIX_HPP
|
||||||
|
@ -2530,3 +2530,25 @@ void os::jfr_report_memory_info() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endif // INCLUDE_JFR
|
#endif // INCLUDE_JFR
|
||||||
|
|
||||||
|
bool os::pd_dll_unload(void* libhandle, char* ebuf, int ebuflen) {
|
||||||
|
|
||||||
|
if (ebuf && ebuflen > 0) {
|
||||||
|
ebuf[0] = '\0';
|
||||||
|
ebuf[ebuflen - 1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
bool res = (0 == ::dlclose(libhandle));
|
||||||
|
if (!res) {
|
||||||
|
// error analysis when dlopen fails
|
||||||
|
const char* error_report = ::dlerror();
|
||||||
|
if (error_report == nullptr) {
|
||||||
|
error_report = "dlerror returned no error description";
|
||||||
|
}
|
||||||
|
if (ebuf != nullptr && ebuflen > 0) {
|
||||||
|
snprintf(ebuf, ebuflen - 1, "%s", error_report);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
} // end: os::pd_dll_unload()
|
||||||
|
@ -5469,3 +5469,25 @@ bool os::trim_native_heap(os::size_change_t* rss_change) {
|
|||||||
return false; // musl
|
return false; // musl
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool os::pd_dll_unload(void* libhandle, char* ebuf, int ebuflen) {
|
||||||
|
|
||||||
|
if (ebuf && ebuflen > 0) {
|
||||||
|
ebuf[0] = '\0';
|
||||||
|
ebuf[ebuflen - 1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
bool res = (0 == ::dlclose(libhandle));
|
||||||
|
if (!res) {
|
||||||
|
// error analysis when dlopen fails
|
||||||
|
const char* error_report = ::dlerror();
|
||||||
|
if (error_report == nullptr) {
|
||||||
|
error_report = "dlerror returned no error description";
|
||||||
|
}
|
||||||
|
if (ebuf != nullptr && ebuflen > 0) {
|
||||||
|
snprintf(ebuf, ebuflen - 1, "%s", error_report);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
} // end: os::pd_dll_unload()
|
||||||
|
@ -56,6 +56,7 @@
|
|||||||
|
|
||||||
#ifdef AIX
|
#ifdef AIX
|
||||||
#include "loadlib_aix.hpp"
|
#include "loadlib_aix.hpp"
|
||||||
|
#include "os_aix.hpp"
|
||||||
#endif
|
#endif
|
||||||
#ifdef LINUX
|
#ifdef LINUX
|
||||||
#include "os_linux.hpp"
|
#include "os_linux.hpp"
|
||||||
@ -731,27 +732,22 @@ void os::dll_unload(void *lib) {
|
|||||||
if (l_path == nullptr) {
|
if (l_path == nullptr) {
|
||||||
l_path = "<not available>";
|
l_path = "<not available>";
|
||||||
}
|
}
|
||||||
int res = ::dlclose(lib);
|
|
||||||
|
|
||||||
if (res == 0) {
|
char ebuf[1024];
|
||||||
|
bool res = os::pd_dll_unload(lib, ebuf, sizeof(ebuf));
|
||||||
|
|
||||||
|
if (res) {
|
||||||
Events::log_dll_message(nullptr, "Unloaded shared library \"%s\" [" INTPTR_FORMAT "]",
|
Events::log_dll_message(nullptr, "Unloaded shared library \"%s\" [" INTPTR_FORMAT "]",
|
||||||
l_path, p2i(lib));
|
l_path, p2i(lib));
|
||||||
log_info(os)("Unloaded shared library \"%s\" [" INTPTR_FORMAT "]", l_path, p2i(lib));
|
log_info(os)("Unloaded shared library \"%s\" [" INTPTR_FORMAT "]", l_path, p2i(lib));
|
||||||
JFR_ONLY(unload_event.set_result(true);)
|
JFR_ONLY(unload_event.set_result(true);)
|
||||||
} else {
|
} else {
|
||||||
const char* error_report = ::dlerror();
|
|
||||||
if (error_report == nullptr) {
|
|
||||||
error_report = "dlerror returned no error description";
|
|
||||||
}
|
|
||||||
|
|
||||||
Events::log_dll_message(nullptr, "Attempt to unload shared library \"%s\" [" INTPTR_FORMAT "] failed, %s",
|
Events::log_dll_message(nullptr, "Attempt to unload shared library \"%s\" [" INTPTR_FORMAT "] failed, %s",
|
||||||
l_path, p2i(lib), error_report);
|
l_path, p2i(lib), ebuf);
|
||||||
log_info(os)("Attempt to unload shared library \"%s\" [" INTPTR_FORMAT "] failed, %s",
|
log_info(os)("Attempt to unload shared library \"%s\" [" INTPTR_FORMAT "] failed, %s",
|
||||||
l_path, p2i(lib), error_report);
|
l_path, p2i(lib), ebuf);
|
||||||
JFR_ONLY(unload_event.set_error_msg(error_report);)
|
JFR_ONLY(unload_event.set_error_msg(ebuf);)
|
||||||
}
|
}
|
||||||
// Update the dll cache
|
|
||||||
AIX_ONLY(LoadedLibraries::reload());
|
|
||||||
LINUX_ONLY(os::free(l_pathdup));
|
LINUX_ONLY(os::free(l_pathdup));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,10 +75,6 @@ JvmtiAgent::JvmtiAgent(const char* name, const char* options, bool is_absolute_p
|
|||||||
_options(copy_string(options)),
|
_options(copy_string(options)),
|
||||||
_os_lib(nullptr),
|
_os_lib(nullptr),
|
||||||
_os_lib_path(nullptr),
|
_os_lib_path(nullptr),
|
||||||
#ifdef AIX
|
|
||||||
_inode(0),
|
|
||||||
_device(0),
|
|
||||||
#endif
|
|
||||||
_jplis(nullptr),
|
_jplis(nullptr),
|
||||||
_loaded(false),
|
_loaded(false),
|
||||||
_absolute_path(is_absolute_path),
|
_absolute_path(is_absolute_path),
|
||||||
@ -123,24 +119,6 @@ const char* JvmtiAgent::os_lib_path() const {
|
|||||||
return _os_lib_path;
|
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 {
|
bool JvmtiAgent::is_loaded() const {
|
||||||
return _loaded;
|
return _loaded;
|
||||||
}
|
}
|
||||||
@ -295,20 +273,6 @@ 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);
|
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.
|
// 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) {
|
static void* load_agent_from_absolute_path(JvmtiAgent* agent, bool vm_exit_on_error) {
|
||||||
DEBUG_ONLY(assert_preload(agent);)
|
DEBUG_ONLY(assert_preload(agent);)
|
||||||
@ -318,7 +282,6 @@ static void* load_agent_from_absolute_path(JvmtiAgent* agent, bool vm_exit_on_er
|
|||||||
if (library == nullptr && vm_exit_on_error) {
|
if (library == nullptr && vm_exit_on_error) {
|
||||||
vm_exit(agent, " in absolute path, with error: ", nullptr);
|
vm_exit(agent, " in absolute path, with error: ", nullptr);
|
||||||
}
|
}
|
||||||
AIX_ONLY(if (library != nullptr) save_library_signature(agent, agent->name());)
|
|
||||||
return library;
|
return library;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,13 +294,11 @@ static void* load_agent_from_relative_path(JvmtiAgent* agent, bool vm_exit_on_er
|
|||||||
// Try to load the agent from the standard dll directory
|
// Try to load the agent from the standard dll directory
|
||||||
if (os::dll_locate_lib(&buffer[0], sizeof buffer, Arguments::get_dll_dir(), name)) {
|
if (os::dll_locate_lib(&buffer[0], sizeof buffer, Arguments::get_dll_dir(), name)) {
|
||||||
library = os::dll_load(&buffer[0], &ebuf[0], sizeof ebuf);
|
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)) {
|
if (library == nullptr && os::dll_build_name(&buffer[0], sizeof buffer, name)) {
|
||||||
// Try the library path directory.
|
// Try the library path directory.
|
||||||
library = os::dll_load(&buffer[0], &ebuf[0], sizeof ebuf);
|
library = os::dll_load(&buffer[0], &ebuf[0], sizeof ebuf);
|
||||||
if (library != nullptr) {
|
if (library != nullptr) {
|
||||||
AIX_ONLY(save_library_signature(agent, &buffer[0]);)
|
|
||||||
return library;
|
return library;
|
||||||
}
|
}
|
||||||
if (vm_exit_on_error) {
|
if (vm_exit_on_error) {
|
||||||
@ -555,11 +516,7 @@ static bool invoke_Agent_OnAttach(JvmtiAgent* agent, outputStream* st) {
|
|||||||
agent->set_os_lib_path(&buffer[0]);
|
agent->set_os_lib_path(&buffer[0]);
|
||||||
agent->set_os_lib(library);
|
agent->set_os_lib(library);
|
||||||
agent->set_loaded();
|
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);
|
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.
|
// Print warning if agent was not previously loaded and EnableDynamicAgentLoading not enabled on the command line.
|
||||||
|
@ -43,10 +43,6 @@ class JvmtiAgent : public CHeapObj<mtServiceability> {
|
|||||||
const char* _options;
|
const char* _options;
|
||||||
void* _os_lib;
|
void* _os_lib;
|
||||||
const char* _os_lib_path;
|
const char* _os_lib_path;
|
||||||
#ifdef AIX
|
|
||||||
ino64_t _inode;
|
|
||||||
dev64_t _device;
|
|
||||||
#endif
|
|
||||||
const void* _jplis;
|
const void* _jplis;
|
||||||
bool _loaded;
|
bool _loaded;
|
||||||
bool _absolute_path;
|
bool _absolute_path;
|
||||||
@ -84,12 +80,6 @@ class JvmtiAgent : public CHeapObj<mtServiceability> {
|
|||||||
void initialization_end();
|
void initialization_end();
|
||||||
const Ticks& initialization_time() const;
|
const Ticks& initialization_time() const;
|
||||||
const Tickspan& initialization_duration() 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);
|
bool load(outputStream* st = nullptr);
|
||||||
void unload();
|
void unload();
|
||||||
|
@ -243,19 +243,6 @@ bool JvmtiAgentList::is_dynamic_lib_loaded(void* os_lib) {
|
|||||||
}
|
}
|
||||||
return false;
|
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) {
|
static bool match(JvmtiEnv* env, const JvmtiAgent* agent, const void* os_module_address) {
|
||||||
assert(env != nullptr, "invariant");
|
assert(env != nullptr, "invariant");
|
||||||
|
@ -78,9 +78,6 @@ class JvmtiAgentList : AllStatic {
|
|||||||
|
|
||||||
static bool is_static_lib_loaded(const char* name);
|
static bool is_static_lib_loaded(const char* name);
|
||||||
static bool is_dynamic_lib_loaded(void* os_lib);
|
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);
|
static JvmtiAgent* lookup(JvmtiEnv* env, void* f_ptr);
|
||||||
|
|
||||||
|
@ -1063,6 +1063,7 @@ class os: AllStatic {
|
|||||||
char pathSep);
|
char pathSep);
|
||||||
static bool set_boot_path(char fileSep, char pathSep);
|
static bool set_boot_path(char fileSep, char pathSep);
|
||||||
|
|
||||||
|
static bool pd_dll_unload(void* libhandle, char* ebuf, int ebuflen);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Note that "PAUSE" is almost always used with synchronization
|
// Note that "PAUSE" is almost always used with synchronization
|
||||||
|
Loading…
x
Reference in New Issue
Block a user