--- old/src/os/posix/vm/os_posix.cpp 2013-08-20 12:11:59.594346442 -0400 +++ new/src/os/posix/vm/os_posix.cpp 2013-08-20 12:11:58.614291454 -0400 @@ -1,5 +1,5 @@ /* -* Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. +* Copyright (c) 1999, 2013, 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 @@ -260,6 +260,55 @@ return ::fdopen(fd, mode); } +void* os::get_default_process_handle() { + return (void*)::dlopen(NULL, RTLD_LAZY); +} + +// Builds a platform dependent Agent_OnLoad_ function name +// which is used to find statically linked in agents. +// Parameters: +// sym_name: Symbol in library we are looking for +// lib_name: Name of library to look in, NULL for shared libs. +// is_absolute_path == true if lib_name is absolute path to agent +// such as "/a/b/libL.so" +// == false if only the base name of the library is passed in +// such as "L" +char* os::build_agent_function_name(const char *symName, const char *lib_name, + bool is_absolute_path) { + char *agent_entry_name; + size_t len; + size_t name_len; + size_t prefix_len = strlen(JNI_LIB_PREFIX); + size_t suffix_len = strlen(JNI_LIB_SUFFIX); + const char *start; + + if (lib_name != NULL) { + len = name_len = strlen(lib_name); + if (is_absolute_path) { + // Need to strip path, prefix and suffix + if ((start = strrchr(lib_name, *os::file_separator())) != NULL) { + lib_name = ++start; + } + if (len <= (prefix_len + suffix_len)) { + return NULL; + } + lib_name += prefix_len; + name_len = strlen(lib_name) - suffix_len; + } + } + len = (lib_name != NULL ? name_len : 0) + strlen(symName) + 2; + agent_entry_name = NEW_C_HEAP_ARRAY_RETURN_NULL(char, len, mtThread); + if (agent_entry_name == NULL) { + return NULL; + } + strcpy(agent_entry_name, symName); + if (lib_name != NULL) { + strcat(agent_entry_name, "_"); + strncat(agent_entry_name, lib_name, name_len); + } + return agent_entry_name; +} + os::WatcherThreadCrashProtection::WatcherThreadCrashProtection() { assert(Thread::current()->is_Watcher_thread(), "Must be WatcherThread"); } --- old/src/os/windows/vm/os_windows.cpp 2013-08-20 12:12:02.662518587 -0400 +++ new/src/os/windows/vm/os_windows.cpp 2013-08-20 12:12:01.666462702 -0400 @@ -5394,6 +5394,75 @@ return true; } +void* os::get_default_process_handle() { + return (void*)GetModuleHandle(NULL); +} + +// Builds a platform dependent Agent_OnLoad_ function name +// which is used to find statically linked in agents. +// Additionally for windows, takes into account __stdcall names. +// Parameters: +// sym_name: Symbol in library we are looking for +// lib_name: Name of library to look in, NULL for shared libs. +// is_absolute_path == true if lib_name is absolute path to agent +// such as "C:/a/b/L.dll" +// == false if only the base name of the library is passed in +// such as "L" +char* os::build_agent_function_name(const char *sym_name, const char *lib_name, + bool is_absolute_path) { + char *agent_entry_name; + size_t len; + size_t name_len; + size_t prefix_len = strlen(JNI_LIB_PREFIX); + size_t suffix_len = strlen(JNI_LIB_SUFFIX); + const char *start; + + if (lib_name != NULL) { + len = name_len = strlen(lib_name); + if (is_absolute_path) { + // Need to strip path, prefix and suffix + if ((start = strrchr(lib_name, *os::file_separator())) != NULL) { + lib_name = ++start; + } else { + // Need to check for C: + if ((start = strchr(lib_name, ':')) != NULL) { + lib_name = ++start; + } + } + if (len <= (prefix_len + suffix_len)) { + return NULL; + } + lib_name += prefix_len; + name_len = strlen(lib_name) - suffix_len; + } + } + len = (lib_name != NULL ? name_len : 0) + strlen(sym_name) + 2; + agent_entry_name = NEW_C_HEAP_ARRAY_RETURN_NULL(char, len, mtThread); + if (agent_entry_name == NULL) { + return NULL; + } + if (lib_name != NULL) { + const char *p = strrchr(sym_name, '@'); + if (p != NULL && p != sym_name) { + // sym_name == _Agent_OnLoad@XX + strncpy(agent_entry_name, sym_name, (p - sym_name)); + agent_entry_name[(p-sym_name)] = '\0'; + // agent_entry_name == _Agent_OnLoad + strcat(agent_entry_name, "_"); + strncat(agent_entry_name, lib_name, name_len); + strcat(agent_entry_name, p); + //agent_entry_name == _Agent_OnLoad_libName@XX + } else { + strcpy(agent_entry_name, sym_name); + strcat(agent_entry_name, "_"); + strncat(agent_entry_name, lib_name, name_len); + } + } else { + strcpy(agent_entry_name, sym_name); + } + return agent_entry_name; +} + #else // Kernel32 API typedef BOOL (WINAPI* SwitchToThread_Fn)(void); --- old/src/share/vm/prims/jvmti.xml 2013-08-20 12:12:05.786693875 -0400 +++ new/src/share/vm/prims/jvmti.xml 2013-08-20 12:12:04.798638438 -0400 @@ -358,7 +358,7 @@ + microversion="3"> <tm>JVM</tm> Tool Interface @@ -431,12 +431,46 @@ On the Solaris Operating Environment, an agent library is a shared object (.so file).

+ An agent may be started at VM startup by specifying the agent library name using a command line option. Some implementations may support a mechanism to start agents in the live phase. The details of how this is initiated are implementation specific. + + + + A native JVMTI Agent may be statically linked with the VM. + The manner in which the library and VM image are combined is + implementation-dependent. + An agent L whose image has been combined with the VM is defined as + statically linked if and only if the agent exports a function + called Agent_OnLoad_L. +

+ If a statically linked agent L exports a function called + Agent_OnLoad_L and a function called Agent_OnLoad, the Agent_OnLoad + function will be ignored. + If an agent L is statically linked, an Agent_OnLoad_L + function will be invoked with the same arguments and expected return + value as specified for the Agent_OnLoad function. + An agent L that is statically linked will prohibit an agent of + the same name from being loaded dynamically. +

+ The VM will invoke the Agent_OnUnload_L function of the agent, if such + a function is exported, at the same point during startup as it would + have called the dynamic entry point Agent_OnUnLoad. + If a statically linked agent L exports a function called + Agent_OnUnLoad_L and a function called Agent_OnUnLoad, the Agent_OnUnLoad + function will be ignored. +

+ If an agent L is statically linked, an Agent_OnAttach_L function + will be invoked with the same arguments and expected return value as + specified for the Agent_OnAttach function. + If a statically linked agent L exports a function called + Agent_OnAttach_L and a function called Agent_OnAttach, the Agent_OnAttach + function will be ignored. + The term "command-line option" is used below to @@ -455,7 +489,7 @@

The name following -agentlib: is the name of the library to load. Lookup of the library, both its full name and location, - proceeds in a platform-specific manner. + proceeds in a platform-specific manner. Typically, the <agent-lib-name> is expanded to an operating system specific file name. The <options> will be passed to the agent on start-up. @@ -463,7 +497,11 @@ -agentlib:foo=opt1,opt2 is specified, the VM will attempt to load the shared library foo.dll from the system PATH under Windows or libfoo.so from the - LD_LIBRARY_PATH under the Solaris operating environment. + LD_LIBRARY_PATH under the Solaris operating + environment. + If the agent library is statically linked into the executable + then no actual loading takes place. +

-agentpath:<path-to-agent>=<options>
@@ -473,11 +511,16 @@ The <options> will be passed to the agent on start-up. For example, if the option -agentpath:c:\myLibs\foo.dll=opt1,opt2 is specified, the VM will attempt to - load the shared library c:\myLibs\foo.dll. + load the shared library c:\myLibs\foo.dll. If the agent + library is statically linked into the executable + then no actual loading takes place. +

- The start-up routine Agent_OnLoad - in the library will be invoked. + For a dynamic shared library agent, the start-up routine Agent_OnLoad + in the library will be invoked. If the agent library is statically linked + into the executable then the system will attempt to invoke the Agent_OnLoad_<agent-lib-name> entry point where <agent-lib-name> is the basename of the + agent. In the above example -agentpath:c:\myLibs\foo.dll=opt1,opt2, the system will attempt to find and call the Agent_OnLoad_foo start-up routine.

Libraries loaded with -agentlib: or -agentpath: will be searched for JNI native method implementations to facilitate the @@ -502,11 +545,13 @@ If the agent is started in the OnLoad phase the function Agent_OnLoad - will be invoked. + or Agent_OnLoad_L + for statically linked agents will be invoked. If the agent is started in the live phase the function Agent_OnAttach - will be invoked. + or Agent_OnAttach_L + for statically linked agents will be invoked. Exactly one call to a start-up function is made per agent. @@ -516,6 +561,11 @@ JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved) + Or for a statically linked agent named 'L': + +JNIEXPORT jint JNICALL +Agent_OnLoad_L(JavaVM *vm, char *options, void *reserved) + The VM will start the agent by calling this function. It will be called early enough in VM initialization that:

    @@ -531,7 +581,7 @@
  • no objects have been created

- The VM will call the Agent_OnLoad function with + The VM will call the Agent_OnLoad or Agent_OnLoad_<agent-lib-name> function with <options> as the second argument - that is, using the command-line option examples, "opt1,opt2" will be passed to the char *options @@ -540,7 +590,7 @@ modified UTF-8 string. If =<options> is not specified, a zero length string is passed to options. - The lifespan of the options string is the Agent_OnLoad + The lifespan of the options string is the Agent_OnLoad or Agent_OnLoad_<agent-lib-name> call. If needed beyond this time the string or parts of the string must be copied. The period between when Agent_OnLoad is called and when it @@ -570,7 +620,7 @@ their functionality.

- The return value from Agent_OnLoad is used to indicate an error. + The return value from Agent_OnLoad or Agent_OnLoad_<agent-lib-name> is used to indicate an error. Any value other than zero indicates an error and causes termination of the VM. @@ -587,6 +637,11 @@ JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM* vm, char *options, void *reserved) +Or for a statically linked agent named 'L': + +JNIEXPORT jint JNICALL +Agent_OnAttach_L(JavaVM* vm, char *options, void *reserved) +

The VM will start the agent by calling this function. It will be called in the context of a thread @@ -596,13 +651,13 @@ string. If startup options were not provided, a zero length string is passed to options. The lifespan of the options string is the - Agent_OnAttach call. If needed beyond this time the string or parts of + Agent_OnAttach or Agent_OnAttach_<agent-lib-name> call. If needed beyond this time the string or parts of the string must be copied.

Note that some capabilities may not be available in the live phase.

- The Agent_OnAttach function initializes the agent and returns a value + The Agent_OnAttach or Agent_OnAttach_<agent-lib-name> function initializes the agent and returns a value to the VM to indicate if an error occurred. Any value other than zero indicates an error. An error does not cause the VM to terminate. Instead the VM ignores the error, or takes some implementation specific action -- for example it might print an error to standard error, @@ -615,8 +670,13 @@ JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm) + Or for a statically linked agent named 'L': + +JNIEXPORT void JNICALL +Agent_OnUnload_L(JavaVM *vm) + This function will be called by the VM when the library is about to be unloaded. - The library will be unloaded and this function will be called if some platform specific + The library will be unloaded (unless it is statically linked into the executable) and this function will be called if some platform specific mechanism causes the unload (an unload mechanism is not specified in this document) or the library is (in effect) unloaded by the termination of the VM whether through normal termination or VM failure, including start-up failure. @@ -625,8 +685,8 @@ VM Death event: for the VM Death event to be sent, the VM must have run at least to the point of initialization and a valid environment must exist which has set a callback for VMDeath - and enabled the event - None of these are required for Agent_OnUnload and this function + and enabled the event. + None of these are required for Agent_OnUnload or Agent_OnUnload_<agent-lib-name> and this function is also called if the library is unloaded for other reasons. In the case that a VM Death event is sent, it will be sent before this function is called (assuming this function is called due to VM termination). @@ -10701,10 +10761,10 @@ OnLoad phase: while in the - Agent_OnLoad function. + Agent_OnLoad or, for statically linked agents, the Agent_OnLoad_<agent-lib-name> function. - Primordial phase: between return from Agent_OnLoad and the + Primordial phase: between return from Agent_OnLoad or Agent_OnLoad_<agent-lib-name> and the VMStart event. @@ -14261,6 +14321,9 @@ Fixed the "HTTP" and "Missing Anchor" errors reported by the LinkCheck tool. + + Added support for statically linked agents. + --- old/src/share/vm/prims/jvmtiExport.cpp 2013-08-20 12:12:09.126881283 -0400 +++ new/src/share/vm/prims/jvmtiExport.cpp 2013-08-20 12:12:08.134825622 -0400 @@ -2191,6 +2191,8 @@ char buffer[JVM_MAXPATHLEN]; void* library = NULL; jint result = JNI_ERR; + const char *on_attach_symbols[] = AGENT_ONATTACH_SYMBOLS; + size_t num_symbol_entries = ARRAY_SIZE(on_attach_symbols); // get agent name and options const char* agent = op->arg(0); @@ -2200,43 +2202,48 @@ // The abs paramter should be "true" or "false" bool is_absolute_path = (absParam != NULL) && (strcmp(absParam,"true")==0); + // Initially marked as invalid. It will be set to valid if we can find the agent + AgentLibrary *agent_lib = new AgentLibrary(agent, options, is_absolute_path, NULL); - // If the path is absolute we attempt to load the library. Otherwise we try to - // load it from the standard dll directory. - - if (is_absolute_path) { - library = os::dll_load(agent, ebuf, sizeof ebuf); - } else { - // Try to load the agent from the standard dll directory - if (os::dll_build_name(buffer, sizeof(buffer), Arguments::get_dll_dir(), - agent)) { - library = os::dll_load(buffer, ebuf, sizeof ebuf); - } - if (library == NULL) { - // not found - try local path - char ns[1] = {0}; - if (os::dll_build_name(buffer, sizeof(buffer), ns, agent)) { + // Check for statically linked in agent. If not found then if the path is + // absolute we attempt to load the library. Otherwise we try to load it + // from the standard dll directory. + + if (!os::find_builtin_agent(agent_lib, on_attach_symbols, num_symbol_entries)) { + if (is_absolute_path) { + library = os::dll_load(agent, ebuf, sizeof ebuf); + } else { + // Try to load the agent from the standard dll directory + if (os::dll_build_name(buffer, sizeof(buffer), Arguments::get_dll_dir(), + agent)) { library = os::dll_load(buffer, ebuf, sizeof ebuf); } + if (library == NULL) { + // not found - try local path + char ns[1] = {0}; + if (os::dll_build_name(buffer, sizeof(buffer), ns, agent)) { + library = os::dll_load(buffer, ebuf, sizeof ebuf); + } + } + } + if (library != NULL) { + agent_lib->set_os_lib(library); + agent_lib->set_valid(); } } - // If the library was loaded then we attempt to invoke the Agent_OnAttach // function - if (library != NULL) { - + if (agent_lib->valid()) { // Lookup the Agent_OnAttach function OnAttachEntry_t on_attach_entry = NULL; - const char *on_attach_symbols[] = AGENT_ONATTACH_SYMBOLS; - for (uint symbol_index = 0; symbol_index < ARRAY_SIZE(on_attach_symbols); symbol_index++) { - on_attach_entry = - CAST_TO_FN_PTR(OnAttachEntry_t, os::dll_lookup(library, on_attach_symbols[symbol_index])); - if (on_attach_entry != NULL) break; - } - + on_attach_entry = CAST_TO_FN_PTR(OnAttachEntry_t, + os::find_agent_function(agent_lib, false, on_attach_symbols, num_symbol_entries)); if (on_attach_entry == NULL) { // Agent_OnAttach missing - unload library - os::dll_unload(library); + if (!agent_lib->is_static_lib()) { + os::dll_unload(library); + } + delete agent_lib; } else { // Invoke the Agent_OnAttach function JavaThread* THREAD = JavaThread::current(); @@ -2256,7 +2263,9 @@ // If OnAttach returns JNI_OK then we add it to the list of // agent libraries so that we can call Agent_OnUnload later. if (result == JNI_OK) { - Arguments::add_loaded_agent(agent, (char*)options, is_absolute_path, library); + Arguments::add_loaded_agent(agent_lib); + } else { + delete agent_lib; } // Agent_OnAttach executed so completion status is JNI_OK --- old/src/share/vm/runtime/arguments.hpp 2013-08-20 12:12:12.219054776 -0400 +++ new/src/share/vm/runtime/arguments.hpp 2013-08-20 12:12:11.238999788 -0400 @@ -118,11 +118,21 @@ // For use by -agentlib, -agentpath and -Xrun class AgentLibrary : public CHeapObj { friend class AgentLibraryList; +public: + // Is this library valid or not. Don't rely on os_lib == NULL as statically + // linked lib could have handle of RTLD_DEFAULT which == 0 on some platforms + enum AgentState { + agent_invalid = 0, + agent_valid = 1 + }; + private: char* _name; char* _options; void* _os_lib; bool _is_absolute_path; + bool _is_static_lib; + AgentState _state; AgentLibrary* _next; public: @@ -133,6 +143,11 @@ void* os_lib() const { return _os_lib; } void set_os_lib(void* os_lib) { _os_lib = os_lib; } AgentLibrary* next() const { return _next; } + bool is_static_lib() const { return _is_static_lib; } + void set_static_lib(bool static_lib) { _is_static_lib = static_lib; } + bool valid() { return (_state == agent_valid); } + void set_valid() { _state = agent_valid; } + void set_invalid() { _state = agent_invalid; } // Constructor AgentLibrary(const char* name, const char* options, bool is_absolute_path, void* os_lib) { @@ -147,6 +162,8 @@ _is_absolute_path = is_absolute_path; _os_lib = os_lib; _next = NULL; + _state = agent_invalid; + _is_static_lib = false; } }; @@ -276,6 +293,8 @@ { _agentList.add(new AgentLibrary(name, options, absolute_path, NULL)); } // Late-binding agents not started via arguments + static void add_loaded_agent(AgentLibrary *agentLib) + { _agentList.add(agentLib); } static void add_loaded_agent(const char* name, char* options, bool absolute_path, void* os_lib) { _agentList.add(new AgentLibrary(name, options, absolute_path, os_lib)); } --- old/src/share/vm/runtime/os.cpp 2013-08-20 12:12:15.371231636 -0400 +++ new/src/share/vm/runtime/os.cpp 2013-08-20 12:12:14.295171263 -0400 @@ -443,6 +443,67 @@ return _native_java_library; } +/* + * Support for finding Agent_On(Un)Load/Attach<_lib_name> if it exists. + * If check_lib == true then we are looking for an + * Agent_OnLoad_lib_name or Agent_OnAttach_lib_name function to determine if + * this library is statically linked into the image. + * If check_lib == false then we will look for the appropriate symbol in the + * executable if agent_lib->is_static_lib() == true or in the shared library + * referenced by 'handle'. + */ +void* os::find_agent_function(AgentLibrary *agent_lib, bool check_lib, + const char *syms[], size_t syms_len) { + const char *lib_name; + void *handle = agent_lib->os_lib(); + void *entryName = NULL; + char *agent_function_name; + size_t i; + + // If checking then use the agent name otherwise test is_static_lib() to + // see how to process this lookup + lib_name = ((check_lib || agent_lib->is_static_lib()) ? agent_lib->name() : NULL); + for (i = 0; i < syms_len; i++) { + agent_function_name = build_agent_function_name(syms[i], lib_name, agent_lib->is_absolute_path()); + if (agent_function_name == NULL) { + break; + } + entryName = dll_lookup(handle, agent_function_name); + FREE_C_HEAP_ARRAY(char, agent_function_name, mtThread); + if (entryName != NULL) { + break; + } + } + return entryName; +} + +// See if the passed in agent is statically linked into the VM image. +bool os::find_builtin_agent(AgentLibrary *agent_lib, const char *syms[], + size_t syms_len) { + void *ret; + void *proc_handle; + void *save_handle; + + if (agent_lib->name() == NULL) { + return false; + } + proc_handle = get_default_process_handle(); + // Check for Agent_OnLoad/Attach_libname function + save_handle = agent_lib->os_lib(); + // We want to look in this process' symbol table. + agent_lib->set_os_lib(proc_handle); + ret = find_agent_function(agent_lib, true, syms, syms_len); + agent_lib->set_os_lib(save_handle); + if (ret != NULL) { + // Found an entry point like Agent_OnLoad_libname so we have a static agent + agent_lib->set_os_lib(proc_handle); + agent_lib->set_valid(); + agent_lib->set_static_lib(true); + return true; + } + return false; +} + // --------------------- heap allocation utilities --------------------- char *os::strdup(const char *str, MEMFLAGS flags) { --- old/src/share/vm/runtime/os.hpp 2013-08-20 12:12:18.471405579 -0400 +++ new/src/share/vm/runtime/os.hpp 2013-08-20 12:12:17.479349917 -0400 @@ -46,6 +46,8 @@ # include #endif +class AgentLibrary; + // os defines the interface to operating system; this includes traditional // OS services (time, I/O) as well as other functionality with system- // dependent code. @@ -537,6 +539,17 @@ // Unload library static void dll_unload(void *lib); + // return the handle of this process + static void* get_default_process_handle(); + + // Check for static linked agent library + static bool find_builtin_agent(AgentLibrary *agent_lib, const char *syms[], + size_t syms_len); + + // Find agent entry point + static void *find_agent_function(AgentLibrary *agent_lib, bool check_lib, + const char *syms[], size_t syms_len); + // Print out system information; they are called by fatal error handler. // Output format may be different on different platforms. static void print_os_info(outputStream* st); @@ -806,6 +819,11 @@ // ResumeThread call) static void pause(); + // Builds a platform dependent Agent_OnLoad_ function name + // which is used to find statically linked in agents. + static char* build_agent_function_name(const char *sym, const char *cname, + bool is_absolute_path); + class SuspendedThreadTaskContext { public: SuspendedThreadTaskContext(Thread* thread, void *ucontext) : _thread(thread), _ucontext(ucontext) {} --- old/src/share/vm/runtime/thread.cpp 2013-08-20 12:12:21.571579522 -0400 +++ new/src/share/vm/runtime/thread.cpp 2013-08-20 12:12:20.575523637 -0400 @@ -3696,15 +3696,18 @@ // num_symbol_entries must be passed-in since only the caller knows the number of symbols in the array. static OnLoadEntry_t lookup_on_load(AgentLibrary* agent, const char *on_load_symbols[], size_t num_symbol_entries) { OnLoadEntry_t on_load_entry = NULL; - void *library = agent->os_lib(); // check if we have looked it up before + void *library = NULL; - if (library == NULL) { + if (!agent->valid()) { char buffer[JVM_MAXPATHLEN]; char ebuf[1024]; const char *name = agent->name(); const char *msg = "Could not find agent library "; - if (agent->is_absolute_path()) { + // First check to see if agent is statcally linked into executable + if (os::find_builtin_agent(agent, on_load_symbols, num_symbol_entries)) { + library = agent->os_lib(); + } else if (agent->is_absolute_path()) { library = os::dll_load(name, ebuf, sizeof ebuf); if (library == NULL) { const char *sub_msg = " in absolute path, with error: "; @@ -3738,13 +3741,14 @@ } } agent->set_os_lib(library); + agent->set_valid(); } // Find the OnLoad function. - for (size_t symbol_index = 0; symbol_index < num_symbol_entries; symbol_index++) { - on_load_entry = CAST_TO_FN_PTR(OnLoadEntry_t, os::dll_lookup(library, on_load_symbols[symbol_index])); - if (on_load_entry != NULL) break; - } + on_load_entry = CAST_TO_FN_PTR(OnLoadEntry_t, os::find_agent_function(agent, + false, + on_load_symbols, + num_symbol_entries)); return on_load_entry; } @@ -3819,22 +3823,23 @@ void Threads::shutdown_vm_agents() { // Send any Agent_OnUnload notifications const char *on_unload_symbols[] = AGENT_ONUNLOAD_SYMBOLS; + size_t num_symbol_entries = ARRAY_SIZE(on_unload_symbols); extern struct JavaVM_ main_vm; for (AgentLibrary* agent = Arguments::agents(); agent != NULL; agent = agent->next()) { // Find the Agent_OnUnload function. - for (uint symbol_index = 0; symbol_index < ARRAY_SIZE(on_unload_symbols); symbol_index++) { - Agent_OnUnload_t unload_entry = CAST_TO_FN_PTR(Agent_OnUnload_t, - os::dll_lookup(agent->os_lib(), on_unload_symbols[symbol_index])); - - // Invoke the Agent_OnUnload function - if (unload_entry != NULL) { - JavaThread* thread = JavaThread::current(); - ThreadToNativeFromVM ttn(thread); - HandleMark hm(thread); - (*unload_entry)(&main_vm); - break; - } + Agent_OnUnload_t unload_entry = CAST_TO_FN_PTR(Agent_OnUnload_t, + os::find_agent_function(agent, + false, + on_unload_symbols, + num_symbol_entries)); + + // Invoke the Agent_OnUnload function + if (unload_entry != NULL) { + JavaThread* thread = JavaThread::current(); + ThreadToNativeFromVM ttn(thread); + HandleMark hm(thread); + (*unload_entry)(&main_vm); } } }