From 862aad4462d72513db0c1b71287ef9d523f85684 Mon Sep 17 00:00:00 2001 From: Shautvast Date: Sun, 23 Jun 2024 20:39:03 +0200 Subject: [PATCH] for readability better making I am --- .../github/shautvast/exceptional/Agent.java | 59 ++++++++++--------- .../exceptional/ExceptionLogger.java | 11 ++++ .../exceptional/ThrowableHandler.java | 11 ---- 3 files changed, 42 insertions(+), 39 deletions(-) create mode 100644 lib/src/main/java/com/github/shautvast/exceptional/ExceptionLogger.java delete mode 100644 lib/src/main/java/com/github/shautvast/exceptional/ThrowableHandler.java diff --git a/agent/src/main/java/com/github/shautvast/exceptional/Agent.java b/agent/src/main/java/com/github/shautvast/exceptional/Agent.java index c5b77eb..0bbb45e 100644 --- a/agent/src/main/java/com/github/shautvast/exceptional/Agent.java +++ b/agent/src/main/java/com/github/shautvast/exceptional/Agent.java @@ -1,9 +1,6 @@ package com.github.shautvast.exceptional; -import java.lang.classfile.ClassElement; -import java.lang.classfile.ClassFile; -import java.lang.classfile.ClassModel; -import java.lang.classfile.MethodModel; +import java.lang.classfile.*; import java.lang.classfile.instruction.ReturnInstruction; import java.lang.constant.ClassDesc; import java.lang.constant.MethodTypeDesc; @@ -21,6 +18,7 @@ public class Agent { private static final String MESSAGE = "--- Exceptional agent active"; public static void premain(String agentArgs, Instrumentation instrumentation) throws Exception { + // add transformer instrumentation.addTransformer(new ClassFileTransformer() { @Override public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) { @@ -33,46 +31,51 @@ public class Agent { } }, true); + // we only want to redefine Throwable byte[] bytecode = Files.readAllBytes( Path.of(Agent.class.getResource("/java/lang/Throwable.class").toURI())); - instrumentation.redefineClasses(new ClassDefinition(Throwable.class, bytecode)); } - private static byte[] instrumentThrowable(String className, byte[] classfileBuffer) { + private static byte[] instrumentThrowable(String className, byte[] bytecode) { + // we only want to instrument Throwable + // or rather,,, is this the right way? This way we also intercept new any Exception that is not thrown + // But,,, who does that?? (famous last words) if (className.equals("java/lang/Throwable")) { ClassFile classFile = ClassFile.of(); - ClassModel classModel = classFile.parse(classfileBuffer); - return instrumentByteCode(classFile, classModel); + ClassModel classModel = classFile.parse(bytecode); + return instrumentConstructors(classFile, classModel); } else { - return classfileBuffer; + return bytecode; } } - private static byte[] instrumentByteCode(ClassFile classFile, ClassModel classModel) { + private static byte[] instrumentConstructors(ClassFile classFile, ClassModel classModel) { return classFile.build(classModel.thisClass().asSymbol(), classBuilder -> { for (ClassElement ce : classModel) { - if (ce instanceof MethodModel mm) { - if (mm.methodName().toString().equals("")) { - classBuilder.withMethod(mm.methodName(), mm.methodType(), mm.flags().flagsMask(), - methodBuilder -> - methodBuilder.transformCode(mm.code().get(), ((builder, element) -> { - if (element instanceof ReturnInstruction) { - builder.aload(0); - builder.invokestatic( - ClassDesc.of("com.github.shautvast.exceptional.ThrowableHandler"), "handle", - MethodTypeDesc.ofDescriptor("(Ljava/lang/Throwable;)V")); - builder.return_(); - } else { - builder.with(element); - } - }) - )); - continue; - } + if (ce instanceof MethodModel mm && mm.methodName().toString().equals("")) { + instrumentMethodWithMyExceptionLogger(classBuilder, mm); + continue; } classBuilder.with(ce); } }); } + + private static void instrumentMethodWithMyExceptionLogger(ClassBuilder classBuilder, MethodModel mm) { + classBuilder.withMethod(mm.methodName(), mm.methodType(), mm.flags().flagsMask(), + methodBuilder -> + methodBuilder.transformCode(mm.code().get(), ((builder, element) -> { + if (element instanceof ReturnInstruction) { + builder.aload(0); // load `this` on the stack, ie the Throwable instance + builder.invokestatic( // call my code + ClassDesc.of("com.github.shautvast.exceptional.ExceptionLogger"), "log", + MethodTypeDesc.ofDescriptor("(Ljava/lang/Throwable;)V")); + builder.return_(); + } else { + builder.with(element); + } + }) + )); + } } \ No newline at end of file diff --git a/lib/src/main/java/com/github/shautvast/exceptional/ExceptionLogger.java b/lib/src/main/java/com/github/shautvast/exceptional/ExceptionLogger.java new file mode 100644 index 0000000..b8df9ae --- /dev/null +++ b/lib/src/main/java/com/github/shautvast/exceptional/ExceptionLogger.java @@ -0,0 +1,11 @@ +package com.github.shautvast.exceptional; + +import java.util.Arrays; + +@SuppressWarnings("unused") // this code is called from the instrumented code +public class ExceptionLogger { + public static void log(Throwable throwable) { + System.out.print("Logging exception:"); + Arrays.stream(throwable.getStackTrace()).forEach(System.out::println); + } +} diff --git a/lib/src/main/java/com/github/shautvast/exceptional/ThrowableHandler.java b/lib/src/main/java/com/github/shautvast/exceptional/ThrowableHandler.java deleted file mode 100644 index 6de9ac6..0000000 --- a/lib/src/main/java/com/github/shautvast/exceptional/ThrowableHandler.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.github.shautvast.exceptional; - -import java.util.Arrays; - -@SuppressWarnings("unused") -public class ThrowableHandler { - public static void handle(Throwable throwable) { - System.out.print("Handling exception:"); - Arrays.stream(throwable.getStackTrace()).forEach(System.out::println); - } -}