提交 3f09a38a 编写于 作者: B bpittore

8014135: The JVMTI specification does not conform to recent changes in JNI specification

Summary: Added support for statically linked agents
Reviewed-by: sspitsyn, bobv, coleenp
上级 ac93da8d
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -260,6 +260,55 @@ FILE* os::open(int fd, const char* mode) { ...@@ -260,6 +260,55 @@ FILE* os::open(int fd, const char* mode) {
return ::fdopen(fd, mode); return ::fdopen(fd, mode);
} }
void* os::get_default_process_handle() {
return (void*)::dlopen(NULL, RTLD_LAZY);
}
// Builds a platform dependent Agent_OnLoad_<lib_name> 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 *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;
}
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;
}
strcpy(agent_entry_name, sym_name);
if (lib_name != NULL) {
strcat(agent_entry_name, "_");
strncat(agent_entry_name, lib_name, name_len);
}
return agent_entry_name;
}
os::WatcherThreadCrashProtection::WatcherThreadCrashProtection() { os::WatcherThreadCrashProtection::WatcherThreadCrashProtection() {
assert(Thread::current()->is_Watcher_thread(), "Must be WatcherThread"); assert(Thread::current()->is_Watcher_thread(), "Must be WatcherThread");
} }
......
...@@ -5394,6 +5394,75 @@ inline BOOL os::Advapi32Dll::AdvapiAvailable() { ...@@ -5394,6 +5394,75 @@ inline BOOL os::Advapi32Dll::AdvapiAvailable() {
return true; return true;
} }
void* os::get_default_process_handle() {
return (void*)GetModuleHandle(NULL);
}
// Builds a platform dependent Agent_OnLoad_<lib_name> 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_lib_name@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 #else
// Kernel32 API // Kernel32 API
typedef BOOL (WINAPI* SwitchToThread_Fn)(void); typedef BOOL (WINAPI* SwitchToThread_Fn)(void);
......
<?xml version="1.0" encoding="ISO-8859-1"?> <?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="jvmti.xsl"?> <?xml-stylesheet type="text/xsl" href="jvmti.xsl"?>
<!-- <!--
Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
This code is free software; you can redistribute it and/or modify it This code is free software; you can redistribute it and/or modify it
...@@ -358,7 +358,7 @@ ...@@ -358,7 +358,7 @@
<specification label="JVM(TM) Tool Interface" <specification label="JVM(TM) Tool Interface"
majorversion="1" majorversion="1"
minorversion="2" minorversion="2"
microversion="2"> microversion="3">
<title subtitle="Version"> <title subtitle="Version">
<tm>JVM</tm> Tool Interface <tm>JVM</tm> Tool Interface
</title> </title>
...@@ -431,6 +431,7 @@ ...@@ -431,6 +431,7 @@
On the <tm>Solaris</tm> Operating Environment, an agent library is a shared On the <tm>Solaris</tm> Operating Environment, an agent library is a shared
object (<code>.so</code> file). object (<code>.so</code> file).
<p/> <p/>
An agent may be started at VM startup by specifying the agent library An agent may be started at VM startup by specifying the agent library
name using a <internallink id="starting">command line option</internallink>. name using a <internallink id="starting">command line option</internallink>.
Some implementations may support a mechanism to <internallink id="onattach"> Some implementations may support a mechanism to <internallink id="onattach">
...@@ -438,6 +439,39 @@ ...@@ -438,6 +439,39 @@
The details of how this is initiated are implementation specific. The details of how this is initiated are implementation specific.
</intro> </intro>
<intro id="entry point" label="Statically Linked Agents (since version 1.2.3)">
A native JVMTI Agent may be <i>statically linked</i> 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
<i>statically linked</i> if and only if the agent exports a function
called Agent_OnLoad_L.
<p/>
If a <i>statically linked</i> 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 <i>statically linked</i>, 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 <i>statically linked</i> will prohibit an agent of
the same name from being loaded dynamically.
<p/>
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 <i>statically linked</i> agent L exports a function called
Agent_OnUnLoad_L and a function called Agent_OnUnLoad, the Agent_OnUnLoad
function will be ignored.
<p/>
If an agent L is <i>statically linked</i>, 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 <i>statically linked</i> agent L exports a function called
Agent_OnAttach_L and a function called Agent_OnAttach, the Agent_OnAttach
function will be ignored.
</intro>
<intro id="starting" label="Agent Command Line Options"> <intro id="starting" label="Agent Command Line Options">
The term "command-line option" is used below to The term "command-line option" is used below to
mean options supplied in the <code>JavaVMInitArgs</code> argument mean options supplied in the <code>JavaVMInitArgs</code> argument
...@@ -463,7 +497,11 @@ ...@@ -463,7 +497,11 @@
<code>-agentlib:foo=opt1,opt2</code> is specified, the VM will attempt to <code>-agentlib:foo=opt1,opt2</code> is specified, the VM will attempt to
load the shared library <code>foo.dll</code> from the system <code>PATH</code> load the shared library <code>foo.dll</code> from the system <code>PATH</code>
under <tm>Windows</tm> or <code>libfoo.so</code> from the under <tm>Windows</tm> or <code>libfoo.so</code> from the
<code>LD_LIBRARY_PATH</code> under the <tm>Solaris</tm> operating environment. <code>LD_LIBRARY_PATH</code> under the <tm>Solaris</tm> operating
environment.
If the agent library is statically linked into the executable
then no actual loading takes place.
<p/>
</dd> </dd>
<dt><code>-agentpath:</code><i>&lt;path-to-agent&gt;</i><code>=</code><i>&lt;options&gt;</i></dt> <dt><code>-agentpath:</code><i>&lt;path-to-agent&gt;</i><code>=</code><i>&lt;options&gt;</i></dt>
<dd> <dd>
...@@ -473,11 +511,20 @@ ...@@ -473,11 +511,20 @@
The <i>&lt;options&gt;</i> will be passed to the agent on start-up. The <i>&lt;options&gt;</i> will be passed to the agent on start-up.
For example, if the option For example, if the option
<code>-agentpath:c:\myLibs\foo.dll=opt1,opt2</code> is specified, the VM will attempt to <code>-agentpath:c:\myLibs\foo.dll=opt1,opt2</code> is specified, the VM will attempt to
load the shared library <code>c:\myLibs\foo.dll</code>. load the shared library <code>c:\myLibs\foo.dll</code>. If the agent
library is statically linked into the executable
then no actual loading takes place.
<p/>
</dd> </dd>
</dl> </dl>
The start-up routine <internallink id="onload"><code>Agent_OnLoad</code></internallink> For a dynamic shared library agent, the start-up routine
in the library will be invoked. <internallink id="onload"><code>Agent_OnLoad</code></internallink>
in the library will be invoked. If the agent library is statically linked
into the executable then the system will attempt to invoke the
<code>Agent_OnLoad_&lt;agent-lib-name&gt;</code> entry point where
&lt;agent-lib-name&gt; is the basename of the
agent. In the above example <code>-agentpath:c:\myLibs\foo.dll=opt1,opt2</code>,
the system will attempt to find and call the <code>Agent_OnLoad_foo</code> start-up routine.
<p/> <p/>
Libraries loaded with <code>-agentlib:</code> or <code>-agentpath:</code> Libraries loaded with <code>-agentlib:</code> or <code>-agentpath:</code>
will be searched for JNI native method implementations to facilitate the will be searched for JNI native method implementations to facilitate the
...@@ -502,11 +549,13 @@ ...@@ -502,11 +549,13 @@
If the agent is started in the <code>OnLoad</code> If the agent is started in the <code>OnLoad</code>
<functionlink id="GetPhase">phase</functionlink> the function <functionlink id="GetPhase">phase</functionlink> the function
<internallink id="onload"><code>Agent_OnLoad</code></internallink> <internallink id="onload"><code>Agent_OnLoad</code></internallink>
will be invoked. or <internallink id="onload"><code>Agent_OnLoad_L</code></internallink>
for statically linked agents will be invoked.
If the agent is started in the live If the agent is started in the live
<functionlink id="GetPhase">phase</functionlink> the function <functionlink id="GetPhase">phase</functionlink> the function
<internallink id="onattach"><code>Agent_OnAttach</code></internallink> <internallink id="onattach"><code>Agent_OnAttach</code></internallink>
will be invoked. or <internallink id="onattach"><code>Agent_OnAttach_L</code></internallink>
for statically linked agents will be invoked.
Exactly one call to a start-up function is made per agent. Exactly one call to a start-up function is made per agent.
</intro> </intro>
...@@ -516,6 +565,11 @@ ...@@ -516,6 +565,11 @@
<example> <example>
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Agent_OnLoad(JavaVM *vm, char *options, void *reserved)</example> Agent_OnLoad(JavaVM *vm, char *options, void *reserved)</example>
Or for a statically linked agent named 'L':
<example>
JNIEXPORT jint JNICALL
Agent_OnLoad_L(JavaVM *vm, char *options, void *reserved)</example>
The VM will start the agent by calling this function. The VM will start the agent by calling this function.
It will be called early enough in VM initialization that: It will be called early enough in VM initialization that:
<ul> <ul>
...@@ -531,7 +585,8 @@ Agent_OnLoad(JavaVM *vm, char *options, void *reserved)</example> ...@@ -531,7 +585,8 @@ Agent_OnLoad(JavaVM *vm, char *options, void *reserved)</example>
<li>no objects have been created</li> <li>no objects have been created</li>
</ul> </ul>
<p/> <p/>
The VM will call the <code>Agent_OnLoad</code> function with The VM will call the <code>Agent_OnLoad</code> or
<code>Agent_OnLoad_&lt;agent-lib-name&gt;</code> function with
<i>&lt;options&gt;</i> as the second argument - <i>&lt;options&gt;</i> as the second argument -
that is, using the command-line option examples, that is, using the command-line option examples,
<code>"opt1,opt2"</code> will be passed to the <code>char *options</code> <code>"opt1,opt2"</code> will be passed to the <code>char *options</code>
...@@ -540,7 +595,8 @@ Agent_OnLoad(JavaVM *vm, char *options, void *reserved)</example> ...@@ -540,7 +595,8 @@ Agent_OnLoad(JavaVM *vm, char *options, void *reserved)</example>
<internallink id="mUTF">modified UTF-8</internallink> string. <internallink id="mUTF">modified UTF-8</internallink> string.
If <i>=&lt;options&gt;</i> is not specified, If <i>=&lt;options&gt;</i> is not specified,
a zero length string is passed to <code>options</code>. a zero length string is passed to <code>options</code>.
The lifespan of the <code>options</code> string is the <code>Agent_OnLoad</code> The lifespan of the <code>options</code> string is the
<code>Agent_OnLoad</code> or <code>Agent_OnLoad_&lt;agent-lib-name&gt;</code>
call. If needed beyond this time the string or parts of the string must call. If needed beyond this time the string or parts of the string must
be copied. be copied.
The period between when <code>Agent_OnLoad</code> is called and when it The period between when <code>Agent_OnLoad</code> is called and when it
...@@ -570,7 +626,8 @@ Agent_OnLoad(JavaVM *vm, char *options, void *reserved)</example> ...@@ -570,7 +626,8 @@ Agent_OnLoad(JavaVM *vm, char *options, void *reserved)</example>
their functionality. their functionality.
</rationale> </rationale>
<p/> <p/>
The return value from <code>Agent_OnLoad</code> is used to indicate an error. The return value from <code>Agent_OnLoad</code> or
<code>Agent_OnLoad_&lt;agent-lib-name&gt;</code> is used to indicate an error.
Any value other than zero indicates an error and causes termination of the VM. Any value other than zero indicates an error and causes termination of the VM.
</intro> </intro>
...@@ -587,6 +644,11 @@ Agent_OnLoad(JavaVM *vm, char *options, void *reserved)</example> ...@@ -587,6 +644,11 @@ Agent_OnLoad(JavaVM *vm, char *options, void *reserved)</example>
<example> <example>
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Agent_OnAttach(JavaVM* vm, char *options, void *reserved)</example> Agent_OnAttach(JavaVM* vm, char *options, void *reserved)</example>
Or for a statically linked agent named 'L':
<example>
JNIEXPORT jint JNICALL
Agent_OnAttach_L(JavaVM* vm, char *options, void *reserved)</example>
<p/> <p/>
The VM will start the agent by calling this function. The VM will start the agent by calling this function.
It will be called in the context of a thread It will be called in the context of a thread
...@@ -596,13 +658,14 @@ Agent_OnAttach(JavaVM* vm, char *options, void *reserved)</example> ...@@ -596,13 +658,14 @@ Agent_OnAttach(JavaVM* vm, char *options, void *reserved)</example>
</internallink> string. </internallink> string.
If startup options were not provided, a zero length string is passed to If startup options were not provided, a zero length string is passed to
<code>options</code>. The lifespan of the <code>options</code> string is the <code>options</code>. The lifespan of the <code>options</code> string is the
<code>Agent_OnAttach</code> call. If needed beyond this time the string or parts of <code>Agent_OnAttach</code> or <code>Agent_OnAttach_&lt;agent-lib-name&gt;</code> call.
the string must be copied. If needed beyond this time the string or parts of the string must be copied.
<p/> <p/>
Note that some <internallink id="capability">capabilities</internallink> Note that some <internallink id="capability">capabilities</internallink>
may not be available in the live phase. may not be available in the live phase.
<p/> <p/>
The <code>Agent_OnAttach</code> function initializes the agent and returns a value The <code>Agent_OnAttach</code> or <code>Agent_OnAttach_&lt;agent-lib-name
&gt;</code> 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. 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 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, some implementation specific action -- for example it might print an error to standard error,
...@@ -615,8 +678,14 @@ Agent_OnAttach(JavaVM* vm, char *options, void *reserved)</example> ...@@ -615,8 +678,14 @@ Agent_OnAttach(JavaVM* vm, char *options, void *reserved)</example>
<example> <example>
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Agent_OnUnload(JavaVM *vm)</example> Agent_OnUnload(JavaVM *vm)</example>
Or for a statically linked agent named 'L':
<example>
JNIEXPORT void JNICALL
Agent_OnUnload_L(JavaVM *vm)</example>
This function will be called by the VM when the library is about to be unloaded. 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) 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 or the library is (in effect) unloaded by the termination of the VM whether through
normal termination or VM failure, including start-up failure. normal termination or VM failure, including start-up failure.
...@@ -625,8 +694,9 @@ Agent_OnUnload(JavaVM *vm)</example> ...@@ -625,8 +694,9 @@ Agent_OnUnload(JavaVM *vm)</example>
<eventlink id="VMDeath">VM Death event</eventlink>: for the VM Death event <eventlink id="VMDeath">VM Death event</eventlink>: for the VM Death event
to be sent, the VM must have run at least to the point of initialization and a valid to be sent, the VM must have run at least to the point of initialization and a valid
<jvmti/> environment must exist which has set a callback for VMDeath <jvmti/> environment must exist which has set a callback for VMDeath
and enabled the event and enabled the event.
None of these are required for <code>Agent_OnUnload</code> and this function None of these are required for <code>Agent_OnUnload</code> or
<code>Agent_OnUnload_&lt;agent-lib-name&gt;</code> and this function
is also called if the library is unloaded for other reasons. 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 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). function is called (assuming this function is called due to VM termination).
...@@ -10701,10 +10771,14 @@ myInit() { ...@@ -10701,10 +10771,14 @@ myInit() {
<constants id="jvmtiPhase" label="Phases of execution" kind="enum"> <constants id="jvmtiPhase" label="Phases of execution" kind="enum">
<constant id="JVMTI_PHASE_ONLOAD" num="1"> <constant id="JVMTI_PHASE_ONLOAD" num="1">
<code>OnLoad</code> phase: while in the <code>OnLoad</code> phase: while in the
<internallink id="onload"><code>Agent_OnLoad</code></internallink> function. <internallink id="onload"><code>Agent_OnLoad</code></internallink>
or, for statically linked agents, the <internallink id="onload">
<code>Agent_OnLoad_&lt;agent-lib-name&gt;
</code></internallink> function.
</constant> </constant>
<constant id="JVMTI_PHASE_PRIMORDIAL" num="2"> <constant id="JVMTI_PHASE_PRIMORDIAL" num="2">
Primordial phase: between return from <code>Agent_OnLoad</code> and the Primordial phase: between return from <code>Agent_OnLoad</code>
or <code>Agent_OnLoad_&lt;agent-lib-name&gt;</code> and the
<code>VMStart</code> event. <code>VMStart</code> event.
</constant> </constant>
<constant id="JVMTI_PHASE_START" num="6"> <constant id="JVMTI_PHASE_START" num="6">
...@@ -14261,6 +14335,9 @@ typedef void (JNICALL *jvmtiEventVMInit) ...@@ -14261,6 +14335,9 @@ typedef void (JNICALL *jvmtiEventVMInit)
<change date="11 October 2012" version="1.2.2"> <change date="11 October 2012" version="1.2.2">
Fixed the "HTTP" and "Missing Anchor" errors reported by the LinkCheck tool. Fixed the "HTTP" and "Missing Anchor" errors reported by the LinkCheck tool.
</change> </change>
<change date="19 June 2013" version="1.2.3">
Added support for statically linked agents.
</change>
</changehistory> </changehistory>
</specification> </specification>
......
...@@ -2191,6 +2191,8 @@ jint JvmtiExport::load_agent_library(AttachOperation* op, outputStream* st) { ...@@ -2191,6 +2191,8 @@ jint JvmtiExport::load_agent_library(AttachOperation* op, outputStream* st) {
char buffer[JVM_MAXPATHLEN]; char buffer[JVM_MAXPATHLEN];
void* library = NULL; void* library = NULL;
jint result = JNI_ERR; 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 // get agent name and options
const char* agent = op->arg(0); const char* agent = op->arg(0);
...@@ -2200,10 +2202,14 @@ jint JvmtiExport::load_agent_library(AttachOperation* op, outputStream* st) { ...@@ -2200,10 +2202,14 @@ jint JvmtiExport::load_agent_library(AttachOperation* op, outputStream* st) {
// The abs paramter should be "true" or "false" // The abs paramter should be "true" or "false"
bool is_absolute_path = (absParam != NULL) && (strcmp(absParam,"true")==0); 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 // Check for statically linked in agent. If not found then if the path is
// load it from the standard dll directory. // 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) { if (is_absolute_path) {
library = os::dll_load(agent, ebuf, sizeof ebuf); library = os::dll_load(agent, ebuf, sizeof ebuf);
} else { } else {
...@@ -2220,23 +2226,24 @@ jint JvmtiExport::load_agent_library(AttachOperation* op, outputStream* st) { ...@@ -2220,23 +2226,24 @@ jint JvmtiExport::load_agent_library(AttachOperation* op, outputStream* st) {
} }
} }
} }
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 // If the library was loaded then we attempt to invoke the Agent_OnAttach
// function // function
if (library != NULL) { if (agent_lib->valid()) {
// Lookup the Agent_OnAttach function // Lookup the Agent_OnAttach function
OnAttachEntry_t on_attach_entry = NULL; OnAttachEntry_t on_attach_entry = NULL;
const char *on_attach_symbols[] = AGENT_ONATTACH_SYMBOLS; on_attach_entry = CAST_TO_FN_PTR(OnAttachEntry_t,
for (uint symbol_index = 0; symbol_index < ARRAY_SIZE(on_attach_symbols); symbol_index++) { os::find_agent_function(agent_lib, false, on_attach_symbols, num_symbol_entries));
on_attach_entry =
CAST_TO_FN_PTR(OnAttachEntry_t, os::dll_lookup(library, on_attach_symbols[symbol_index]));
if (on_attach_entry != NULL) break;
}
if (on_attach_entry == NULL) { if (on_attach_entry == NULL) {
// Agent_OnAttach missing - unload library // Agent_OnAttach missing - unload library
if (!agent_lib->is_static_lib()) {
os::dll_unload(library); os::dll_unload(library);
}
delete agent_lib;
} else { } else {
// Invoke the Agent_OnAttach function // Invoke the Agent_OnAttach function
JavaThread* THREAD = JavaThread::current(); JavaThread* THREAD = JavaThread::current();
...@@ -2256,7 +2263,9 @@ jint JvmtiExport::load_agent_library(AttachOperation* op, outputStream* st) { ...@@ -2256,7 +2263,9 @@ jint JvmtiExport::load_agent_library(AttachOperation* op, outputStream* st) {
// If OnAttach returns JNI_OK then we add it to the list of // If OnAttach returns JNI_OK then we add it to the list of
// agent libraries so that we can call Agent_OnUnload later. // agent libraries so that we can call Agent_OnUnload later.
if (result == JNI_OK) { 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 // Agent_OnAttach executed so completion status is JNI_OK
......
...@@ -118,11 +118,21 @@ class SystemProperty: public CHeapObj<mtInternal> { ...@@ -118,11 +118,21 @@ class SystemProperty: public CHeapObj<mtInternal> {
// For use by -agentlib, -agentpath and -Xrun // For use by -agentlib, -agentpath and -Xrun
class AgentLibrary : public CHeapObj<mtInternal> { class AgentLibrary : public CHeapObj<mtInternal> {
friend class AgentLibraryList; 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: private:
char* _name; char* _name;
char* _options; char* _options;
void* _os_lib; void* _os_lib;
bool _is_absolute_path; bool _is_absolute_path;
bool _is_static_lib;
AgentState _state;
AgentLibrary* _next; AgentLibrary* _next;
public: public:
...@@ -133,6 +143,11 @@ class AgentLibrary : public CHeapObj<mtInternal> { ...@@ -133,6 +143,11 @@ class AgentLibrary : public CHeapObj<mtInternal> {
void* os_lib() const { return _os_lib; } void* os_lib() const { return _os_lib; }
void set_os_lib(void* os_lib) { _os_lib = os_lib; } void set_os_lib(void* os_lib) { _os_lib = os_lib; }
AgentLibrary* next() const { return _next; } 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 // Constructor
AgentLibrary(const char* name, const char* options, bool is_absolute_path, void* os_lib) { AgentLibrary(const char* name, const char* options, bool is_absolute_path, void* os_lib) {
...@@ -147,6 +162,8 @@ class AgentLibrary : public CHeapObj<mtInternal> { ...@@ -147,6 +162,8 @@ class AgentLibrary : public CHeapObj<mtInternal> {
_is_absolute_path = is_absolute_path; _is_absolute_path = is_absolute_path;
_os_lib = os_lib; _os_lib = os_lib;
_next = NULL; _next = NULL;
_state = agent_invalid;
_is_static_lib = false;
} }
}; };
...@@ -276,6 +293,8 @@ class Arguments : AllStatic { ...@@ -276,6 +293,8 @@ class Arguments : AllStatic {
{ _agentList.add(new AgentLibrary(name, options, absolute_path, NULL)); } { _agentList.add(new AgentLibrary(name, options, absolute_path, NULL)); }
// Late-binding agents not started via arguments // 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) 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)); } { _agentList.add(new AgentLibrary(name, options, absolute_path, os_lib)); }
......
...@@ -443,6 +443,67 @@ void* os::native_java_library() { ...@@ -443,6 +443,67 @@ void* os::native_java_library() {
return _native_java_library; 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_lib_name 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_lib_name 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 --------------------- // --------------------- heap allocation utilities ---------------------
char *os::strdup(const char *str, MEMFLAGS flags) { char *os::strdup(const char *str, MEMFLAGS flags) {
......
...@@ -46,6 +46,8 @@ ...@@ -46,6 +46,8 @@
# include <setjmp.h> # include <setjmp.h>
#endif #endif
class AgentLibrary;
// os defines the interface to operating system; this includes traditional // os defines the interface to operating system; this includes traditional
// OS services (time, I/O) as well as other functionality with system- // OS services (time, I/O) as well as other functionality with system-
// dependent code. // dependent code.
...@@ -537,6 +539,17 @@ class os: AllStatic { ...@@ -537,6 +539,17 @@ class os: AllStatic {
// Unload library // Unload library
static void dll_unload(void *lib); 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. // Print out system information; they are called by fatal error handler.
// Output format may be different on different platforms. // Output format may be different on different platforms.
static void print_os_info(outputStream* st); static void print_os_info(outputStream* st);
...@@ -806,6 +819,11 @@ class os: AllStatic { ...@@ -806,6 +819,11 @@ class os: AllStatic {
// ResumeThread call) // ResumeThread call)
static void pause(); static void pause();
// Builds a platform dependent Agent_OnLoad_<libname> 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 { class SuspendedThreadTaskContext {
public: public:
SuspendedThreadTaskContext(Thread* thread, void *ucontext) : _thread(thread), _ucontext(ucontext) {} SuspendedThreadTaskContext(Thread* thread, void *ucontext) : _thread(thread), _ucontext(ucontext) {}
......
...@@ -3696,15 +3696,18 @@ extern "C" { ...@@ -3696,15 +3696,18 @@ extern "C" {
// num_symbol_entries must be passed-in since only the caller knows the number of symbols in the array. // 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) { static OnLoadEntry_t lookup_on_load(AgentLibrary* agent, const char *on_load_symbols[], size_t num_symbol_entries) {
OnLoadEntry_t on_load_entry = NULL; 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 buffer[JVM_MAXPATHLEN];
char ebuf[1024]; char ebuf[1024];
const char *name = agent->name(); const char *name = agent->name();
const char *msg = "Could not find agent library "; 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); library = os::dll_load(name, ebuf, sizeof ebuf);
if (library == NULL) { if (library == NULL) {
const char *sub_msg = " in absolute path, with error: "; const char *sub_msg = " in absolute path, with error: ";
...@@ -3738,13 +3741,15 @@ static OnLoadEntry_t lookup_on_load(AgentLibrary* agent, const char *on_load_sym ...@@ -3738,13 +3741,15 @@ static OnLoadEntry_t lookup_on_load(AgentLibrary* agent, const char *on_load_sym
} }
} }
agent->set_os_lib(library); agent->set_os_lib(library);
agent->set_valid();
} }
// Find the OnLoad function. // Find the OnLoad function.
for (size_t symbol_index = 0; symbol_index < num_symbol_entries; symbol_index++) { on_load_entry =
on_load_entry = CAST_TO_FN_PTR(OnLoadEntry_t, os::dll_lookup(library, on_load_symbols[symbol_index])); CAST_TO_FN_PTR(OnLoadEntry_t, os::find_agent_function(agent,
if (on_load_entry != NULL) break; false,
} on_load_symbols,
num_symbol_entries));
return on_load_entry; return on_load_entry;
} }
...@@ -3819,13 +3824,16 @@ extern "C" { ...@@ -3819,13 +3824,16 @@ extern "C" {
void Threads::shutdown_vm_agents() { void Threads::shutdown_vm_agents() {
// Send any Agent_OnUnload notifications // Send any Agent_OnUnload notifications
const char *on_unload_symbols[] = AGENT_ONUNLOAD_SYMBOLS; const char *on_unload_symbols[] = AGENT_ONUNLOAD_SYMBOLS;
size_t num_symbol_entries = ARRAY_SIZE(on_unload_symbols);
extern struct JavaVM_ main_vm; extern struct JavaVM_ main_vm;
for (AgentLibrary* agent = Arguments::agents(); agent != NULL; agent = agent->next()) { for (AgentLibrary* agent = Arguments::agents(); agent != NULL; agent = agent->next()) {
// Find the Agent_OnUnload function. // 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, Agent_OnUnload_t unload_entry = CAST_TO_FN_PTR(Agent_OnUnload_t,
os::dll_lookup(agent->os_lib(), on_unload_symbols[symbol_index])); os::find_agent_function(agent,
false,
on_unload_symbols,
num_symbol_entries));
// Invoke the Agent_OnUnload function // Invoke the Agent_OnUnload function
if (unload_entry != NULL) { if (unload_entry != NULL) {
...@@ -3833,8 +3841,6 @@ void Threads::shutdown_vm_agents() { ...@@ -3833,8 +3841,6 @@ void Threads::shutdown_vm_agents() {
ThreadToNativeFromVM ttn(thread); ThreadToNativeFromVM ttn(thread);
HandleMark hm(thread); HandleMark hm(thread);
(*unload_entry)(&main_vm); (*unload_entry)(&main_vm);
break;
}
} }
} }
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册