Старые смещения байт-кода после инструментирования с использованием ASM в Java - PullRequest
0 голосов
/ 18 февраля 2020

Я хочу напечатать смещение байт-кода, где исключение произошло во время выполнения. У меня есть патч JVMTI, чтобы сделать это. Но когда я применяю код с помощью ASM, смещение напечатанного байтового кода для исключения отличается из-за инструментария. Есть ли способ получить старое смещение байт-кода инструкции после завершения инструментирования? Или есть какой-нибудь альтернативный способ сделать это?

Вот пример класса:

class Test {
  public static void main(String args[]) {
    System.out.println("Before exception!!!");
    System.out.println(5/0);
    System.out.println("After exception!!!");
  }
}

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

#include <jvmti.h>
#include <stdio.h>

static jclass Exception;
static jfieldID detailMessage;

void JNICALL VMInit(jvmtiEnv* jvmti, JNIEnv* env, jthread thread) {
    jclass localE = env->FindClass("java/lang/Exception");
    Exception = (jclass) env->NewGlobalRef(localE);

    jclass Throwable = env->FindClass("java/lang/Throwable");
    detailMessage = env->GetFieldID(Throwable, "detailMessage", "Ljava/lang/String;");
}

void JNICALL ExceptionCallback(jvmtiEnv* jvmti, JNIEnv* env, jthread thread,
                               jmethodID method, jlocation location, jobject exception,
                               jmethodID catch_method, jlocation catch_location) {
    if (env->IsInstanceOf(exception, Exception)) {
        char buf[32];
        sprintf(buf, "location=%ld", (long)location);
        env->SetObjectField(exception, detailMessage, env->NewStringUTF(buf));
    }
}

JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void* reserved) {
    jvmtiEnv* jvmti;
    vm->GetEnv((void**)&jvmti, JVMTI_VERSION_1_0);

    jvmtiCapabilities capabilities = {0};
    capabilities.can_generate_exception_events = 1;
    jvmti->AddCapabilities(&capabilities);

    jvmtiEventCallbacks callbacks = {0};
    callbacks.VMInit = VMInit;
    callbacks.Exception = ExceptionCallback;
    jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks));
    jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL);
    jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_EXCEPTION, NULL);

    return 0;
}

Чтобы скомпилировать patch используйте команду:

g++ -shared -fPIC -I/path/to/java/jdk1.7.0_80/include -I/path/to/java/jdk1.7.0_80/include/linux -o libJVMTIPatch.so JVMTIPatch.cpp

Для запуска используйте опцию -agentpath:

java -agentpath:/path/to/libJVMTIPatch.so Test

Вывод будет:

Before exception!!!
Exception in thread "main" java.lang.ArithmeticException: location=13
at Test.main(Test.java:6)

Где "местоположение = 13 "- это смещение байт-кода, где произошло исключение.

class Test {
  Test();
  Code:
   0: aload_0
   1: invokespecial #1                  // Method java/lang/Object."<init>":()V
   4: return

public static void main(java.lang.String[]);
Code:
   0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
   3: ldc           #3                  // String Before exception!!!
   5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
   8: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
  11: iconst_5
  12: iconst_0
  13: idiv
  14: invokevirtual #5                  // Method java/io/PrintStream.println:(I)V
  17: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
  20: ldc           #6                  // String After exception!!!
  22: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
  25: return
}

Но когда ASM для какой-то цели оснащается ASM, смещение байт-кода инструкции idiv изменяется и, следовательно, выходные данные отличаются, как и ожидалось:

public class Test {
Test();
Code:
   0: invokestatic  #39                 // Method rr/state/ShadowThread.getCurrentShadowThread:()Lrr/state/ShadowThread;
   3: astore_1
   4: aload_1
   5: astore_1
   6: ldc           #41                 // String Test.<init>()V 0
   8: aload_1
   9: invokestatic  #47                 // Method rr/tool/RREventGenerator.bbEnter:(Ljava/lang/String;Lrr/state/ShadowThread;)V
  12: aload_0
  13: invokespecial #1                  // Method java/lang/Object."<init>":()V
  16: aload_0
  17: ldc           #49                 // String ALOAD 0
  19: aload_1
  20: invokestatic  #53                 // Method rr/tool/RREventGenerator.objIdPrint:(Ljava/lang/Object;Ljava/lang/String;Lrr/state/ShadowThread;)V
  23: return

public static void main(java.lang.String[]);
Code:
   0: invokestatic  #39                 // Method rr/state/ShadowThread.getCurrentShadowThread:()Lrr/state/ShadowThread;
   3: astore_1
   4: aload_1
   5: astore_1
   6: ldc           #55                 // String Test.main([Ljava/lang/String;)V 0
   8: aload_1
   9: invokestatic  #47                 // Method rr/tool/RREventGenerator.bbEnter:(Ljava/lang/String;Lrr/state/ShadowThread;)V
  12: aload_0
  13: ldc           #49                 // String ALOAD 0
  15: aload_1
  16: invokestatic  #53                 // Method rr/tool/RREventGenerator.objIdPrint:(Ljava/lang/Object;Ljava/lang/String;Lrr/state/ShadowThread;)V
  19: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
  22: ldc           #56                 // int 0
  24: invokestatic  #61                 // Method rr/instrument/classes/ClassInitNotifier.__$rr_static_access:(I)V
  27: ldc           #3                  // String Before exception!!!
  29: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
  32: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
  35: ldc           #56                 // int 0
  37: invokestatic  #61                 // Method rr/instrument/classes/ClassInitNotifier.__$rr_static_access:(I)V
  40: iconst_5
  41: iconst_0
  42: idiv
  43: invokevirtual #5                  // Method java/io/PrintStream.println:(I)V
  46: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
  49: ldc           #56                 // int 0
  51: invokestatic  #61                 // Method rr/instrument/classes/ClassInitNotifier.__$rr_static_access:(I)V
  54: ldc           #6                  // String After exception!!!
  56: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
  59: return
}

Отсюда вывод:

Before exception!!!
Exception in thread "main" java.lang.ArithmeticException: location=42
at Test.main(Test.java:6)

Я хочу получить смещение до того, как контрольно-измерительные приборы были сделаны.

...