2017-02-22 19 views
0

У меня есть следующие программы Java с помощью которой я пытаюсь захватить состояние переменных внутри метода, когда исключение происходит с использованием JVMTI,Invalid Ошибка Slot При попытке доступа к значению исключения и темы объектов Использование JVMTI

public class SimpleThread{ 
    static MyThread t; 
    String thisThread = "this Thread"; 
    public static void main(String[] args) throws Exception { 
      Thread thr = new Thread(new Runnable() { 
        final Exception exec = new IllegalArgumentException("Titanic"); 
        public void run() { 
          // while(true) { 
          String firstString = "string"; 
          int firstInt = 1; 
          for (int i =0 ; i <=3; i++) { 
            try { 
              throw exec; 
            } catch(Exception e) { 
              e.printStackTrace(); 
            } 
          } 
          // } 
        } 
      }); 

      thr.start(); 
    } 
} 

JVMTI агент, который я использую в состоянии получить доступ к имени переменной, но когда он пытается получить значение с помощью

jobject object_value; 
error = jvmti.GetLocalObject(thread, depth, slot, &object_value); 

я получаю следующий вывод

Trying to fetch value of e 
JNIException (java/lang/AssertionError): 'Unable to get local value; JVMTI  ERROR: '35' (JVMTI_ERROR_INVALID_SLOT)' 

То же самое происходит, когда он пытается получить информацию для MyThread t; , где я ошибаюсь?

код агента выглядит следующим образом:

#include<jni.h> 
#include<jvmti.h> 
#include<string.h> 
#include<stdlib.h> 
#include<stdbool.h> 
typedef struct { 
jvmtiEnv *jvmti; 
jrawMonitorID lock; 
} GlobalAgentData; 

static GlobalAgentData *gdata; 

static bool check_jvmti_error(jvmtiEnv *jvmti,jvmtiError errnum,const char *str){ 
if(errnum != JVMTI_ERROR_NONE){ 
    char *errnum_str; 
    errnum_str = NULL; 
    if(errnum!=JVMTI_ERROR_ABSENT_INFORMATION){ 
    (void)(*jvmti)->GetErrorName(jvmti,errnum,&errnum_str); 
    printf("ERROR: JVMTI: %d(%s): %s\n", errnum, 
    (errnum_str==NULL?"Unknown":errnum_str), 
    (str==NULL?"":str)); 

} 
return false; 
} 
return true; 
} 

static void deallocate(jvmtiEnv *jvmti,void *ptr){ 
jvmtiError error; 
error = (*jvmti)->Deallocate(jvmti,ptr); 
check_jvmti_error(jvmti,error,"Cannot deallocate memory"); 
} 

static void allocate(jvmtiEnv *jvmti,jint len){ 
jvmtiError error; 
void *ptr; 
error = (*jvmti)->Allocate(jvmti,len,(unsigned char **)&ptr); 
check_jvmti_error(jvmti,error,"Cannot allocate memory"); 
} 


JNICALL jint objectCountingCallback(jlong class_tag,jlong size,jlong* tag_ptr,jint length,void* user_data){ 
    int* count = (int*)user_data; 
    *count+=1; 
    return JVMTI_VISIT_OBJECTS; 
} 

JNICALL jint stringPrimitiveValueCallback(jlong class_tag,jlong size,jlong* tag_ptr,const jchar* value,jint value_length,void* user_data){ 
printf("Inside String primitive call back\n"); 
printf("%s\n",(char*)value); 
return JVMTI_VISIT_OBJECTS; 
} 


JNICALL jint primitiveFieldCallBack(jvmtiHeapReferenceKind kind,const jvmtiHeapReferenceInfo* info,jlong object_class_tag,jlong* object_tag_ptr,jvalue value,jvmtiPrimitiveType value_type,void *user_data){ 
printf("Inside Primitive field callback\n"); 
switch(value_type){ 
    case 90 : { 
       printf("%d\n",value.z); 
       break; 
    } 
    case 66 : { 
       printf("%d\n",value.b); 
       break; 
    } 
    case 67 : { 
       printf("%c\n",value.c); 
       break; 
    } 
    case 83 : { 
       printf("%d\n",value.s); 
       break; 
    } 
    case 73 : { 
       printf("%d\n",value.i); 
       break; 
    } 
    case 74 : { 
       printf("%ld\n",value.j); 
       break; 
    } 
    case 70 : { 
       printf("%f\n",value.f); 
       break; 
    } 
    case 68 : { 
       printf("%f\n",value.d); 
       break; 
    } 
} 
return JVMTI_VISIT_OBJECTS; 
} 


JNIEXPORT jint JNICALL Java_Test_countInstances(JNIEnv *env,jclass thisClass,jclass klass){ 
    int count =0 ; 
    jvmtiError error; 
    jvmtiHeapCallbacks callbacks; 
jvmtiEnv *jvmti; 
    (void)memset(&callbacks,0,sizeof(callbacks)); 
    callbacks.heap_iteration_callback = &objectCountingCallback; 
    jvmti = gdata->jvmti; 
error = (*jvmti)->IterateThroughHeap(jvmti,0,klass,&callbacks,&count); 
// check_jvmti_error(*gdata->jvmti,error,"Unable to iterate through the heap"); 
    return count; 
} 

static void enter_critical_section(jvmtiEnv *jvmti){ 
jvmtiError error; 
error = (*jvmti)->RawMonitorEnter(jvmti,gdata->lock); 
check_jvmti_error(jvmti,error,"Cannot enter with raw monitor"); 
} 

static void exit_critical_section(jvmtiEnv *jvmti){ 
jvmtiError error; 
error = (*jvmti)->RawMonitorExit(jvmti,gdata->lock); 
check_jvmti_error(jvmti,error,"Cannot exit with raw monitor"); 
} 

static void JNICALL callbackVMInit(jvmtiEnv *jvmti,JNIEnv *env,jthread thread){ 
jvmtiError error; 
// enter_critical_section(jvmti);{ /* not needed since we are just setting event notifications */ 
printf("Initializing JVM\n"); 
error = (*jvmti)->SetEventNotificationMode(jvmti,JVMTI_ENABLE,JVMTI_EVENT_EXCEPTION,(jthread)NULL); 
// error = (*jvmti)->SetEventNotificationMode(jvmti,JVMTI_ENABLE,JVMTI_EVENT_METHOD_ENTRY,(jthread)NULL); 
check_jvmti_error(jvmti,error,"Cannot set Exception Event notification"); 
// } exit_critical_section(jvmti); 
} 



static void JNICALL callbackException(jvmtiEnv *jvmti, JNIEnv *env, 
    jthread thread, jmethodID method, jlocation location, jobject exception, 
    jmethodID catch_method, jlocation catch_location) { 
jvmtiFrameInfo frames[10]; 
jint count, entry_count_ptr; 
int i, j; 
jvmtiError error; 
char *sig, *gsig,*methodName,*className; 
jclass declaring_class_ptr; 
jvmtiLocalVariableEntry *table_ptr; 

error = (*jvmti)->GetStackTrace(jvmti, thread, 0, 10, frames, &count); 
if (check_jvmti_error(jvmti, error, "Cannot Get Frame") && count >= 1) { 
    for (i = 0; i < count; i++) { 
     error = (*jvmti)->GetMethodName(jvmti, frames[i].method, 
       &methodName, &sig, &gsig); 
     if (check_jvmti_error(jvmti, error, "Cannot Get method name")) { 

      error = (*jvmti)->GetMethodDeclaringClass(jvmti, 
        frames[i].method, &declaring_class_ptr); 
      check_jvmti_error(jvmti, error, 
        "Cannot Get method declaring class"); 

      error = (*jvmti)->GetClassSignature(jvmti, declaring_class_ptr, 
        &className, NULL); 
      check_jvmti_error(jvmti, error, "Cannot get class signature"); 

      error = (*jvmti)->GetLocalVariableTable(jvmti, frames[i].method, 
        &entry_count_ptr, &table_ptr); 
      check_jvmti_error(jvmti, error, 
        "Cannot Get Local Variable Table"); 

      if (strstr(className, "java") == NULL 
        && strstr(className, "javax") == NULL 
        && strstr(className, "sun") == NULL) { 
       printf(
        "Got Exception in Method: %s at Line: %ld with Signature:%s,%s within Class:%s\n", 
        methodName, frames[i].location, sig, gsig, className); 

       for (j = 0; j < entry_count_ptr; j++) { 
        printf("Field Signature:%s\n", table_ptr[j].signature); 
        switch (*(table_ptr[j].signature)) { 
        case 'B': { 
         jint value_ptr; 
         error = (*jvmti)->GetLocalInt(jvmti, thread, i, 
           table_ptr[j].slot, &value_ptr); 
         check_jvmti_error(jvmti, error, 
           "Cannot Get Local Variable Byte"); 

         printf("Value of Field %s is %d.\n", table_ptr[j].name, (jbyte)value_ptr); 
         break; 
        } 

        case 'C': { 
         jint value_ptr; 
         error = (*jvmti)->GetLocalInt(jvmti, thread, i, 
           table_ptr[j].slot, &value_ptr); 
         check_jvmti_error(jvmti, error, 
           "Cannot Get Local Variable Char"); 

         printf("Value of Field %s is %c.\n", table_ptr[j].name, (jchar)value_ptr); 
         break; 
        } 
        case 'D': { 
         jdouble value_ptr; 
         error = (*jvmti)->GetLocalDouble(jvmti, thread, i, 
           table_ptr[j].slot, &value_ptr); 
         check_jvmti_error(jvmti, error, 
           "Cannot Get Local Variable Double"); 

         printf("Value of Field %s is %f.\n", table_ptr[j].name, value_ptr); 
         break; 
        } 
        case 'F': { 
         jfloat value_ptr; 
         error = (*jvmti)->GetLocalFloat(jvmti, thread, i, 
           table_ptr[j].slot, &value_ptr); 
         check_jvmti_error(jvmti, error, 
           "Cannot Get Local Variable Float"); 

         printf("Value of Field %s is %f.\n", table_ptr[j].name, value_ptr); 
         break; 
        } 
        case 'I': { 
         jint value_ptr; 
         error = (*jvmti)->GetLocalInt(jvmti, thread, i, 
           table_ptr[j].slot, &value_ptr); 
         check_jvmti_error(jvmti, error, 
           "Cannot Get Local Variable Integer"); 

         printf("Value of Field %s is %d.\n", table_ptr[j].name, value_ptr); 
         break; 
        } 
        case 'J': { 
         jlong value_ptr; 
         error = (*jvmti)->GetLocalLong(jvmti, thread, i, 
           table_ptr[j].slot, &value_ptr); 
         check_jvmti_error(jvmti, error, 
           "Cannot Get Local Variable Long"); 

         printf("Value of Field %s is %ld.\n", table_ptr[j].name, value_ptr); 
         break; 
        } 
        case 'S':{ 
         jint value_ptr; 
         error = (*jvmti)->GetLocalInt(jvmti, thread, i, 
           table_ptr[j].slot, &value_ptr); 
         check_jvmti_error(jvmti, error, 
           "Cannot Get Local Variable Short"); 

         printf("Value of Field %s is %d.\n", table_ptr[j].name, (jshort)value_ptr); 
         break; 
        } 
        case 'Z':{ 
         jint value_ptr; 
         error = (*jvmti)->GetLocalInt(jvmti, thread, i, 
           table_ptr[j].slot, &value_ptr); 
         check_jvmti_error(jvmti, error, 
           "Cannot Get Local Variable Boolean"); 

         printf("Value of Field %s is %d.\n", table_ptr[j].name, (jboolean)value_ptr); 
         break; 
        } 
        case 'L':{ 
         int count=0; 
         jobject value_ptr; 
         jclass klaz; 
         jfieldID field; 
         jstring value; 
         const char *stringVal; 
         jvmtiHeapCallbacks callbacks; 
         // (void)memset(&callbacks,0,sizeof(callbacks)); 
         // callbacks.primitive_field_callback = &primitiveFieldCallBack; 
         // callbacks.string_primitive_value_callback = &stringPrimitiveValueCallback; 
         // if(strcmp(table_ptr[j].name,"this")==0){ 
         // printf("Iterating through primitive fields of this object\n"); 
         error = (*jvmti)->GetLocalObject(jvmti, thread, i,table_ptr[j].slot, &value_ptr); 
         check_jvmti_error(jvmti, error,"Cannot Get Local Variable Object"); 
         // error = (*jvmti)->IterateThroughHeap(jvmti,0,declaring_class_ptr,&callbacks,&count); 
         // error = (*jvmti)->FollowReferences(jvmti,0,declaring_class_ptr,value_ptr,&callbacks,&count); 
         // } 


        // char *klazName; 
        // error = (*jvmti)->GetLocalObject(jvmti, thread, i, 
        //   table_ptr[j].slot, &value_ptr); 
        // check_jvmti_error(jvmti, error, 
        //   "Cannot Get Local Variable Object"); 
        // if(!error){ 
        //  klaz = (*env)->GetObjectClass(env,value_ptr); 
        //  error = (*jvmti)->GetClassSignature(jvmti, klaz, 
        // &klazName, NULL); 
        //  if(strstr(klazName,"String")!=NULL){ 
        //   printf("...%s\n",klazName); 
        //   field = (*env)->GetFieldID(env,declaring_class_ptr,table_ptr[j].name,"S"); 
        //   value = (jstring)(*env)->GetObjectField(env,value_ptr,field); 
        //   stringVal = (*env)->GetStringUTFChars(env,value,0); 
        //   printf("Value of Field %s is .\n", stringVal); 
          } 
         } 


         printf("Value of Field %s is .\n", table_ptr[j].name); 
         break; 
        } 
        case '[':{ 
         printf("This is an array reference \n"); 
         printf("Value of Field %s is .\n", table_ptr[j].name); 
         break; 
        } 
        default: 
         printf("Can't get %s type.\n", 
           table_ptr[j].signature); 
        } 

       } 
      } 

     } 
    } 
} 

} 



JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm,char *options,void *reserved){ 
jvmtiEnv *jvmti; 
jvmtiCapabilities capabilities; 
jvmtiError error; 
jint result; 
jvmtiEventCallbacks callbacks; 

result = (*jvm)->GetEnv(jvm,(void **)&jvmti,JVMTI_VERSION_1); 
if(result!=JNI_OK){ 
    printf("Unable to access JVMTI! \n"); 
} 
    gdata = (GlobalAgentData*)malloc(sizeof(GlobalAgentData)); 
    gdata->jvmti=jvmti; 

(void)memset(&capabilities,0,sizeof(jvmtiCapabilities)); 
capabilities.can_tag_objects = 1; 
capabilities.can_signal_thread=1; 
capabilities.can_get_owned_monitor_info=1; 
capabilities.can_generate_method_entry_events=1; 
capabilities.can_generate_exception_events=1; 
capabilities.can_access_local_variables=1; 

error = (*(gdata->jvmti))->AddCapabilities(gdata->jvmti,&capabilities); 
check_jvmti_error(gdata->jvmti,error,"Unable to set Capabilities"); 

(void)memset(&callbacks,0,sizeof(callbacks)); 
callbacks.VMInit = &callbackVMInit; 
callbacks.Exception = &callbackException; 
//callbacks.MethodEntry = &callbackMethodEntry; 

error = (*(gdata->jvmti))->SetEventCallbacks(gdata->jvmti,&callbacks,(jint)sizeof(callbacks)); 
check_jvmti_error(gdata->jvmti,error,"Cannot set event callbacks"); 

error = (*(gdata->jvmti))->SetEventNotificationMode(gdata->jvmti,JVMTI_ENABLE,JVMTI_EVENT_VM_INIT,(jthread)NULL); 
check_jvmti_error(gdata->jvmti,error,"Cannot set event notification"); 

error = (*(gdata->jvmti))->CreateRawMonitor(gdata->jvmti,"agent data",&(gdata->lock)); 
check_jvmti_error(gdata->jvmti,error,"Cannot create raw monitor"); 

printf("A message from my custom super agent!!\n"); 
return JNI_OK; 
} 

ответ

0

JVMTI агент, который я использую в состоянии получить доступ к имени переменной, но когда он пытается получить значение, используя ....

Вы не ввели свой собственный код, поэтому я не знаю, почему вы столкнулись с этой проблемой. Я могу дать вам альтернативное решение. Регистрация MethodEixt Event и получить значение e по адресу Функция возврата события события FunctionExit.

обратного вызова функции псевдокод, как показано ниже:

void JNICALL tdMethodExit(...) 
{ 
    jvmtiError error; 
    //method 
    char * method_name; 
    char * method_signature; 
    jclass declaring_klass; 
    char * klass_signature; 
    jint local_count; 
    jvmtiLocalVariableEntry * Var_table; 
    //locals 
    char * local_name; 
    char * local_signature; 
    char * local_generic_signature; 
    jint local_slot; 
    jint local_depth; 
    jobject local_object; 

    error = (*jvmti_env).GetMethodDeclaringClass(method, &declaring_klass); 
    error = (*jvmti_env).GetClassSignature(declaring_klass, &klass_signature, NULL); 
    if (strstr(klass_signature, "Ldemo/SimpleThread$1") != NULL) {// 
     error = (*jvmti_env).GetMethodName(method, &method_name, &method_signature, NULL); 
     if (strstr(method_name, "run") == NULL) { 
      return; 
     } 
     error = (*jvmti_env).GetLocalVariableTable(method, &local_count, &Var_table); 
     //show locals, skip slot 0 
     for (int i = 1; i < local_count; i++) 
     { 
      local_depth = 0; 
      jvmtiLocalVariableEntry * temp = Var_table + i; 
      local_name = temp->name; 
      local_signature = temp->signature; 
      local_slot = temp->slot; 
      cout << local_name << endl; 
      error = (*jvmti_env).GetLocalObject(thread, local_depth, local_slot, &local_object); 

      error = (*jvmti_env).Deallocate((unsigned char *)local_name); 
      error = (*jvmti_env).Deallocate((unsigned char *)local_signature); 
     } 
    } 
} 

"Ldemo/SimpleThread $ 1" является анонимный внутренний класс, который реализует интерфейс Runnable . Грубый рабочий процесс определяет целевой класс, а затем получает значение e, которое в этом методе.

+0

Я приложил код агента, пожалуйста, посмотрите. – kumarD