This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFA] JVMTI Agent Loading


This patch allows the -agentlib and -agentpath command line options for gij. These are used when loading JVMTI agents, and, in Java1.5 (and most notably in eclipse), they are used to launch JDWP as follows:

gij -agentlib:jdwp=transport=dt_socket,address=localhost:6969,server=n,suspend=y HelloWorld

This patch changes the code in gij.cc to add these options to the vm_args, instead of ignoring them, and there is code in prims.cc which will find the agent library, using ltdl, and load and (optionally) unload it by calling the appropriate functions if they are found. It will also check to see if the agent is jdwp and in that case will setup the options and start JDWP in the same way as -Xdebug -Xrunjdwp. It will also report errors if the library is not found, the arguments are malformed, or the proper function is not found inside the agent library

ChangeLog
2007-03-28  Kyle Galloway  <kgallowa@redhat.com>
   * gij.cc (main): Accept -agentlib and -agentpath options.
   * prims.cc (parse_init_args): Deal with -agentlib and -agentpath.
   (load_jvmti_agent) New function.

Questions/comments/concerns?

Thanks,
Kyle
Index: libjava/gij.cc
===================================================================
--- libjava/gij.cc	(revision 123266)
+++ 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 123266)
+++ libjava/prims.cc	(working copy)
@@ -108,6 +108,15 @@
 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 +1367,84 @@
   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
+  lt_dlhandle lib;
+
+  if (lt_dlinit ())
+    {
+      fprintf (stderr, 
+              "libgcj: Error in ltdl init loading agent library\nlibgcj: %s\n",
+               (char *) lt_dlerror ());
+      return -1;
+    }
+  
+  if (!(lib = lt_dlopenext (name)))
+    {
+      fprintf (stderr, 
+               "libgcj: Error opening agent library\nlibgcj: %s\n",
+               (char *) lt_dlerror ());
+      return -2;
+    }
+  
+  if (lib)
+    {
+      // first try to load the unmangled symbol name
+      jvmti_agentonload 
+			  = (jvmti_agent_onload_func *) lt_dlsym (lib, "Agent_OnLoad");
+      
+      // if the unmangled name fails, try the mangled name
+      if (!jvmti_agentonload)
+			  {
+          jvmti_agentonload 
+					  = (jvmti_agent_onload_func *) lt_dlsym (lib,
+                                          "_Z12Agent_OnLoadP10_Jv_JavaVMPcPv");
+				}
+      
+      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
+        {
+          // We have found an Agent_OnLoad function, so search for the optional
+          // Agent_OnUnload
+          jvmti_agentonunload
+					  = (jvmti_agent_onunload_func *) lt_dlsym (lib, "Agent_OnUnload");
+          
+          if (!jvmti_agentonunload)
+					  {
+              jvmti_agentonunload 
+                = (jvmti_agent_onunload_func *) lt_dlsym (lib,
+                                             "_Z14Agent_OnUnloadP7JavaVM_");
+						}
+        	
+          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 +1469,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 +1497,95 @@
 
 	  continue;
 	}
+	  else if (! strncmp (option_string, "-agentlib", sizeof ("-agentlib") - 1))
+	{
+      char *strPtr;
+	                                              
+      if (strlen(option_string) > 10)
+        strPtr = &option_string[10];
+      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] == '_')
@@ -1571,13 +1747,17 @@
 				      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)
 	{
 	  using namespace gnu::classpath::jdwp;
 	  VMVirtualMachine::initialize ();
 	  Jdwp *jdwp = new Jdwp ();
-	  jdwp->setDaemon (true);
+	  jdwp->setDaemon (true);	  
 	  jdwp->configure (JvNewStringLatin1 (jdwpOptions));
 	  jdwp->start ();
 
@@ -1609,6 +1789,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.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]