From 7bd49bf0d01bf252db42bc24caf84291f6be73d6 Mon Sep 17 00:00:00 2001 From: seongtaekkim Date: Mon, 16 Oct 2023 16:35:21 +0900 Subject: [PATCH 1/2] Test: ADD VirtualMachineManager Example --- .../staek/jvm/VirtualMachineManagerTest.java | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 java/jvm/jvm/src/main/java/me/staek/jvm/VirtualMachineManagerTest.java diff --git a/java/jvm/jvm/src/main/java/me/staek/jvm/VirtualMachineManagerTest.java b/java/jvm/jvm/src/main/java/me/staek/jvm/VirtualMachineManagerTest.java new file mode 100644 index 00000000..dc4a4076 --- /dev/null +++ b/java/jvm/jvm/src/main/java/me/staek/jvm/VirtualMachineManagerTest.java @@ -0,0 +1,90 @@ +package me.staek.jvm; + +import com.sun.jdi.*; +import com.sun.jdi.connect.Connector; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.stream.Stream; + +/** + * https://stackoverflow.com/questions/62433660/is-it-possible-to-get-jdis-current-stackframe-in-java-at-the-debuggee-side + * https://alvinalexander.com/scala/fp-book/recursion-jvm-stacks-stack-frames/ + * + * jvm 관련 옵션같은걸 찾아보자 + */ +public class VirtualMachineManagerTest { + public static void main(String[] args) throws Exception { + Object o = null; + int test = 42; + String s = "hello"; + Map vars = variables(); + System.out.println(vars); + } + // get the variables in the caller’s frame + static Map variables() throws Exception { + Thread th = Thread.currentThread(); + String oldName = th.getName(), tmpName = UUID.randomUUID().toString(); + th.setName(tmpName); + long depth = StackWalker.getInstance( + StackWalker.Option.SHOW_HIDDEN_FRAMES).walk(Stream::count) - 1; + + ExecutorService es = Executors.newSingleThreadExecutor(); + try { + return es.>submit(() -> { + VirtualMachineManager m = Bootstrap.virtualMachineManager(); + for(var ac: m.attachingConnectors()) { + Map arg = ac.defaultArguments(); + Connector.Argument a = arg.get("pid"); + if(a == null) continue; + a.setValue(String.valueOf(ProcessHandle.current().pid())); + VirtualMachine vm = ac.attach(arg); + return getVariableValues(vm, tmpName, depth); + } + return Map.of(); + }).get(); + } finally { + th.setName(oldName); + es.shutdown(); + } + } + + private static Map getVariableValues( + VirtualMachine vm, String tmpName, long depth) + throws IncompatibleThreadStateException, AbsentInformationException { + + for(ThreadReference r: vm.allThreads()) { + if(!r.name().equals(tmpName)) continue; + r.suspend(); + try { + StackFrame frame = r.frame((int)(r.frameCount() - depth)); + return frame.getValues(frame.visibleVariables()) + .entrySet().stream().collect(HashMap::new, + (m,e) -> m.put(e.getKey().name(), t(e.getValue())), Map::putAll); + } finally { + r.resume(); + } + } + return Map.of(); + } + private static Object t(Value v) { + if(v == null) return null; + switch(v.type().signature()) { + case "Z": return ((PrimitiveValue)v).booleanValue(); + case "B": return ((PrimitiveValue)v).byteValue(); + case "S": return ((PrimitiveValue)v).shortValue(); + case "C": return ((PrimitiveValue)v).charValue(); + case "I": return ((PrimitiveValue)v).intValue(); + case "J": return ((PrimitiveValue)v).longValue(); + case "F": return ((PrimitiveValue)v).floatValue(); + case "D": return ((PrimitiveValue)v).doubleValue(); + case "Ljava/lang/String;": return ((StringReference)v).value(); + } + if(v instanceof ArrayReference) + return ((ArrayReference)v).getValues().stream().map(e -> t(e)).toArray(); + return v.type().name()+'@'+Integer.toHexString(v.hashCode()); + } +} From e9e97800ab2179ee8af165de49d1bcf3368cfaa3 Mon Sep 17 00:00:00 2001 From: seongtaekkim Date: Mon, 16 Oct 2023 16:35:42 +0900 Subject: [PATCH 2/2] Test: ADD StaekFrame Example --- .../main/java/me/staek/jvm/StackFrameEx.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 java/jvm/jvm/src/main/java/me/staek/jvm/StackFrameEx.java diff --git a/java/jvm/jvm/src/main/java/me/staek/jvm/StackFrameEx.java b/java/jvm/jvm/src/main/java/me/staek/jvm/StackFrameEx.java new file mode 100644 index 00000000..8aabdb5a --- /dev/null +++ b/java/jvm/jvm/src/main/java/me/staek/jvm/StackFrameEx.java @@ -0,0 +1,31 @@ +package me.staek.jvm; + +import java.lang.StackWalker.StackFrame; +import java.lang.reflect.Method; +import java.util.List; +import java.util.stream.Collectors; + +public class StackFrameEx { + public static void main(String args[]) throws Exception { + Method test1Method = Helper1.class.getDeclaredMethod("test1", (Class[])null); + test1Method.invoke(null, (Object[]) null); + } +} + +// Helper1 class +class Helper1 { + protected static void test1() { + int a = 1; + Helper2.test2(); + } +} + +// Helper2 class +class Helper2 { + protected static void test2() { + List stack = StackWalker.getInstance().walk((s) -> s.collect(Collectors.toList())); + for(StackFrame frame : stack) { + System.out.println(frame.getClassName() + " " + frame.getLineNumber() + " " + frame.getMethodName()); + } + } +}