简体   繁体   English

尝试使用jvmti访问Exception和Thread对象的值时出现无效的插槽错误

[英]Invalid Slot Error When trying to access value of Exception and Thread Objects Using jvmti

I have the following java Program using which i am trying to capture the state of the variables inside the method when an exception occurs using JVMTI, 我有以下java程序,当使用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();
    }
}

the jvmti agent which i am using is able to access the name of the variable, but when it tries to fetch the value using 我正在使用的jvmti代理能够访问变量的名称,但是当它尝试使用来获取值时

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

I get the following output 我得到以下输出

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

The same happens when it tries to fetch the info for MyThread t; 当它尝试获取MyThread t;的信息时, MyThread t;发生同样的情况MyThread t; where am i going wrong? 我要去哪里错了?

The agent code is as follows: 代理代码如下:

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

the jvmti agent which i am using is able to access the name of the variable, but when it tries to fetch the value using.... 我正在使用的jvmti代理能够访问变量的名称,但是当它尝试使用...来获取值时...

You havent post your native code, so I dont know why you encounter this trouble. 您尚未发布您的本机代码,所以我不知道您为什么遇到此麻烦。 I can give you an alternative solution. 我可以给你一个替代解决方案。 Register MethodEixt Event and get the value of e at MethodExit event callback function . 注册MethodEixt事件并在MethodExit事件回调函数中获取e的值。

the callback function pseudocode as below: 回调函数伪代码如下:

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" is the anonymous inner class which implements Runnable Interface . “ Ldemo / SimpleThread $ 1”是实现Runnable接口的匿名内部类。 The rough workflow is locate the target class the method then get the value of e which in this method. 粗略的工作流程是找到该方法的目标类,然后获取此方法中e的值。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在JVMTI代理中访问线程局部变量 - Access thread local variable in JVMTI Agent 运行jar时的SWT异常:线程“main”中的异常org.eclipse.swt.SWTException:无效的线程访问 - SWT Exception when running jar: Exception in thread “main” org.eclipse.swt.SWTException: Invalid thread access 使用多个活动和OpenWeatherMap API时出现JVMTI_ERROR_THREAD_NOT_ALIVE错误 - JVMTI_ERROR_THREAD_NOT_ALIVE error using multiple activites and OpenWeatherMap API 尝试使用ObjectDraw运行Java程序时线程“ main”错误 - Exception in thread “main” error when trying to run a java program with objectdraw 更改Java SWT标签时出现无效的线程访问错误 - Invalid Thread Access error when changing Java SWT Label 线程“main”中的异常当尝试运行TestNG类时,Eclipse中出现错误 - Exception in thread “main” Error in Eclipse when trying to run TestNG class E/StudioProfiler: JVMTI error: 15(JVMTI_ERROR_THREAD_NOT_ALIVE) 是什么意思? - What does E/StudioProfiler: JVMTI error: 15(JVMTI_ERROR_THREAD_NOT_ALIVE) mean? 更新文本字段时无效的线程访问异常 - Invalid thread access exception while updating textfield 线程“主”java.time.DateTimeException 中的异常:MonthOfYear 的值无效(有效值 1 - 12):当我使用 Google Map jar 时为 0 - Exception in thread "main" java.time.DateTimeException: Invalid value for MonthOfYear (valid values 1 - 12): 0 when i am using Google Map jar 为什么对象列表在尝试更新其值时会引发异常? - Why list of objects throws an exception when trying to update it's value?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM