From 8f516d5612ed39775441ea670d2f7194093a7b47 Mon Sep 17 00:00:00 2001 From: Shautvast Date: Sun, 23 Jun 2024 17:47:35 +0200 Subject: [PATCH] working now this is --- agent/pom.xml | 49 ++++++++ .../github/shautvast/exceptional/Agent.java | 111 ++++++++++++++++++ lib/pom.xml | 37 ++++++ .../exceptional/ThrowableHandler.java | 11 ++ pom.xml | 40 ++----- .../github/shautvast/exceptional/Agent.java | 73 ------------ 6 files changed, 215 insertions(+), 106 deletions(-) create mode 100644 agent/pom.xml create mode 100644 agent/src/main/java/com/github/shautvast/exceptional/Agent.java create mode 100644 lib/pom.xml create mode 100644 lib/src/main/java/com/github/shautvast/exceptional/ThrowableHandler.java delete mode 100644 src/main/java/com/github/shautvast/exceptional/Agent.java diff --git a/agent/pom.xml b/agent/pom.xml new file mode 100644 index 0000000..deb8ba9 --- /dev/null +++ b/agent/pom.xml @@ -0,0 +1,49 @@ + + + 4.0.0 + + + org.github.shautvast.exceptional + exceptional-parent + 1.0-SNAPSHOT + + + exceptional-agent + 1.0-SNAPSHOT + + + 22 + 22 + UTF-8 + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 22 + 22 + --enable-preview + + + + maven-jar-plugin + 3.1.0 + + + + com.github.shautvast.exceptional.Agent + true + true + /Users/Shautvast/dev/exceptional/lib/target/exceptional-lib-1.0-SNAPSHOT.jar + + + + + + + + \ No newline at end of file diff --git a/agent/src/main/java/com/github/shautvast/exceptional/Agent.java b/agent/src/main/java/com/github/shautvast/exceptional/Agent.java new file mode 100644 index 0000000..a5fd43b --- /dev/null +++ b/agent/src/main/java/com/github/shautvast/exceptional/Agent.java @@ -0,0 +1,111 @@ +package com.github.shautvast.exceptional; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.classfile.*; +import java.lang.constant.ClassDesc; +import java.lang.constant.ConstantDescs; +import java.lang.constant.MethodTypeDesc; +import java.lang.instrument.ClassDefinition; +import java.lang.instrument.ClassFileTransformer; +import java.lang.instrument.IllegalClassFormatException; +import java.lang.instrument.Instrumentation; +import java.lang.reflect.Modifier; +import java.security.ProtectionDomain; + +@SuppressWarnings("ALL") +public class Agent { + + private static final String MESSAGE = "--- Exceptional agent active"; + + public static void premain(String agentArgs, Instrumentation instrumentation) throws Exception { + instrumentation.addTransformer(new ClassFileTransformer() { + @Override + public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) { + return instrumentTheThrowable(className, classfileBuffer); + } + + @Override + public byte[] transform(Module module, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { + return instrumentTheThrowable(className, classfileBuffer); + } + }, true); + + InputStream stream = Agent.class.getResourceAsStream("/java/lang/Throwable.class"); + byte[] bytecode = readFully(stream); + + instrumentation.redefineClasses(new ClassDefinition(Throwable.class, bytecode)); + } + + private static byte[] readFully(InputStream stream) throws IOException { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + int nRead; + byte[] data = new byte[1024]; + while ((nRead = stream.read(data, 0, data.length)) != -1) { + buffer.write(data, 0, nRead); + } + + buffer.flush(); + return buffer.toByteArray(); + } + + private static byte[] instrumentTheThrowable(String className, byte[] classfileBuffer) { + if (className.equals("java/lang/Throwable")) { + ClassFile classFile = ClassFile.of(); + ClassModel classModel = classFile.parse(classfileBuffer); + + return classFile.build(classModel.thisClass().asSymbol(), classBuilder -> { + for (ClassElement ce : classModel) { + if (ce instanceof MethodModel mm) { + String signature = mm.methodName() + mm.methodType().stringValue(); + if (signature.equals("()V")) { + classBuilder.withMethod(mm.methodName(), mm.methodType(), Modifier.PUBLIC, + methodBuilder -> methodBuilder.withCode( + cb -> { + // recreate existing code for this method, because... I don't know how to simply add the new code at the end🫣 + ClassDesc throwable = ClassDesc.of("java.lang.Throwable"); + cb.aload(0); + cb.invokespecial(ConstantDescs.CD_Object, "", MethodTypeDesc.ofDescriptor("()V")); + cb.aload(0); + cb.aload(0); + cb.putfield(throwable, "cause", ClassDesc.ofDescriptor("Ljava/lang/Throwable;")); + cb.aload(0); + cb.getstatic(throwable, "UNASSIGNED_STACK", ClassDesc.ofDescriptor("[Ljava/lang/StackTraceElement;")); + cb.putfield(throwable, "stackTrace", ClassDesc.ofDescriptor("[Ljava/lang/StackTraceElement;")); + cb.aload(0); + cb.invokevirtual(throwable, "fillInStackTrace", MethodTypeDesc.ofDescriptor("()Ljava/lang/Throwable;")); + cb.pop(); +// cb.getstatic(throwable, "jfrTracing", ConstantDescs.CD_Boolean); +// Label end = cb.newLabel(); +// cb.ifeq(end); +// cb.aload(0); +// cb.invokevirtual(ConstantDescs.CD_Object, "getClass", MethodTypeDesc.ofDescriptor("()Ljava/lang/Class;")); +// cb.aconst_null(); +// cb.invokestatic(ClassDesc.of("jdk.internal.event.ThrowableTracer"), "traceThrowable", MethodTypeDesc.ofDescriptor("(Ljava/lang/Class;Ljava/lang/String;)V")); +// cb.labelBinding(end); + + cb.aload(0); + cb.invokestatic( + ClassDesc.of("com.github.shautvast.exceptional.ThrowableHandler"), "handle", + MethodTypeDesc.ofDescriptor("(Ljava/lang/Throwable;)V")); + cb.return_(); + } + )); + continue; + } + } + classBuilder.with(ce); + } + }); + } else { + return classfileBuffer; + } + } +} + +//getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream; +//ldc #13 // class com/github/shautvast/exceptional/Foo +//invokevirtual #15 // Method java/lang/Class.getModule:()Ljava/lang/Module; +//invokevirtual #21 // Method java/lang/Module.getName:()Ljava/lang/String; +//invokevirtual #27 // Method java/io/PrintStream.println:(Ljava/lang/String;)V diff --git a/lib/pom.xml b/lib/pom.xml new file mode 100644 index 0000000..31b0304 --- /dev/null +++ b/lib/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + + + org.github.shautvast.exceptional + exceptional-parent + 1.0-SNAPSHOT + + + exceptional-lib + 1.0-SNAPSHOT + + + 22 + 22 + UTF-8 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 22 + 22 + --enable-preview + + + + + + + \ No newline at end of file diff --git a/lib/src/main/java/com/github/shautvast/exceptional/ThrowableHandler.java b/lib/src/main/java/com/github/shautvast/exceptional/ThrowableHandler.java new file mode 100644 index 0000000..6de9ac6 --- /dev/null +++ b/lib/src/main/java/com/github/shautvast/exceptional/ThrowableHandler.java @@ -0,0 +1,11 @@ +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); + } +} diff --git a/pom.xml b/pom.xml index aee9829..90d7b6b 100644 --- a/pom.xml +++ b/pom.xml @@ -4,40 +4,14 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - org.example - Exceptional + org.github.shautvast.exceptional + exceptional-parent 1.0-SNAPSHOT + pom - - 21 - 21 - UTF-8 - - - - - org.apache.maven.plugins - maven-compiler-plugin - - 22 - 22 - --enable-preview - - - - maven-jar-plugin - 3.1.0 - - - - com.github.shautvast.exceptional.Agent - true - true - - - - - - + + agent + lib + \ No newline at end of file diff --git a/src/main/java/com/github/shautvast/exceptional/Agent.java b/src/main/java/com/github/shautvast/exceptional/Agent.java deleted file mode 100644 index e2cd75a..0000000 --- a/src/main/java/com/github/shautvast/exceptional/Agent.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.github.shautvast.exceptional; - -import java.io.InputStream; -import java.lang.classfile.*; -import java.lang.constant.ClassDesc; -import java.lang.constant.MethodTypeDesc; -import java.lang.instrument.ClassDefinition; -import java.lang.instrument.ClassFileTransformer; -import java.lang.instrument.IllegalClassFormatException; -import java.lang.instrument.Instrumentation; -import java.security.ProtectionDomain; - -@SuppressWarnings("ALL") -public class Agent { - - private static final String MESSAGE = "--- Exceptional agent active"; - - public static void premain(String agentArgs, Instrumentation instrumentation) throws Exception { - instrumentation.addTransformer(new ClassFileTransformer() { - @Override - public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) { - return instrumentTheThrowable(className, classfileBuffer); - } - - @Override - public byte[] transform(Module module, ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { - return instrumentTheThrowable(className, classfileBuffer); - } - }, true); - - InputStream stream = Agent.class.getResourceAsStream("/java/lang/Throwable.class"); - byte[] b = new byte[stream.available()]; - stream.read(b); - - instrumentation.redefineClasses(new ClassDefinition(Throwable.class, b)); - } - - private static byte[] instrumentTheThrowable(String className, byte[] classfileBuffer) { - if (className.equals("java/lang/Throwable")) { - - ClassFile classFile = ClassFile.of(); - ClassModel classModel = classFile.parse(classfileBuffer); - - return classFile.build(classModel.thisClass().asSymbol(), classBuilder -> { - for (ClassElement ce : classModel) { - if (ce instanceof MethodModel mm) { - String signature = mm.methodName() + "." + mm.methodType().stringValue(); - if (signature.equals(".()V")) { - classBuilder.withMethod(mm.methodName(), mm.methodType(), 1, - methodBuilder -> methodBuilder.withCode( - codebuilder -> -// codebuilder.invokeInstruction(Opcode.LDC, ); - codebuilder.invokeInstruction(Opcode.INVOKESTATIC, - ClassDesc.of("com.github.shautvast.exceptional.Agent"), "foo", - MethodTypeDesc.ofDescriptor("()V"), - false) - )); - continue; - } - } - classBuilder.with(ce); - } - }); - } else { - return classfileBuffer; - } - } - - public static void foo() { - System.out.println("foo"); - } - -} \ No newline at end of file