gpt4 book ai didi

java - 通过 JVMTI 识别异常

转载 作者:搜寻专家 更新时间:2023-11-01 03:49:07 26 4
gpt4 key购买 nike

我正在使用 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 中捕获的异常)。换句话说,对于

# 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 naïve 示例(也包括源代码),最后您可以通过“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 中,请注意每个异常都有一个对应的 ExceptionCatch,但在主要 Java 代码之外还有六个异常,我怀疑它们来自 Java VM 本身。请注意,exception 的值在每一对中都不相同。在第 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:%d\n", #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,
JNIEnv* jni_env, jthread thread, jmethodID method, jlocation location,
jobject exception)
{
printf ("cb_ExceptionCatch (exception=%p vs last_exception=%p)\n"
"AreSameObject? = %d\n",
exception,
last_exception,
(*jni_env)->IsSameObject(jni_env, exception, 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=%d\n", rc);
return -1;
}

/* Get/Add JVMTI capabilities */
memset(&capabilities, 0, 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, 0, 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_ENABLE,
JVMTI_EVENT_EXCEPTION_CATCH, NULL);
CHECK_JVMTI_ERROR(r, 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 ();
}
}

生成文件

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,call) \
{ if (x != JVMTI_ERROR_NONE) { fprintf (stderr, "Error during %s in %s:%d\n", #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 = (*jni_env)->NewGlobalRef (jni_env, exception);
}

static void JNICALL cb_ExceptionCatch (jvmtiEnv *jvmti_env,
JNIEnv* jni_env, jthread thread, jmethodID method, jlocation location,
jobject exception)
{
printf ("cb_ExceptionCatch (exception=%p vs last_exception=%p)\n"
"AreSameObject? = %d\n",
exception,
last_exception,
(*jni_env)->IsSameObject(jni_env, exception, last_exception));

(*jni_env)->DeleteGlobalRef(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=%d\n", rc);
return -1;
}

/* Get/Add JVMTI capabilities */
memset(&capabilities, 0, 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, 0, 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_ENABLE,
JVMTI_EVENT_EXCEPTION_CATCH, NULL);
CHECK_JVMTI_ERROR(r, 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 方法为它们创建一个引用。

关于java - 通过 JVMTI 识别异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33481612/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com