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