Search code examples
javabyte-buddyjavaagentsjdi

How to load a class from a Jar file at runtime with the Java Debug Interface


I am trying to inject a ByteBuddy agent at runtime, in a case where ByteBuddy was not present on the machine (and thus not in the classpath) when the JVM was launched. My first thought was to add the bytebuddy library jar files inside a directory present in the classpath, so that it gets loaded when I inject my agent, but I cannot find a way to retrieve the classpath of the running JVM. I was thus wondering if it is possible to use the Java Debug Interface to manually load the bytebuddy library jar files in the JVM just before injecting my agent.

I tried to adapt this code (using the JDI), which translate for the first two lines to :

ClassType jarFileClass = (ClassType) findClassRef("java.util.jar.JarFile");
Method jarFileInit = findOverloadRef("java.util.jar.JarFile", "<init>", "java.lang.String");
Method entries = findOverloadRef("java.util.jar.JarFile", "entries", "");
ArrayList<Value> argz = new ArrayList<Value>();
argz.add(vm.mirrorOf(path)); // path is the path to the bytebuddy library jar file, as a String
ObjectReference jarFile = jarFileClass.newInstance(ev.thread(), jarFileInit, argz, ObjectReference.INVOKE_SINGLE_THREADED);
ObjectReference x = jarFile.invokeMethod(ev.thread(), entries, new ArrayList<Value>(), ObjectReference.INVOKE_SINGLE_THREADED);

where findClassRef and findOverloadRef are methods of my own to respectively get a ReferenceType and a Method object. Sadly, I cannot get any further as the java.net.URL[] class is not loaded in the JVM, and thus I cannot get a ReferenceType for it.

How can I pursue my quest ?


Solution

  • Often, agents shade all of their dependencies into a single jar. This can still be problematic. Byte Buddy is a rather common dependency, it night already be on the class path but in a different version. To avoid this, many agents shade their dependency into a different namespace.