2

I'm writing a native Java agent using JVMTI that goes over all the methods of all the loaded classes. Unfortunately many classes seem not yet prepared and therefore GetClassMethods returns JVMTI_ERROR_CLASS_NOT_PREPARED. I am registering a ClassPrepare event callback but that seem to be called only for very few classes. Simplified (minus all the error handling and deallocation) my code looks like this

JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM* jvm, char *options, void *reserved) {

     jvmtiEnv *jvmti;
     jint class_count;
     jclass* classes;
     jint method_count;
     jmethodID* methods;

     (*jvm)->GetEnv(jvm, (void**) &jvmti, JVMTI_VERSION_11);
     (*jvmti)->GetLoadedClasses(jvmti, &class_count, &classes);
     for (int i = 0; i < class_count; i++) {
       jclass klass = classes[i];
       // here a lot of time JVMTI_ERROR_CLASS_NOT_PREPARED is returned
       jvmtiError err = (*jvmti)->GetClassMethods(jvmti, klass, &method_count, &methods);
     }

The agent is attached dynamically to a running JVM using JCMD and the JVMTI.agent_load command. I did try to register a class prepare callback using:

jvmtiEventCallbacks callbacks;
(void)memset(&callbacks, 0, sizeof(callbacks));
callbacks.ClassPrepare = &callbackClassPrepare;
(*jvmti)->SetEventCallbacks(jvmti, &callbacks, (jint) sizeof(callbacks));
(*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_PREPARE, (jthread) NULL);

But this ended only being called for very few classes.

How can I get the JVM to prepare the loaded classes so that GetClassMethods returns JVMTI_ERROR_NONE?

So far I have only tested with JDK 17.0.1 with Shenandoah GC.

Philippe Marschall
  • 4,452
  • 1
  • 34
  • 52
  • So what is the question? I don't see any question marks here. – apangin Dec 05 '21 at 21:28
  • How can I get the JVM to prepare the loaded classes so that `GetClassMethods` returns `JVMTI_ERROR_NONE`? – Philippe Marschall Dec 06 '21 at 12:20
  • 2
    You don't need to do anything to "prepare" classes. This is done automatically when needed, specifically, at link time. It's absolutely normal when some classes are loaded but not yet linked. – apangin Dec 06 '21 at 19:59
  • So I simply won't be able to call `GetClassMethods` on loaded classes that are not yet linked. There isn't anything I should do about this, just register callbacks for `ClassPrepare` and `ClassLoad`? – Philippe Marschall Dec 07 '21 at 15:33
  • 1
    Yes, exactly... – apangin Dec 07 '21 at 16:46
  • Very well. If it's not too much to ask could your turn the comment into an answer so I can mark it and other people can find it more easily? – Philippe Marschall Dec 08 '21 at 17:32

1 Answers1

3

This is a normal situation when some classes are loaded but not linked. You don't need to do anything to prepare classes manually - JVM does this automatically when needed. JVM Specification guarantees the classes is completely prepared before it is initialized. As soon as it happens, JVM TI ClassPrepare event is fired.

So in order to get all available jmethodIDs you'll need:

  1. Iterate over all loaded classes, ignoring possible JVMTI_ERROR_CLASS_NOT_PREPARED.
  2. Set ClassPrepare event callback and call GetClassMethods in it.
apangin
  • 92,924
  • 10
  • 193
  • 247