This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
Re: [RFA] JVMTI Agent Loading
- From: Kyle Galloway <kgallowa at redhat dot com>
- To: tromey at redhat dot com
- Cc: GCJ-patches <java-patches at gcc dot gnu dot org>
- Date: Tue, 03 Apr 2007 09:29:28 -0400
- Subject: Re: [RFA] JVMTI Agent Loading
- References: <460AC972.5080101@redhat.com> <m3vegi4h2s.fsf@localhost.localdomain> <460D7838.6080306@redhat.com> <m3wt0y313m.fsf@localhost.localdomain>
Tom Tromey wrote:
"Kyle" == Kyle Galloway <kgallowa@redhat.com> writes:
Kyle> The reason for this is that if the library is a C library, it will
Kyle> have unmangled names, but if the library is a C++ library the names
Kyle> will be mangled.
Yeah, but the declaration of Agent_OnLoad and Agent_OnUnload is
wrapped in 'extern "C"'... so I'd assume this case can't happen.
I think your right, I could swear I've seen a mangled AgentOnLoad
before, but I can't reproduce it so I whacked the mangled check.
Kyle> Is it better to have sizeof("-agentlib:") - 1 to be more clear about
Kyle> what's happening or sizeof(agentlib) because it avoids the subtraction?
The first one I think. Don't worry about the subtraction, the
compiler will fold this to a constant.
I think I have all the changes made now, but I've attached a revised
patch here in case there are any other issues before I check this in.
- Kyle
Index: libjava/gij.cc
===================================================================
--- libjava/gij.cc (revision 123426)
+++ libjava/gij.cc (working copy)
@@ -121,11 +121,11 @@
continue;
else if (! strcmp (arg, "-jrockit"))
continue;
- // Ignore JVM Tool Interface options
+ // JVM Tool Interface options
else if (! strncmp (arg, "-agentlib:", sizeof ("-agentlib:") - 1))
- continue;
+ add_option (vm_args, arg, NULL);
else if (! strncmp (arg, "-agentpath:", sizeof ("-agentpath:") - 1))
- continue;
+ add_option (vm_args, arg, NULL);
else if (! strcmp (arg, "-classpath") || ! strcmp (arg, "-cp"))
{
if (i >= argc - 1)
Index: libjava/prims.cc
===================================================================
--- libjava/prims.cc (revision 123426)
+++ libjava/prims.cc (working copy)
@@ -108,6 +108,16 @@
static char defaultJdwpOptions[] = "";
static char *jdwpOptions = defaultJdwpOptions;
+// Typedefs for JVMTI agent functions
+typedef jint jvmti_agent_onload_func (JavaVM *vm, char *options,
+ void *reserved);
+typedef jint jvmti_agent_onunload_func (JavaVM *vm);
+
+// JVMTI agent functions
+static jvmti_agent_onload_func *jvmti_agentonload = NULL;
+static jvmti_agent_onunload_func *jvmti_agentonunload = NULL;
+static char *jvmti_agent_opts;
+
// Argument support.
int
_Jv_GetNbArgs (void)
@@ -1358,7 +1368,65 @@
return 0;
}
+// This function loads the agent functions for JVMTI from the library indicated
+// by name. It returns a negative value on failure, the value of which
+// indicates where ltdl failed, it also prints an error message.
static jint
+load_jvmti_agent (const char *name)
+{
+#ifdef USE_LTDL
+ if (lt_dlinit ())
+ {
+ fprintf (stderr,
+ "libgcj: Error in ltdl init loading agent library\nlibgcj: %s\n",
+ (char *) lt_dlerror ());
+ return -1;
+ }
+
+ lt_dlhandle lib = lt_dlopenext (name);
+ if (!lib)
+ {
+ fprintf (stderr,
+ "libgcj: Error opening agent library\nlibgcj: %s\n",
+ (char *) lt_dlerror ());
+ return -2;
+ }
+
+ if (lib)
+ {
+ jvmti_agentonload
+ = (jvmti_agent_onload_func *) lt_dlsym (lib, "Agent_OnLoad");
+
+ if (!jvmti_agentonload)
+ {
+ fprintf (stderr,
+ "libgcj: Error finding agent function in %s\nlibgcj: %s\n",
+ name, (char *) lt_dlerror ());
+ lt_dlclose (lib);
+ lib = NULL;
+ return -4;
+ }
+ else
+ {
+ jvmti_agentonunload
+ = (jvmti_agent_onunload_func *) lt_dlsym (lib, "Agent_OnUnload");
+
+ return 0;
+ }
+ }
+ else
+ {
+ fprintf (stderr, "libgcj: %s not found in library path\n", name);
+ return -3;
+ }
+
+#endif /* USE_LTDL */
+
+// If LTDL cannot be used, return an error code indicating this
+return -99;
+}
+
+static jint
parse_init_args (JvVMInitArgs* vm_args)
{
// if _Jv_Compiler_Properties is non-NULL then it needs to be
@@ -1383,6 +1451,7 @@
for (int i = 0; i < vm_args->nOptions; ++i)
{
char* option_string = vm_args->options[i].optionString;
+
if (! strcmp (option_string, "vfprintf")
|| ! strcmp (option_string, "exit")
|| ! strcmp (option_string, "abort"))
@@ -1410,6 +1479,95 @@
continue;
}
+ else if (! strncmp (option_string, "-agentlib", sizeof ("-agentlib") - 1))
+ {
+ char *strPtr;
+
+ if (strlen(option_string) > (sizeof ("-agentlib:") - 1))
+ strPtr = &option_string[sizeof ("-agentlib:") - 1];
+ else
+ {
+ fprintf (stderr,
+ "libgcj: Malformed agentlib argument %s: expected lib name\n",
+ option_string);
+ return -1;
+ }
+
+ // This is optional
+ jvmti_agent_opts = strchr (strPtr, '=');
+
+ if (! strncmp (strPtr, "jdwp", 4))
+ {
+ // We want to run JDWP here so set the variables
+ remoteDebug = true;
+ jdwpOptions = ++jvmti_agent_opts;
+ }
+ else
+ {
+ jint nameLength;
+
+ if (jvmti_agent_opts == NULL)
+ nameLength = strlen (strPtr);
+ else
+ {
+ nameLength = jvmti_agent_opts - strPtr;
+ jvmti_agent_opts++;
+ }
+
+ char lib_name[nameLength + 3 + 1];
+ strcpy (lib_name, "lib");
+ strncat (lib_name, strPtr, nameLength);
+
+ jint result = load_jvmti_agent (lib_name);
+
+ if (result < 0)
+ {
+ return -1;
+ }
+ }
+
+ continue;
+ }
+ else if (! strncmp (option_string, "-agentpath:",
+ sizeof ("-agentpath:") - 1))
+ {
+ char *strPtr;
+
+ if (strlen(option_string) > 10)
+ strPtr = &option_string[10];
+ else
+ {
+ fprintf (stderr,
+ "libgcj: Malformed agentlib argument %s: expected lib path\n",
+ option_string);
+ return -1;
+ }
+
+ // This is optional
+ jvmti_agent_opts = strchr (strPtr, '=');
+
+ jint nameLength;
+
+ if (jvmti_agent_opts == NULL)
+ nameLength = strlen (strPtr);
+ else
+ {
+ nameLength = jvmti_agent_opts - strPtr;
+ jvmti_agent_opts++;
+ }
+
+ char lib_name[nameLength + 3 + 1];
+ strcpy (lib_name, "lib");
+ strncat (lib_name, strPtr, nameLength);
+ jint result = load_jvmti_agent (strPtr);
+
+ if (result < 0)
+ {
+ return -1;
+ }
+
+ continue;
+ }
else if (vm_args->ignoreUnrecognized)
{
if (option_string[0] == '_')
@@ -1570,6 +1728,10 @@
main_thread = new MainThread (JvNewStringUTF (name),
arg_vec, is_jar);
_Jv_AttachCurrentThread (main_thread);
+
+ //start JVMTI if an agent function has been found
+ if (jvmti_agentonload)
+ (*jvmti_agentonload) (_Jv_GetJavaVM (), jvmti_agent_opts, NULL);
// Start JDWP
if (remoteDebug)
@@ -1609,6 +1770,10 @@
JNIEnv *jni_env = _Jv_GetCurrentJNIEnv ();
_Jv_JVMTI_PostEvent (JVMTI_EVENT_VM_DEATH, thread, jni_env);
}
+
+ // Run JVMTI AgentOnUnload if it exists and an agent is loaded
+ if (jvmti_agentonunload)
+ (*jvmti_agentonunload) (_Jv_GetJavaVM ());
// If we got here then something went wrong, as MainThread is not
// supposed to terminate.