加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

java – 通过JVMTI识别异常

发布时间:2020-12-15 02:11:03 所属栏目:Java 来源:网络整理
导读:我正在使用JVMTI为 Java应用程序编写一个检测工具.我已经看到JVMTI检测到抛出异常的时间以及根据 http://docs.oracle.com/javase/7/docs/platform/jvmti/jvmti.html#Exception捕获的时间. 本文档说明了Exception和ExceptionCatch事件 The exception field id
我正在使用JVMTI为 Java应用程序编写一个检测工具.我已经看到JVMTI检测到抛出异常的时间以及根据 http://docs.oracle.com/javase/7/docs/platform/jvmti/jvmti.html#Exception捕获的时间.
本文档说明了Exception和ExceptionCatch事件

The exception field identifies the thrown exception object.

虽然它没有说明如何在运行期间比较它们(即比较Exception中提供的异常对应于ExceptionCatch中捕获的expcetion).换句话说,为

# java -version
java version "1.7.0_85"
OpenJDK Runtime Environment (IcedTea 2.6.1) (7u85-2.6.1-5ubuntu0.14.04.1)
OpenJDK 64-Bit Server VM (build 24.85-b03,mixed mode)

直接比较jexception / jobject似乎并不总是如此.考虑监视Exception和ExceptionCatch事件的JVMTI代理(下面的源代码),还考虑抛出异常的后续Java天真示例(也包括源代码),最后您可以通过“make run”运行代理示例“使用给定的Makefile(包含在最后).

如果我使用OpenJDK 7运行该示例,它会给我以下结果:

# make run
...
cb_Exception (exception=0x2ae6b8087be8)
cb_ExceptionCatch (exception=0x2ae6b80859f8 vs last_exception=0x2ae6b8087be8)
AreSameObject? = 0
cb_Exception (exception=0x2ae6b80859f8)
cb_ExceptionCatch (exception=0x2ae6b807a388 vs last_exception=0x2ae6b80859f8)
AreSameObject? = 0
cb_Exception (exception=0x2ae6b807a388)
cb_ExceptionCatch (exception=0x2ae6b807a388 vs last_exception=0x2ae6b807a388)
AreSameObject? = 1
cb_Exception (exception=0x2ae6b807a388)
cb_ExceptionCatch (exception=0x2ae6b8078108 vs last_exception=0x2ae6b807a388)
AreSameObject? = 0
cb_Exception (exception=0x2ae6b8078108)
cb_ExceptionCatch (exception=0x2ae6b8078108 vs last_exception=0x2ae6b8078108)
AreSameObject? = 1
cb_Exception (exception=0x2ae6b8078108)
cb_ExceptionCatch (exception=0x2ae6b8078108 vs last_exception=0x2ae6b8078108)
AreSameObject? = 1
before doing work
cb_Exception (exception=0x2ae6b8078108)
cb_ExceptionCatch (exception=0x2ae6b8078108 vs last_exception=0x2ae6b8078108)
AreSameObject? = 1
after doing work

如果我使用IBM的Java 1.7.0运行该示例,情况有点类似.

# make run
...
cb_Exception (exception=0x7d78a0)
cb_ExceptionCatch (exception=0x7d7950 vs last_exception=0x7d78a0)
AreSameObject? = 1
cb_Exception (exception=0x7d7938)
cb_ExceptionCatch (exception=0x7d7950 vs last_exception=0x7d7938)
AreSameObject? = 0
cb_Exception (exception=0x7d7938)
cb_ExceptionCatch (exception=0x7d79a8 vs last_exception=0x7d7938)
AreSameObject? = 1
before doing work
cb_Exception (exception=0x7d7a60)
cb_ExceptionCatch (exception=0x7d7a98 vs last_exception=0x7d7a60)
AreSameObject? = 0
after doing work

在OpenJDK中,请注意每个Exception都有一个相应的ExceptionCatch,但主Java代码之外有六个异常,我怀疑这些异常来自Java VM本身.请注意,异常的值在每对中都不相同.在第5次回调调用之后,异常的值似乎变得不变.这种情况在IBM的Java中有些类似,但引发的异常较少.作为来自评论的Chen Harel的建议,我已经存储了引发的异常,并通过IsSameObject JNI的方法与捕获的异常进行了比较,但JNI声称异常并不相同.

那么,Exception和ExceptionCatch可以在应用程序生命周期中识别异常吗?如果是,那么通过JVMTI或JNI比较异常的适当方法是什么?

agent.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <jni.h>
#include <jvmti.h>

#define CHECK_JVMTI_ERROR(x,call) 
    { if (x != JVMTI_ERROR_NONE) { fprintf (stderr,"Error during %s in %s:%dn",#call,__FILE__,__LINE__); } }

/* Global static data */
static jvmtiEnv     *jvmti;
static jrawMonitorID ExtraeJ_AgentLock;

jobject last_exception;

static void JNICALL cb_Exception (jvmtiEnv *jvmti_env,JNIEnv* jni_env,jthread thread,jmethodID method,jlocation location,jobject exception,jmethodID catch_method,jlocation catch_location)
{
    printf ("cb_Exception (exception=%p)n",exception);

    last_exception = exception;
}

static void JNICALL cb_ExceptionCatch (jvmtiEnv *jvmti_env,jobject exception)
{
    printf ("cb_ExceptionCatch (exception=%p vs last_exception=%p)n"
      "AreSameObject? = %dn",exception,last_exception,(*jni_env)->IsSameObject(jni_env,last_exception));
}

JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm,char *options,void *reserved)
{
    jint                rc;
    jvmtiError          r;
    jvmtiCapabilities   capabilities;
    jvmtiEventCallbacks callbacks;

    /* Get JVMTI environment */
    rc = (*vm)->GetEnv(vm,(void **)&jvmti,JVMTI_VERSION);
    if (rc != JNI_OK)
    {
        fprintf (stderr,"Error!: Unable to create jvmtiEnv,rc=%dn",rc);
        return -1;
    }

    /* Get/Add JVMTI capabilities */
    memset(&capabilities,sizeof(capabilities));
    capabilities.can_generate_exception_events = 1;
    r = (*jvmti)->AddCapabilities(jvmti,&capabilities);
    CHECK_JVMTI_ERROR(r,AddCapabilities);

    /* Set callbacks and enable event notifications */
    memset(&callbacks,sizeof(callbacks));
    callbacks.Exception               = &cb_Exception;
    callbacks.ExceptionCatch          = &cb_ExceptionCatch;
    r = (*jvmti)->SetEventCallbacks(jvmti,&callbacks,sizeof(callbacks));
    CHECK_JVMTI_ERROR(r,SetEventCallbacks);

    /* Exception events */
    r = (*jvmti)->SetEventNotificationMode(jvmti,JVMTI_ENABLE,JVMTI_EVENT_EXCEPTION,NULL);
    CHECK_JVMTI_ERROR(r,SetEventNotificationMode);
    r = (*jvmti)->SetEventNotificationMode(jvmti,JVMTI_EVENT_EXCEPTION_CATCH,SetEventNotificationMode);

    return 0;
}

JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm)
{
}

example.java

public class example
{
    void except () throws Exception
    { throw new Exception ("new-exception"); }

    void do_work()
    {
        System.out.println ("before doing work");

        try
        { except(); }
        catch (Exception e)
        {}

        System.out.println ("after doing work");
    }

    public static void main (String [] args)
    {
        example e = new example();
        e.do_work ();
    }
}

Makefile文件

JAVA_JDK=/usr/lib/jvm/java-7-openjdk-amd64

all: libagent.so example.class

libagent.so: agent.c
    gcc -shared -fPIC -DPIC agent.c -o libagent.so -I$(JAVA_JDK)/include

example.class: example.java
    javac example.java

run: libagent.so example.class
    java -agentpath:$(PWD)/libagent.so example

11月9日更新

正如Chen Harel建议的那样,我创建了一个对异常的全局引用. agent.c的修改版本如下,执行的输出如下所示.

agent.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <jni.h>
#include <jvmti.h>

#define CHECK_JVMTI_ERROR(x,exception);

    last_exception = (*jni_env)->NewGlobalRef (jni_env,exception);
}

static void JNICALL cb_ExceptionCatch (jvmtiEnv *jvmti_env,last_exception));

    (*jni_env)->DeleteGlobalRef(jni_env,last_exception);
}

JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm,SetEventNotificationMode);

    return 0;
}

JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm)
{
}

** make run **的输出

# make run
...
cb_Exception (exception=0x2b13b0087c18)
cb_ExceptionCatch (exception=0x2b13b0085a08 vs last_exception=0x2b13e4001608)
AreSameObject? = 0
cb_Exception (exception=0x2b13b0085a08)
cb_ExceptionCatch (exception=0x2b13b007a388 vs last_exception=0x2b13e4001610)
AreSameObject? = 0
cb_Exception (exception=0x2b13b007a388)
cb_ExceptionCatch (exception=0x2b13b007a388 vs last_exception=0x2b13e4001618)
AreSameObject? = 1
cb_Exception (exception=0x2b13b007a388)
cb_ExceptionCatch (exception=0x2b13b0078108 vs last_exception=0x2b13b0085a00)
AreSameObject? = 0
cb_Exception (exception=0x2b13b0078108)
cb_ExceptionCatch (exception=0x2b13b0078108 vs last_exception=0x2b13b0085a08)
AreSameObject? = 1
cb_Exception (exception=0x2b13b0078108)
cb_ExceptionCatch (exception=0x2b13b0078108 vs last_exception=0x2b13b0085a10)
AreSameObject? = 1
before doing work
cb_Exception (exception=0x2b13b0078108)
cb_ExceptionCatch (exception=0x2b13b0078108 vs last_exception=0x2b13b0085a18)
AreSameObject? = 1
after doing work

解决方法

jobject是一个C指针,在它下面处理对堆的引用.因此,如果您考虑它,这更像是指针的指针.

测试两个jobject是否相同的方法是使用jni方法IsSameObject

如果要测试异常的类型,请使用GetObjectClass IsInstanceOf

编辑

请注意,为了在方法之间保持jobject(s)有效,您必须使用jni NewGlobalRef方法为它们创建引用.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读