2017-02-14 7 views
1

Я пытаюсь захватить значения переменных, используя JVMTI, когда генерируется событие исключения, я прошел через документацию jvmti и обнаружил, что нет функций, которые позволяют я извлекаю значения полей (переменных), как это можно достичь?Как получить значения методов локальных переменных и переменных класса с помощью jvmti

Ниже приведен код Агент:

#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; 
    (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; 
} 

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 callbackMethodEntry(jvmtiEnv *jvmti,JNIEnv *env,jthread thread,jmethodID method){ 
jvmtiError error; 
jvmtiLocalVariableEntry **table_ptr; 
jint count,entry_count_ptr; 
jobject value_ptr; 
int j; 
error = (*jvmti)->GetLocalVariableTable(jvmti,method,&entry_count_ptr,table_ptr); 
if(check_jvmti_error(jvmti,error,"Cannot Get Local Variable table\n")){ 
    printf("local variable table entry size : %d %s\n",entry_count_ptr,(*table_ptr)[0].name);   
} 
// for(j=0;j<*entry_count_ptr;j++){ 
//  error = (*jvmti)->GetLocalObject(jvmti,thread,0,(*table_ptr)[j].slot,&value_ptr); 
//  printf("Field Name:%s\n",(*table_ptr)[j].name); 
// } 
} 


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; 
jobject* value_ptr; 
char *name,*sig,*gsig; 
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){ 
    char *methodName,*className; 
    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"); 
      // 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++){ 
       callbackMethodEntry(jvmti,env,thread,frames[j].method); 
       error = (*jvmti)->GetLocalObject(jvmti,thread,i,table_ptr[j].slot,value_ptr);// change the value of the slot parameter 
       printf("Field Name:%s\n",table_ptr[j].name); 
      } 

     } 
    } 
} 

/* error = (*jvmti)->GetMethodName(jvmti,method,&name,&sig,&gsig); 
check_jvmti_error(jvmti,error,"Cannot Get Method name"); 
printf("Exception in Method: %s%s at line number: %ld\n",name,sig,location);*/ 
} 

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_tag_objects=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; 
} 

Ниже выход:

ERROR: JVMTI: 101(JVMTI_ERROR_ABSENT_INFORMATION): Cannot Get Local Variable table 

# 
# A fatal error has been detected by the Java Runtime Environment: 
# 
# SIGSEGV (0xb) at pc=0x00007f3faab0cefa, pid=14869, tid=0x00007f3fad251700 
# 
# JRE version: Java(TM) SE Runtime Environment (8.0_111-b14) (build 1.8.0_111-b14) 
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.111-b14 mixed mode linux-amd64 compressed oops) 
# Problematic frame: 
# C [liblearnAgent.so+0xefa] callbackException+0x277 
# 
# Core dump written. Default location: /home/kumard/Desktop/core or core.14869 
# 
# An error report file with more information is saved as: 
# /home/kumard/Desktop/hs_err_pid14869.log 
# 
# If you would like to submit a bug report, please visit: 
# http://bugreport.java.com/bugreport/crash.jsp 
# The crash happened outside the Java Virtual Machine in native code. 
# See problematic frame for where to report the bug. 
# 
[1] 14869 abort (core dumped) java -agentlib:learnAgent SimpleThread 
+1

В чем проблема с использованием 'GetLocalObject' в событиях обратного вызова' Exception' и 'ExceptionCatch' ??? –

+0

Я приложил свой агент, пожалуйста, обратитесь к нему, я получаю основные свалки, следовательно, не в состоянии выяснить точную причину – kumarD

+0

Извините. Я не могу видеть агента. –

ответ

2

Это не полный ответ, но это решить некоторые проблемы в агенте и распечатывает значения для базовых типов данных при удалении исключения. Мы разрешили проблемы в чате комментариев. Поэтому я просто размещаю код здесь. Любой, кто заинтересован узнать больше об этом, может видеть чат. Вы также можете рассказать о проблеме.

#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; 
     (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 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; 
    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) { 
     char *methodName, *className; 
     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"); 

       printf(
         "Got Exception in Method: %s at Line: %ld with Signature:%s,%s within Class:%s\n", 
         methodName, frames[i].location, sig, gsig, className); 

       if (strstr(className, "java") == NULL 
         && strstr(className, "javax") == NULL 
         && strstr(className, "sun") == NULL) { 
        for (j = 0; j < entry_count_ptr; j++) { 

         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':{ 
          jobject value_ptr; 
          error = (*jvmti)->GetLocalObject(jvmti, thread, i, 
            table_ptr[j].slot, &value_ptr); 
          check_jvmti_error(jvmti, error, 
            "Cannot Get Local Variable Object"); 

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


         printf("Field Signature:%s\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_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"); 

    error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, 
      JVMTI_EVENT_EXCEPTION, (jthread) NULL); 
    check_jvmti_error(jvmti, error, "Cannot set Exception Event notification"); 

    (void) memset(&callbacks, 0, sizeof(callbacks)); 
    callbacks.Exception = &callbackException; 

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

    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

позволяет работать над этим и находить полное решение. – kumarD

+0

Несомненно. Мне будет приятно. –

+0

@SaqibAhmed - Не забудьте «Deallocate'' table_ptr'. –

Смежные вопросы