diff --git a/Ghidra/Debug/Debugger-jpda/data/debugger-launchers/local-java.jsh b/Ghidra/Debug/Debugger-jpda/data/debugger-launchers/local-java.jsh index 409b733e43..ef53572a03 100755 --- a/Ghidra/Debug/Debugger-jpda/data/debugger-launchers/local-java.jsh +++ b/Ghidra/Debug/Debugger-jpda/data/debugger-launchers/local-java.jsh @@ -1,5 +1,6 @@ -//@title java launch -//@timeout 20000 +//@title java +////@image-opt env:OPT_TARGET_CLASS +//@timeout 2000000 //@desc //@desc

Launch with java

//@desc

@@ -10,10 +11,11 @@ //@menu-group local //@icon icon.debugger //@help TraceRmiLauncherServicePlugin#java +//@env OPT_TARGET_CLASS:str="" "Image" "The Main Class to launch (defaults to current program)." +//@env OPT_TARGET_CLASSPATH:str="" "ClassPath" "The JVM classpath" //@args "Arguments" "Command-line arguments to pass to the target" //@enum Arch:str JVM Dalvik //@env OPT_ARCH:Arch="JVM" "Arch" "Either 'JVM' or 'Dalvik'" -//@env OPT_TARGET_CLASS:str="" "Image" "The Main Class to launch (defaults to current program)." ////@env OPT_SUSPEND:bool=true "Suspend" "Suspend the VM on launch." //@env OPT_INCLUDE:str=n "Include virtual threads" "Include virtual threads." //@env OPT_JSHELL_PATH:file="" "JShell cmd (if desired)" "The full path to jshell." diff --git a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/manager/JdiEventHandler.java b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/manager/JdiEventHandler.java index 10176849da..2efc29bfcc 100644 --- a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/manager/JdiEventHandler.java +++ b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/manager/JdiEventHandler.java @@ -140,6 +140,7 @@ public class JdiEventHandler implements Runnable { //System.err.println(event + ":" + vm); return switch (event) { case ExceptionEvent ev -> processException(ev); + case BreakpointEvent ev -> processBreakpoint(ev); case AccessWatchpointEvent ev -> processAccessWatchpoint(ev); case ModificationWatchpointEvent ev -> processWatchpointModification(ev); case WatchpointEvent ev -> processWatchpoint(ev); diff --git a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/manager/impl/JdiManagerImpl.java b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/manager/impl/JdiManagerImpl.java index d8c58efe95..f71e379d0f 100644 --- a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/manager/impl/JdiManagerImpl.java +++ b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/manager/impl/JdiManagerImpl.java @@ -17,7 +17,7 @@ package ghidra.dbg.jdi.manager.impl; import static ghidra.lifecycle.Unfinished.TODO; -import java.io.IOException; +import java.io.*; import java.util.*; import java.util.concurrent.*; @@ -29,6 +29,7 @@ import com.sun.jdi.event.Event; import ghidra.dbg.jdi.manager.*; import ghidra.dbg.jdi.manager.JdiCause.Causes; +import ghidra.dbg.jdi.rmi.jpda.JdiArguments; import ghidra.util.Msg; import ghidra.util.datastruct.ListenerSet; @@ -61,23 +62,40 @@ public class JdiManagerImpl implements JdiManager { virtualMachineManager = Bootstrap.virtualMachineManager(); } + private static void pumpStream(InputStream in, OutputStream out) { + try { + in.transferTo(out); + } + catch (IOException e) { + // We're done! + } + } + public VirtualMachine connectVM(Connector cx, Map arguments) throws Exception { - if (cx instanceof LaunchingConnector) { - LaunchingConnector lcx = (LaunchingConnector) cx; - return lcx.launch(arguments); + if (cx instanceof LaunchingConnector lcx) { + VirtualMachine vm = lcx.launch(arguments); + new Thread(() -> pumpStream(vm.process().getErrorStream(), System.err)).start(); + new Thread(() -> pumpStream(vm.process().getInputStream(), System.out)).start(); + return vm; } - if (cx instanceof AttachingConnector) { - AttachingConnector acx = (AttachingConnector) cx; + if (cx instanceof AttachingConnector acx) { return acx.attach(arguments); } - if (cx instanceof ListeningConnector) { - ListeningConnector lcx = (ListeningConnector) cx; + if (cx instanceof ListeningConnector lcx) { return lcx.accept(arguments); } throw new Exception("Unknown connector type"); } + public VirtualMachine createVM(Map env) { + JdiArguments args = new JdiArguments(env); + Connector cx = args.getConnector(virtualMachineManager); + Map defaultArguments = cx.defaultArguments(); + args.putArguments(defaultArguments); + return addVM(cx, defaultArguments); + } + @Override public void terminate() { /** diff --git a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/TraceJdiArch.java b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/JdiArch.java similarity index 98% rename from Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/TraceJdiArch.java rename to Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/JdiArch.java index 93d360eacd..27d444eb98 100644 --- a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/TraceJdiArch.java +++ b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/JdiArch.java @@ -23,7 +23,7 @@ import ghidra.app.plugin.core.debug.client.tracermi.DefaultRegisterMapper; import ghidra.program.model.lang.*; import ghidra.program.util.DefaultLanguageService; -public class TraceJdiArch { +public class JdiArch { private LanguageID langID; private Language language; diff --git a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/JdiArguments.java b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/JdiArguments.java new file mode 100644 index 0000000000..01073ca7eb --- /dev/null +++ b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/JdiArguments.java @@ -0,0 +1,109 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.dbg.jdi.rmi.jpda; + +import java.util.Map; + +import com.sun.jdi.VirtualMachineManager; +import com.sun.jdi.connect.AttachingConnector; +import com.sun.jdi.connect.Connector; +import com.sun.jdi.connect.Connector.Argument; + +import ghidra.dbg.util.ShellUtils; + +public class JdiArguments { + enum Mode { + ATTACH_PORT, ATTACH_PID, LAUNCH; + } + + private final Map env; + private final Mode mode; + + public JdiArguments(Map env) { + this.env = Map.copyOf(env); + this.mode = computeMode(); + } + + /** + * Compute/detect the launch mode using the environment map. + * + *

+ * It'd be nice if this were selected/specified in the script body, rather than by what options + * are present in its header. The reason we can't, though, is that the JDI client thread needs + * to also work within Ghidra's JVM, i.e., without launching a jshell subprocess. By far, the + * simplest way to accomplish this is to keep all the logic here, and just pass the environment + * map in. For the jshell-subprocess case, it's the environment map proper. For the + * in-Ghidra's-VM case, it's the map we would have passed when creating the subprocess. + * + * @return the mode. + */ + protected Mode computeMode() { + if (env.containsKey("OPT_PORT")) { + return Mode.ATTACH_PORT; + } + if (env.containsKey("OPT_PID")) { + return Mode.ATTACH_PID; + } + return Mode.LAUNCH; + } + + protected AttachingConnector findConnectorByArgKey(VirtualMachineManager vmm, String key) { + return vmm.attachingConnectors() + .stream() + .filter(ac -> ac.defaultArguments().containsKey(key)) + .findFirst() + .orElseThrow(); + } + + public Connector getConnector(VirtualMachineManager vmm) { + return switch (mode) { + case ATTACH_PORT -> findConnectorByArgKey(vmm, "port"); + case ATTACH_PID -> findConnectorByArgKey(vmm, "pid"); + case LAUNCH -> vmm.defaultConnector(); + }; + } + + public void putArguments(Map args) { + switch (mode) { + case ATTACH_PORT -> { + args.get("hostname").setValue(env.get("OPT_HOST").toString()); + args.get("port").setValue(env.get("OPT_PORT").toString()); + args.get("timeout").setValue(env.get("OPT_TIMEOUT").toString()); + } + case ATTACH_PID -> { + args.get("pid").setValue(env.get("OPT_PID").toString()); + args.get("timeout").setValue(env.get("OPT_TIMEOUT").toString()); + } + case LAUNCH -> { + args.get("main").setValue(env.get("OPT_TARGET_CLASS")); + Argument argSuspend = args.get("suspend"); + String optSuspend = env.get("OPT_SUSPEND"); + if (argSuspend != null && optSuspend != null) { + argSuspend.setValue(optSuspend); + } + Argument argIncludeVirtualThreads = args.get("includevirtualthreads"); + String optInclude = env.get("OPT_INCLUDE"); + if (argIncludeVirtualThreads != null && optInclude != null) { + argIncludeVirtualThreads.setValue(optInclude); + } + String cp = env.get("OPT_TARGET_CLASSPATH"); + if (!cp.isBlank()) { + args.get("options").setValue("-cp " + ShellUtils.generateArgument(cp)); + } + } + } + } +} diff --git a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/JdiClientThread.java b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/JdiClientThread.java index ab2ac07b91..ae0c79d45a 100644 --- a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/JdiClientThread.java +++ b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/JdiClientThread.java @@ -17,7 +17,6 @@ package ghidra.dbg.jdi.rmi.jpda; import java.util.Map; -import com.sun.jdi.connect.AttachingConnector; import com.sun.jdi.connect.Connector; import com.sun.jdi.connect.Connector.Argument; @@ -26,70 +25,31 @@ import ghidra.dbg.jdi.manager.impl.JdiManagerImpl; import ghidra.util.Msg; public class JdiClientThread extends Thread { - enum Mode { - ATTACH_PORT, ATTACH_PID, LAUNCH; - } private final Map env; - private final Mode mode; + private final JdiArguments arguments; private JdiManagerImpl manager; - private TraceJdiManager traceJdiManager; + private JdiManager jdiManager; public JdiClientThread(Map env) { this.env = env; - this.mode = computeMode(); - } - - /** - * Compute/detect the launch mode using the environment map. - * - *

- * It'd be nice if this were selected/specified in the script body, rather than by what options - * are present in its header. The reason we can't, though, is that the JDI client thread needs - * to also work within Ghidra's JVM, i.e., without launching a jshell subprocess. By far, the - * simplest way to accomplish this is to keep all the logic here, and just pass the environment - * map in. For the jshell-subprocess case, it's the environment map proper. For the - * in-Ghidra's-VM case, it's the map we would have passed when creating the subprocess. - * - * @return the mode. - */ - Mode computeMode() { - if (env.containsKey("OPT_PORT")) { - return Mode.ATTACH_PORT; - } - if (env.containsKey("OPT_PID")) { - return Mode.ATTACH_PID; - } - return Mode.LAUNCH; - } - - AttachingConnector findConnectorByArgKey(String key) { - return manager.getVirtualMachineManager() - .attachingConnectors() - .stream() - .filter(ac -> ac.defaultArguments().containsKey(key)) - .findFirst() - .orElseThrow(); + this.arguments = new JdiArguments(env); } @Override public void run() { try { manager = new JdiManagerImpl(); - traceJdiManager = new TraceJdiManager(manager, env); + jdiManager = new JdiManager(manager, env); - Connector cx = switch (mode) { - case ATTACH_PORT -> findConnectorByArgKey("port"); - case ATTACH_PID -> findConnectorByArgKey("pid"); - case LAUNCH -> manager.getVirtualMachineManager().defaultConnector(); - }; + Connector cx = arguments.getConnector(manager.getVirtualMachineManager()); Map args = cx.defaultArguments(); - putArguments(args); + arguments.putArguments(args); if (manager.addVM(cx, args) != null) { - traceJdiManager.getCommands().ghidraTraceSyncEnable(); - traceJdiManager.getHooks().vmStarted(null, Causes.UNCLAIMED); + jdiManager.getCommands().ghidraTraceSyncEnable(); + jdiManager.getHooks().vmStarted(null, Causes.UNCLAIMED); } else { // Nothing. addVM should already have reported the error. @@ -100,30 +60,11 @@ public class JdiClientThread extends Thread { } } - protected void putArguments(Map args) { - switch (mode) { - case ATTACH_PORT -> { - args.get("hostname").setValue(env.get("OPT_HOST").toString()); - args.get("port").setValue(env.get("OPT_PORT").toString()); - args.get("timeout").setValue(env.get("OPT_TIMEOUT").toString()); - } - case ATTACH_PID -> { - args.get("pid").setValue(env.get("OPT_PID").toString()); - args.get("timeout").setValue(env.get("OPT_TIMEOUT").toString()); - } - case LAUNCH -> { - args.get("main").setValue(env.get("OPT_TARGET_CLASS")); - //args.get("suspend").setValue(env.get("OPT_SUSPEND")); - args.get("includevirtualthreads").setValue(env.get("OPT_INCLUDE")); - } - } + public JdiManager mgr() { + return jdiManager; } - public TraceJdiManager mgr() { - return traceJdiManager; - } - - public TraceJdiCommands cmds() { - return traceJdiManager.getCommands(); + public JdiCommands cmds() { + return jdiManager.getCommands(); } } diff --git a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/TraceJdiCommands.java b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/JdiCommands.java similarity index 81% rename from Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/TraceJdiCommands.java rename to Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/JdiCommands.java index 4299d79b2b..75fff119cb 100644 --- a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/TraceJdiCommands.java +++ b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/JdiCommands.java @@ -15,7 +15,10 @@ */ package ghidra.dbg.jdi.rmi.jpda; +import static ghidra.dbg.jdi.rmi.jpda.JdiManager.*; + import java.io.IOException; +import java.io.PrintStream; import java.lang.ProcessHandle.Info; import java.math.BigInteger; import java.net.InetSocketAddress; @@ -23,6 +26,9 @@ import java.nio.channels.*; import java.util.*; import java.util.Map.Entry; import java.util.concurrent.ExecutionException; +import java.util.stream.IntStream; + +import org.apache.commons.lang3.StringUtils; import com.sun.jdi.*; import com.sun.jdi.Method; @@ -36,6 +42,7 @@ import ghidra.program.model.address.*; import ghidra.program.model.lang.*; import ghidra.program.model.lang.Language; import ghidra.rmi.trace.TraceRmi.*; +import ghidra.trace.model.Lifespan; import ghidra.util.Msg; /* @@ -49,7 +56,7 @@ import ghidra.util.Msg; class State { - RmiClient client; + public RmiClient client; public RmiTrace trace; RmiTransaction tx; @@ -109,25 +116,16 @@ class State { } -public class TraceJdiCommands { +public class JdiCommands { - private TraceJdiManager manager; + private JdiManager manager; private JdiManagerImpl jdi; public State state; private String[] regNames = { "PC", "return_address" }; public long MAX_REFS = 100; -// protected static final TargetStepKindSet SUPPORTED_KINDS = TargetStepKindSet.of( // -// TargetStepKind.FINISH, // -// TargetStepKind.LINE, // -// TargetStepKind.OVER, // -// TargetStepKind.OVER_LINE, // -// TargetStepKind.RETURN, // -// TargetStepKind.UNTIL, // -// TargetStepKind.EXTENDED); - - public TraceJdiCommands(TraceJdiManager manager) { + public JdiCommands(JdiManager manager) { this.manager = manager; this.jdi = manager.getJdi(); state = new State(); @@ -145,7 +143,7 @@ public class TraceJdiCommands { state.client = new RmiClient(channel, "jdi"); state.client.setRegistry(manager.remoteMethodRegistry); state.client.negotiate("Connect"); - Msg.info(this, "Connected to " + state.client.getDescription() + " at " + address); + Msg.out("Connected to " + state.client.getDescription()); } catch (NumberFormatException e) { throw new RuntimeException("Port must be numeric"); @@ -187,8 +185,7 @@ public class TraceJdiCommands { state.client = new RmiClient(client, "jdi"); state.client.setRegistry(manager.remoteMethodRegistry); client.configureBlocking(false); - Msg.info(this, "Connected from " + state.client.getDescription() + " at " + - client.getLocalAddress()); + Msg.out("Connected from " + state.client.getDescription()); } } keyIterator.remove(); @@ -219,7 +216,7 @@ public class TraceJdiCommands { } public void startTrace(String name) { - TraceJdiArch arch = manager.getArch(); + JdiArch arch = manager.getArch(); LanguageID language = arch.computeGhidraLanguage(); CompilerSpecID compiler = arch.computeGhidraCompiler(language); state.trace = state.client.createTrace(name, language, compiler); @@ -245,6 +242,9 @@ public class TraceJdiCommands { if (name == null) { name = computeName(); } + else if (name.contains("/")) { + name = name.substring(name.lastIndexOf("/")); + } state.requireNoTrace(); startTrace(name); } @@ -266,19 +266,26 @@ public class TraceJdiCommands { startTrace(name); } + public VirtualMachine ghidraTraceCreate(Map env) { + return manager.getJdi().createVM(env); + } + public void ghidraTraceInfo() { if (state.client == null) { Msg.error(this, "Not connected to Ghidra"); + return; } - Msg.info(this, "Connected to" + state.client.getDescription()); + Msg.info(this, "Connected to " + state.client.getDescription()); if (state.trace == null) { Msg.error(this, "No trace"); } - Msg.info(this, "Trace active"); + else { + Msg.info(this, "Trace active"); + } } public void ghidraTraceInfoLcsp() { - TraceJdiArch arch = manager.getArch(); + JdiArch arch = manager.getArch(); LanguageID language = arch.computeGhidraLanguage(); CompilerSpecID compiler = arch.computeGhidraCompiler(language); Msg.info(this, "Selected Ghidra language: " + language); @@ -286,7 +293,7 @@ public class TraceJdiCommands { } public void ghidraTraceTxStart(String description) { - state.requireTx(); + state.requireNoTx(); state.tx = state.requireTrace().startTx(description, false); } @@ -332,7 +339,6 @@ public class TraceJdiCommands { public void ghidraTraceDelMem(Address address, long length) { state.requireTrace(); try (RmiTransaction tx = state.trace.startTx("ghidraTraceDelMem", false)) { - VirtualMachine currentVM = manager.getJdi().getCurrentVM(); Address mapped = state.trace.memoryMapper.map(address); AddressRangeImpl range = new AddressRangeImpl(mapped, mapped.add(length - 1)); state.trace.deleteBytes(range, state.trace.getSnap()); @@ -369,19 +375,26 @@ public class TraceJdiCommands { public void ghidraTraceInsertObj(String path) { state.requireTx(); try (RmiTransaction tx = state.trace.startTx("ghidraTraceInsertObj", false)) { - state.trace.proxyObjectPath(path).insert(state.trace.getSnap(), Resolution.CR_ADJUST); + Lifespan span = state.trace.proxyObjectPath(path) + .insert(state.trace.getSnap(), Resolution.CR_ADJUST); + System.out.println("Inserted object: lifespan=" + span); } } public void ghidraTraceRemoveObj(String path) { state.requireTx(); try (RmiTransaction tx = state.trace.startTx("ghidraTraceRemoveObj", false)) { - state.trace.proxyObjectPath(path).remove(state.trace.getSnap(), false); + Lifespan span = state.trace.proxyObjectPath(path).remove(state.trace.getSnap(), false); + System.out.println("Removed object: lifespan=" + span); } } -// public void ghidraTraceSetValue(String path, String key, Object value, TargetObjectSchema schema) { -// } + public void ghidraTraceSetValue(String path, String key, Object value) { + state.requireTx(); + try (RmiTransaction tx = state.trace.startTx("ghidraTraceSetValue", false)) { + setValue(path, key, value); + } + } public void ghidraTraceRetainValues(String kind, String path, Set keys) { state.requireTx(); @@ -405,11 +418,77 @@ public class TraceJdiCommands { return state.trace.proxyObjectPath(path); } -// public void ghidraTraceGetValues(String pattern) { -// } -// -// public void ghidraTraceGetValuesRng() { -// } + public static class Tabulator { + static class Column { + int width; + + public void measure(String string) { + width = Math.max(width, string.length()); + } + + public void print(PrintStream out, String string) { + out.print(pad(string)); + } + + private String pad(String string) { + return StringUtils.rightPad(string, width); + } + } + + private final PrintStream out; + private final List columns; + + public Tabulator(PrintStream out, int colCount) { + this.out = out; + this.columns = IntStream.range(0, colCount).mapToObj(i -> new Column()).toList(); + } + + public void measure(Object... row) { + if (row.length != columns.size()) { + throw new IllegalArgumentException("Column count mismatch"); + } + for (int i = 0; i < row.length; i++) { + columns.get(i).measure(row[i].toString()); + } + } + + public void print(Object... row) { + if (row.length != columns.size()) { + throw new IllegalArgumentException("Column count mismatch"); + } + for (int i = 0; i < row.length; i++) { + if (i != 0) { + out.print(" "); + } + columns.get(i).print(out, row[i].toString()); + } + out.println(); + } + } + + public void printValues(List values) { + Tabulator tab = new Tabulator(System.out, 5); + tab.measure("Parent", "Key", "Span", "Value", "Type"); + for (RmiTraceObjectValue d : values) { + tab.measure(d.parent().getPath(), d.span(), d.key(), d.value(), d.schema()); + } + tab.print("Parent", "Key", "Span", "Value", "Type"); + for (RmiTraceObjectValue d : values) { + tab.print(d.parent().getPath(), d.span(), d.key(), d.value(), d.schema()); + } + } + + public void ghidraTraceGetValues(String pattern) { + state.requireTrace(); + List values = state.trace.getValues(pattern); + printValues(values); + } + + public void ghidraTraceGetValuesRng(Address addr, long sz) { + state.requireTrace(); + List values = state.trace.getValuesRng(addr, sz); + printValues(values); + } public void ghidraTracePutVMs() { state.requireTrace(); @@ -467,7 +546,6 @@ public class TraceJdiCommands { public void ghidraTraceDisassemble(Address address) { state.requireTrace(); - VirtualMachine currentVM = manager.getJdi().getCurrentVM(); MemoryMapper mapper = state.trace.memoryMapper; Address mappedAddress = mapper.map(address); AddressSpace addressSpace = mappedAddress.getAddressSpace(); @@ -480,7 +558,6 @@ public class TraceJdiCommands { // STATE // public void putMemState(Address start, long length, MemoryState memState, boolean usePages) { - VirtualMachine currentVM = manager.getJdi().getCurrentVM(); Address mapped = state.trace.memoryMapper.map(start); if (mapped.getAddressSpace() != start.getAddressSpace() && !memState.equals(MemoryState.MS_UNKNOWN)) { @@ -503,7 +580,7 @@ public class TraceJdiCommands { } public RegisterValue[] putRegisters(StackFrame frame, String ppath) { - TraceJdiArch arch = manager.getArch(); + JdiArch arch = manager.getArch(); Language lang = arch.getLanguage(); Set keys = new HashSet<>(); RegisterValue[] rvs = new RegisterValue[regNames.length]; @@ -568,7 +645,7 @@ public class TraceJdiCommands { Address addr = manager.getAddressFromLocation(loc); RegisterMapper mapper = state.trace.registerMapper; String regName = mapper.mapName(name); - TraceJdiArch arch = manager.getArch(); + JdiArch arch = manager.getArch(); Language lang = arch.getLanguage(); Register register = lang.getRegister(name); RegisterValue rv = new RegisterValue(register, addr.getOffsetAsBigInteger()); @@ -584,7 +661,6 @@ public class TraceJdiCommands { } public void putMem(Address address, long length, boolean create) { - VirtualMachine vm = manager.getJdi().getCurrentVM(); MemoryMapper mapper = state.trace.memoryMapper; Address mappedAddress = mapper.map(address); AddressSpace addressSpace = mappedAddress.getAddressSpace(); @@ -636,8 +712,8 @@ public class TraceJdiCommands { } public void putTypeDetails(String path, Type type) { - setValue(path, "_display", "Type: " + type.name()); - setValue(path, "Signature", type.signature()); + setValue(path, ATTR_DISPLAY, "Type: " + type.name()); + setValue(path, ATTR_SIGNATURE, type.signature()); } public void putReferenceTypeContainer(String ppath, List reftypes) { @@ -666,17 +742,28 @@ public class TraceJdiCommands { if (name.indexOf(".") > 0) { name = name.substring(name.lastIndexOf(".") + 1); } - setValue(path, TraceJdiManager.MODULE_NAME_ATTRIBUTE_NAME, name + ".class"); + setValue(path, ATTR_MODULE_NAME, name + ".class"); putRefTypeAttributes(path, reftype); - createObject(path + ".Fields"); - createObject(path + ".Instances"); - createObject(path + ".Locations"); - //createObject(path + ".Methods"); + String fpath = createObject(path + ".Fields"); + String ipath = createObject(path + ".Instances"); + String lpath = createObject(path + ".Locations"); + insertObject(fpath); + insertObject(ipath); + insertObject(lpath); putMethodContainer(path + ".Methods", reftype); String rpath = createObject(path + ".Relations"); + insertObject(rpath); ModuleReference module = reftype.module(); - createObject(module, module.name(), rpath + ".ModuleRef"); + String moduleName = module.name(); + if (moduleName == null) { + moduleName = ""; + } + if (moduleName.contains(".")) { + moduleName = "\"" + moduleName + "\""; + } + String mrpath = createObject(module, moduleName, rpath + ".ModuleRef"); + insertObject(mrpath); if (reftype instanceof ArrayType at) { putArrayTypeDetails(rpath, at); } @@ -713,6 +800,7 @@ public class TraceJdiCommands { setValue(path, "defaultStratum", reftype.defaultStratum()); setValue(path, "availableStata", reftype.availableStrata()); setValue(path, "failedToInitialize", reftype.failedToInitialize()); + insertObject(path); } private void registerMemory(String path, ReferenceType reftype) { @@ -727,17 +815,17 @@ public class TraceJdiCommands { bounds.add(range); String mpath = createObject(mempath + manager.key(m.toString())); - setValue(mpath, "Range", range); - insertObject(path); + setValue(mpath, ATTR_RANGE, range); + insertObject(mpath); } } } AddressRange range = manager.putAddressRange(reftype, bounds); - setValue(path, "Range", range); + setValue(path, ATTR_RANGE, range); - setValue(path, "Count", reftype.constantPoolCount()); + setValue(path, ATTR_COUNT, reftype.constantPoolCount()); range = manager.getPoolAddressRange(reftype, getSize(reftype) - 1); - setValue(path, "RangeCP", range); + setValue(path, ATTR_RANGE_CP, range); try { putMem(range.getMinAddress(), range.getLength(), true); } @@ -755,19 +843,24 @@ public class TraceJdiCommands { } } - public void loadReferenceType(String ppath, List reftypes, String targetClass) { + public boolean loadReferenceType(String ppath, List reftypes, + String targetClass) { + boolean result = false; List classes = reftypes; for (ReferenceType ref : classes) { if (ref.name().contains(targetClass)) { putReferenceType(ppath, ref, true); + result = true; } } + return result; } public void putArrayTypeDetails(String path, ArrayType type) { + String cpath = createObject(path + ".ComponentType"); setValue(path, "ComponentSignature", type.componentSignature()); setValue(path, "ComponentTypeName", type.componentTypeName()); - createObject(path + ".ComponentType"); + insertObject(cpath); } public void putClassTypes(String ppath, List reftypes) { @@ -781,10 +874,14 @@ public class TraceJdiCommands { public void putClassTypeDetails(String path, ClassType type) { setValue(path, "IsEnum", type.isEnum()); - createObject(path + ".AllInterfaces"); - createObject(path + ".Interfaces"); - createObject(path + ".SubClasses"); - createObject(path + ".ClassType"); + String aipath = createObject(path + ".AllInterfaces"); + String ipath = createObject(path + ".Interfaces"); + String scpath = createObject(path + ".SubClasses"); + String cpath = createObject(path + ".ClassType"); + insertObject(aipath); + insertObject(ipath); + insertObject(scpath); + insertObject(cpath); } public void putInterfaceTypes(String ppath, List reftypes) { @@ -797,9 +894,12 @@ public class TraceJdiCommands { } public void putInterfaceTypeDetails(String path, InterfaceType type) { - createObject(path + ".Implementors"); - createObject(path + ".SubInterfaces"); - createObject(path + ".SuperInterfaces"); + String impath = createObject(path + ".Implementors"); + String sbpath = createObject(path + ".SubInterfaces"); + String sppath = createObject(path + ".SuperInterfaces"); + insertObject(impath); + insertObject(sbpath); + insertObject(sppath); } // VALUES // @@ -812,7 +912,7 @@ public class TraceJdiCommands { public void putValue(String ppath, String key, Value value) { String path = createObject(value, key, ppath); - setValue(path, "_display", "Value: " + value.toString()); + setValue(path, ATTR_DISPLAY, "Value: " + value.toString()); //putValueDetailsByType(path, value); insertObject(path); } @@ -848,35 +948,35 @@ public class TraceJdiCommands { } public void putValueDetails(String path, Value value) { - putType(path, "Type", value.type()); + putType(path, ATTR_TYPE, value.type()); } public void putPrimitiveValue(String ppath, PrimitiveValue value) { String path = createObject(value, value.toString(), ppath); putValueDetails(path, value); if (value instanceof BooleanValue v) { - setValue(path, "Value", v.booleanValue()); + setValue(path, ATTR_VALUE, v.booleanValue()); } if (value instanceof ByteValue b) { - setValue(path, "Value", b.byteValue()); + setValue(path, ATTR_VALUE, b.byteValue()); } if (value instanceof CharValue v) { - setValue(path, "Value", v.charValue()); + setValue(path, ATTR_VALUE, v.charValue()); } if (value instanceof ShortValue v) { - setValue(path, "Value", v.shortValue()); + setValue(path, ATTR_VALUE, v.shortValue()); } if (value instanceof IntegerValue v) { - setValue(path, "Value", v.intValue()); + setValue(path, ATTR_VALUE, v.intValue()); } if (value instanceof LongValue v) { - setValue(path, "Value", v.longValue()); + setValue(path, ATTR_VALUE, v.longValue()); } if (value instanceof FloatValue v) { - setValue(path, "Value", v.floatValue()); + setValue(path, ATTR_VALUE, v.floatValue()); } if (value instanceof DoubleValue v) { - setValue(path, "Value", v.doubleValue()); + setValue(path, ATTR_VALUE, v.doubleValue()); } insertObject(path); } @@ -962,7 +1062,8 @@ public class TraceJdiCommands { public void putObjectContainer(String path, List objects) { for (ObjectReference obj : objects) { - createObject(obj, obj.toString(), path); + String opath = createObject(obj, obj.toString(), path); + insertObject(opath); } } @@ -983,27 +1084,34 @@ public class TraceJdiCommands { // IGNORE } setValue(apath, "isCollected", ref.isCollected()); + insertObject(apath); String rpath = createObject(path + ".Relations"); try { if (ref.owningThread() != null) { - createObject(rpath + ".OwningThread"); + String otpath = createObject(rpath + ".OwningThread"); + insertObject(otpath); } if (ref.waitingThreads() != null) { - createObject(rpath + ".WaitingThreads"); + String wtpath = createObject(rpath + ".WaitingThreads"); + insertObject(wtpath); } } catch (IncompatibleThreadStateException e) { // IGNORE } if (ref.referenceType() != null) { - createObject(rpath + ".ReferenceType"); + String rtpath = createObject(rpath + ".ReferenceType"); + insertObject(rtpath); } if (ref.referringObjects(MAX_REFS) != null) { - createObject(rpath + ".ReferringObjects"); + String ropath = createObject(rpath + ".ReferringObjects"); + insertObject(ropath); } if (!(ref instanceof ArrayReference)) { - createObject(path + ".Variables"); + String vpath = createObject(path + ".Variables"); + insertObject(vpath); } + insertObject(rpath); } public void putArrayReference(String ppath, ArrayReference ref) { @@ -1014,8 +1122,9 @@ public class TraceJdiCommands { public void putArrayReferenceDetails(String path, ArrayReference ref) { putObjectReferenceDetails(path, ref); - setValue(path, "Length", ref.length()); - createObject(path + ".Values"); + setValue(path, ATTR_LENGTH, ref.length()); + String vpath = createObject(path + ".Values"); + insertObject(vpath); } public void putClassLoaderReference(String ppath, ClassLoaderReference ref) { @@ -1026,8 +1135,10 @@ public class TraceJdiCommands { public void putClassLoaderReferenceDetails(String path, ClassLoaderReference ref) { putObjectReferenceDetails(path, ref); - createObject(path + ".DefinedClasses"); - createObject(path + ".VisibleClasses"); + String dcpath = createObject(path + ".DefinedClasses"); + String vcpath = createObject(path + ".VisibleClasses"); + insertObject(dcpath); + insertObject(vcpath); } public void putClassObjectReference(String ppath, ClassObjectReference ref) { @@ -1038,7 +1149,8 @@ public class TraceJdiCommands { public void putClassObjectReferenceDetails(String path, ClassObjectReference ref) { putObjectReferenceDetails(path, ref); - createObject(path + ".ReflectedType"); + String rtpath = createObject(path + ".ReflectedType"); + insertObject(rtpath); } public void putModuleReferenceContainer() { @@ -1048,7 +1160,8 @@ public class TraceJdiCommands { List modules = vm.allModules(); for (ModuleReference ref : modules) { keys.add(manager.key(ref.name())); - createObject(ref, ref.name(), ppath); + String mpath = createObject(ref, ref.name(), ppath); + insertObject(mpath); } retainKeys(ppath, keys); } @@ -1061,7 +1174,8 @@ public class TraceJdiCommands { public void putModuleReferenceDetails(String path, ModuleReference ref) { putObjectReferenceDetails(path, ref); - createObject(path + ".ClassLoader"); + String clpath = createObject(path + ".ClassLoader"); + insertObject(clpath); } public void putStringReference(String ppath, StringReference ref) { @@ -1072,7 +1186,7 @@ public class TraceJdiCommands { public void putStringReferenceDetails(String path, StringReference ref) { putObjectReferenceDetails(path, ref); - setValue(path, "Value", ref.value()); + setValue(path, ATTR_VALUE, ref.value()); } public void putThreadGroupContainer(String refpath, List refs) { @@ -1094,10 +1208,13 @@ public class TraceJdiCommands { public void putThreadGroupReferenceDetails(String path, ThreadGroupReference ref) { putObjectReferenceDetails(path, ref); if (ref.parent() != null) { - createObject(path + ".Parent"); + String ppath = createObject(path + ".Parent"); + insertObject(ppath); } - createObject(path + ".ThreadGroups"); - createObject(path + ".Threads"); + String tgpath = createObject(path + ".ThreadGroups"); + String tpath = createObject(path + ".Threads"); + insertObject(tgpath); + insertObject(tpath); } public void putThreadContainer(String refpath, List refs, boolean asLink) { @@ -1123,13 +1240,18 @@ public class TraceJdiCommands { public void putThreadReferenceDetails(String path, ThreadReference ref) { putObjectReferenceDetails(path, ref); - createObject(path + ".Stack"); + String spath = createObject(path + ".Stack"); String rpath = createObject(path + ".Relations"); - createObject(rpath + ".CurrentContendedMonitor"); - createObject(rpath + ".OwnedMonitors"); - createObject(rpath + ".OwnedMonitorsAndFrames"); - createObject(rpath + ".ThreadGroup"); + String ccpath = createObject(rpath + ".CurrentContendedMonitor"); + String ompath = createObject(rpath + ".OwnedMonitors"); + String omfpath = createObject(rpath + ".OwnedMonitorsAndFrames"); + String tgpath = createObject(rpath + ".ThreadGroup"); putThreadAttributes(ref, path); + insertObject(spath); + insertObject(ccpath); + insertObject(ompath); + insertObject(omfpath); + insertObject(tgpath); } void putThreadAttributes(ThreadReference thread, String ppath) { @@ -1152,18 +1274,22 @@ public class TraceJdiCommands { // Ignore } setValue(path, "suspendCount", thread.suspendCount()); + insertObject(path); } public void putMonitorInfoContainer(String path, List info) { for (MonitorInfo f : info) { - createObject(f, f.toString(), path); + String ipath = createObject(f, f.toString(), path); + insertObject(ipath); } } public void putMonitorInfoDetails(String path, MonitorInfo info) { setValue(path, "StackDepth", info.stackDepth()); - createObject(path + ".Monitor"); - createObject(path + ".Thread"); + String mpath = createObject(path + ".Monitor"); + String tpath = createObject(path + ".Thread"); + insertObject(mpath); + insertObject(tpath); } // TYPE COMPONENTS @@ -1183,6 +1309,7 @@ public class TraceJdiCommands { catch (IllegalArgumentException iae) { // IGNORE } + keys.add(manager.key(f.name())); putField(path, f, value); } retainKeys(path, keys); @@ -1201,6 +1328,7 @@ public class TraceJdiCommands { catch (IllegalArgumentException iae) { // IGNORE } + keys.add(manager.key(f.name())); putField(path, f, value); } retainKeys(path, keys); @@ -1210,23 +1338,23 @@ public class TraceJdiCommands { String path = createObject(f, f.name(), ppath); putFieldDetails(path, f); if (value != null) { - putValue(path, "Value", value); - setValue(path, "_display", f.name() + " (" + f.typeName() + ") : " + value); + putValue(path, ATTR_VALUE, value); + setValue(path, ATTR_DISPLAY, f.name() + " (" + f.typeName() + ") : " + value); } else { - setValue(path, "_display", f.name() + " (" + f.typeName() + ")"); + setValue(path, ATTR_DISPLAY, f.name() + " (" + f.typeName() + ")"); } insertObject(path); } public void putFieldDetails(String path, Field f) { - setValue(path, TraceJdiManager.MODULE_NAME_ATTRIBUTE_NAME, f.declaringType().name()); + setValue(path, ATTR_MODULE_NAME, f.declaringType().name()); if (f.genericSignature() != null) { setValue(path, "GenericSignature", f.genericSignature()); } putFieldAttributes(path, f); try { - putType(path, "Type", f.type()); + putType(path, ATTR_TYPE, f.type()); } catch (ClassNotLoadedException e) { // IGNORE @@ -1247,6 +1375,7 @@ public class TraceJdiCommands { setValue(path, "isSynthetic", f.isSynthetic()); setValue(path, "isTransient", f.isTransient()); setValue(path, "isVolatile", f.isVolatile()); + insertObject(path); } public void putMethodContainer(String path, ReferenceType reftype) { @@ -1268,24 +1397,27 @@ public class TraceJdiCommands { public void putMethodDetails(String path, Method m, boolean partial) { ReferenceType declaringType = m.declaringType(); - setValue(path, TraceJdiManager.MODULE_NAME_ATTRIBUTE_NAME, declaringType.name()); + setValue(path, ATTR_MODULE_NAME, declaringType.name()); createLink(m, "DeclaringType", declaringType); if (!partial) { - createObject(path + ".Arguments"); + String apath = createObject(path + ".Arguments"); if (m.genericSignature() != null) { setValue(path, "GenericSignature", m.genericSignature()); } - createObject(path + ".Locations"); + String lpath = createObject(path + ".Locations"); setValue(path, "Modifiers", m.modifiers()); setValue(path, "ReturnType", m.returnTypeName()); setValue(path, "Signature", m.signature()); - createObject(path + ".Variables"); + String vpath = createObject(path + ".Variables"); putMethodAttributes(path, m); + insertObject(apath); + insertObject(lpath); + insertObject(vpath); } if (m.location() != null) { AddressRange range = manager.getAddressRange(m); if (!range.equals(manager.defaultRange)) { - setValue(path, "Range", range); + setValue(path, ATTR_RANGE, range); } } String bytes = ""; @@ -1308,6 +1440,12 @@ public class TraceJdiCommands { setValue(path, "isPrivate", m.isPrivate()); setValue(path, "isProtected", m.isProtected()); setValue(path, "isPublic", m.isPublic()); + setValue(path, "isStatic", m.isStatic()); + setValue(path, "isStaticInitializer", m.isStaticInitializer()); + setValue(path, "isSynchronized", m.isSynchronized()); + setValue(path, "isSynthetic", m.isSynthetic()); + setValue(path, "isVarArgs", m.isVarArgs()); + insertObject(path); } // OTHER OBJECTS // @@ -1334,17 +1472,21 @@ public class TraceJdiCommands { } public void putVMDetails(String path, VirtualMachine vm) { - createObject(path + ".Classes"); - createObject(path + ".Memory"); - createObject(path + ".ThreadGroups"); - createObject(path + ".Threads"); + String cpath = createObject(path + ".Classes"); + String mpath = createObject(path + ".Memory"); + String tgpath = createObject(path + ".ThreadGroups"); + String tpath = createObject(path + ".Threads"); Event currentEvent = jdi.getCurrentEvent(); String shortName = vm.name().substring(0, vm.name().indexOf(" ")); String display = currentEvent == null ? shortName : shortName + " [" + currentEvent + "]"; - setValue(path, TraceJdiManager.DISPLAY_ATTRIBUTE_NAME, display); - setValue(path, TraceJdiManager.ARCH_ATTRIBUTE_NAME, vm.name()); - setValue(path, TraceJdiManager.DEBUGGER_ATTRIBUTE_NAME, vm.description()); - setValue(path, TraceJdiManager.OS_ATTRIBUTE_NAME, vm.version()); + setValue(path, ATTR_DISPLAY, display); + setValue(path, ATTR_ARCH, vm.name()); + setValue(path, ATTR_DEBUGGER, vm.description()); + setValue(path, ATTR_OS, vm.version()); + insertObject(cpath); + insertObject(mpath); + insertObject(tgpath); + insertObject(tpath); } public void putProcesses() { @@ -1383,13 +1525,13 @@ public class TraceJdiCommands { Info info = proc.info(); Optional optional = info.command(); if (optional.isPresent()) { - setValue(path, "Executable", optional.get()); + setValue(path, ATTR_EXECUTABLE, optional.get()); } optional = info.commandLine(); if (optional.isPresent()) { - setValue(path, "CommandLine", optional.get()); + setValue(path, ATTR_COMMAND_LINE, optional.get()); } - setValue(path, "Alive", proc.isAlive()); + setValue(path, ATTR_ALIVE, proc.isAlive()); } public void putFrames() { @@ -1409,6 +1551,7 @@ public class TraceJdiCommands { // IGNORE } retainKeys(ppath, keys); + insertObject(ppath); } private void putFrame(String ppath, StackFrame frame, String key) { @@ -1419,17 +1562,20 @@ public class TraceJdiCommands { private void putFrameDetails(String path, StackFrame frame, String key) { Location location = frame.location(); - setValue(path, "_display", "[" + key + "] " + location + ":" + location.method().name() + + setValue(path, ATTR_DISPLAY, "[" + key + "] " + location + ":" + location.method().name() + ":" + location.codeIndex()); - putLocation(path, "Location", location); + putLocation(path, ATTR_LOCATION, location); Address addr = manager.getAddressFromLocation(location); - setValue(path, "PC", addr); + setValue(path, ATTR_PC, addr); String rpath = createObject(path + ".Registers"); putRegisters(frame, rpath); - createObject(path + ".Variables"); + insertObject(rpath); + String vpath = createObject(path + ".Variables"); + insertObject(vpath); try { - createObject(frame.thisObject(), "This", path); + String thpath = createObject(frame.thisObject(), "This", path); + insertObject(thpath); } catch (Exception e) { // Ignore @@ -1439,7 +1585,8 @@ public class TraceJdiCommands { public void putLocationContainer(String path, Method m) { try { for (Location loc : m.allLineLocations()) { - createObject(loc, loc.toString(), path); + String lpath = createObject(loc, loc.toString(), path); + insertObject(lpath); } } catch (AbsentInformationException e) { @@ -1450,7 +1597,8 @@ public class TraceJdiCommands { public void putLocationContainer(String path, ReferenceType ref) { try { for (Location loc : ref.allLineLocations()) { - createObject(loc, loc.toString(), path); + String lpath = createObject(loc, loc.toString(), path); + insertObject(lpath); } } catch (AbsentInformationException e) { @@ -1467,29 +1615,32 @@ public class TraceJdiCommands { public void putLocationDetails(String path, Location location) { Address addr = manager.getAddressFromLocation(location); if (isLoaded(location)) { - setValue(path, "_display", manager.key(location.toString()) + ": " + addr); - setValue(path, "Addr", addr); + setValue(path, ATTR_DISPLAY, manager.key(location.toString()) + ": " + addr); + setValue(path, ATTR_ADDRESS, addr); } - setValue(path, "Index", location.codeIndex()); - setValue(path, "Line#", location.lineNumber()); + setValue(path, ATTR_INDEX, location.codeIndex()); + setValue(path, ATTR_LINENO, location.lineNumber()); try { - setValue(path, "Name", location.sourceName()); + setValue(path, ATTR_NAME, location.sourceName()); } catch (AbsentInformationException e) { - // IGNORE + // sourceName is not available. IGNORE } try { setValue(path, "Path", location.sourcePath()); } catch (AbsentInformationException e) { - // IGNORE + // sourcePath is not available. IGNORE } Method method = location.method(); + RmiTraceObject methodObject = proxyObject(method); + if (methodObject == null) { + String ppath = getVmPath(method.virtualMachine()) + ".Classes"; + putReferenceType(ppath, method.declaringType(), true); + } createLink(location, "Method", method); createLink(location, "DeclaringType", location.declaringType()); createLink(location, "ModuleRef", location.declaringType().module()); - //createObject(method, method.name(), path+".Method"); - //putMethodDetails(path, method); } private boolean isLoaded(Location location) { @@ -1513,15 +1664,15 @@ public class TraceJdiCommands { String path = createObject(lv, lv.name(), ppath); putLocalVariableDetails(path, lv); if (value != null) { - putValue(path, "Value", value); - setValue(path, "_display", lv.name() + ": " + value); + putValue(path, ATTR_VALUE, value); + setValue(path, ATTR_DISPLAY, lv.name() + ": " + value); } insertObject(path); } public void putLocalVariableDetails(String path, LocalVariable lv) { try { - putType(path, "Type", lv.type()); + putType(path, ATTR_TYPE, lv.type()); } catch (ClassNotLoadedException e) { // IGNORE @@ -1536,16 +1687,19 @@ public class TraceJdiCommands { setValue(path, "GenericSignature", lv.genericSignature()); } setValue(path, "Signature", lv.signature()); + insertObject(path); } public void putMethodTypeContainer(String ppath, Method m) { try { for (Type type : m.argumentTypes()) { - createObject(type, type.name(), ppath); + String tpath = createObject(type, type.name(), ppath); + insertObject(tpath); } } catch (ClassNotLoadedException e) { - createObject(ppath + "Class Not Loaded"); + String epath = createObject(ppath + "Class Not Loaded"); + insertObject(epath); } } @@ -1553,7 +1707,7 @@ public class TraceJdiCommands { VirtualMachine vm = manager.getJdi().getCurrentVM(); EventRequestManager requestManager = vm.eventRequestManager(); String ppath = getPath(vm) + ".Breakpoints"; - createObject(ppath); + String path = createObject(ppath); Set keys = new HashSet<>(); List brkReqs = requestManager.breakpointRequests(); @@ -1579,13 +1733,14 @@ public class TraceJdiCommands { } retainKeys(ppath, keys); + insertObject(path); } public void putEvents() { VirtualMachine vm = manager.getJdi().getCurrentVM(); EventRequestManager requestManager = vm.eventRequestManager(); String ppath = getPath(vm) + ".Events"; - createObject(ppath); + String path = createObject(ppath); Set keys = new HashSet<>(); List deathReqs = requestManager.vmDeathRequests(); @@ -1669,6 +1824,7 @@ public class TraceJdiCommands { } retainKeys(ppath, keys); + insertObject(path); } // REQUESTS // @@ -1711,13 +1867,14 @@ public class TraceJdiCommands { private void putReqBreakpointDetails(String path, BreakpointRequest req, String key) { Location location = req.location(); - setValue(path, "_display", "[" + key + "] " + location + ":" + location.method().name() + + setValue(path, ATTR_DISPLAY, "[" + key + "] " + location + ":" + location.method().name() + ":" + location.codeIndex()); Address addr = manager.getAddressFromLocation(location); AddressRangeImpl range = new AddressRangeImpl(addr, addr); - setValue(path, "Range", range); - createObject(location, location.toString(), path + ".Location"); - setValue(path, "Enabled", req.isEnabled()); + setValue(path, ATTR_RANGE, range); + String lpath = createObject(location, location.toString(), path + ".Location"); + insertObject(lpath); + setValue(path, ATTR_ENABLED, req.isEnabled()); putFilterDetails(path, req); } @@ -1730,13 +1887,14 @@ public class TraceJdiCommands { private void putReqAccessWatchpointDetails(String path, AccessWatchpointRequest req, String key) { Field field = req.field(); - setValue(path, "_display", "[" + key + "] " + field + ":" + field.declaringType()); + setValue(path, ATTR_DISPLAY, "[" + key + "] " + field + ":" + field.declaringType()); // NB: This isn't correct, but we need a range (any range) AddressRange range = manager.getPoolAddressRange(field.declaringType(), getSize(field.declaringType())); - setValue(path, "Range", range); - createObject(field, field.toString(), path + ".Field"); - setValue(path, "Enabled", req.isEnabled()); + setValue(path, ATTR_RANGE, range); + String fpath = createObject(field, field.toString(), path + ".Field"); + insertObject(fpath); + setValue(path, ATTR_ENABLED, req.isEnabled()); putFilterDetails(path, req); } @@ -1750,13 +1908,14 @@ public class TraceJdiCommands { private void putReqModificationWatchpointDetails(String path, ModificationWatchpointRequest req, String key) { Field field = req.field(); - setValue(path, "_display", "[" + key + "] " + field + ":" + field.declaringType()); + setValue(path, ATTR_DISPLAY, "[" + key + "] " + field + ":" + field.declaringType()); // NB: This isn't correct, but we need a range (any range) AddressRange range = manager.getPoolAddressRange(field.declaringType(), getSize(field.declaringType())); - setValue(path, "Range", range); - createObject(field, field.toString(), path + ".Field"); - setValue(path, "Enabled", req.isEnabled()); + setValue(path, ATTR_RANGE, range); + String fpath = createObject(field, field.toString(), path + ".Field"); + insertObject(fpath); + setValue(path, ATTR_ENABLED, req.isEnabled()); putFilterDetails(path, req); } @@ -1767,7 +1926,7 @@ public class TraceJdiCommands { } private void putReqExceptionDetails(String path, ExceptionRequest req, String key) { - setValue(path, "Enabled", req.isEnabled()); + setValue(path, ATTR_ENABLED, req.isEnabled()); } private void putReqClassLoad(String ppath, ClassPrepareRequest req, String key) { @@ -1777,7 +1936,7 @@ public class TraceJdiCommands { } private void putReqClassLoadDetails(String path, ClassPrepareRequest req, String key) { - setValue(path, "Enabled", req.isEnabled()); + setValue(path, ATTR_ENABLED, req.isEnabled()); putFilterDetails(path, req); } @@ -1788,7 +1947,7 @@ public class TraceJdiCommands { } private void putReqClassUnloadDetails(String path, ClassUnloadRequest req, String key) { - setValue(path, "Enabled", req.isEnabled()); + setValue(path, ATTR_ENABLED, req.isEnabled()); putFilterDetails(path, req); } @@ -1799,7 +1958,7 @@ public class TraceJdiCommands { } private void putReqMethodEntryDetails(String path, MethodEntryRequest req, String key) { - setValue(path, "Enabled", req.isEnabled()); + setValue(path, ATTR_ENABLED, req.isEnabled()); putFilterDetails(path, req); } @@ -1810,7 +1969,7 @@ public class TraceJdiCommands { } private void putReqMethodExitDetails(String path, MethodExitRequest req, String key) { - setValue(path, "Enabled", req.isEnabled()); + setValue(path, ATTR_ENABLED, req.isEnabled()); putFilterDetails(path, req); } @@ -1821,7 +1980,7 @@ public class TraceJdiCommands { } private void putReqStepRequestDetails(String path, StepRequest req, String key) { - setValue(path, "Enabled", req.isEnabled()); + setValue(path, ATTR_ENABLED, req.isEnabled()); putFilterDetails(path, req); } @@ -1873,19 +2032,19 @@ public class TraceJdiCommands { Object property = req.getProperty("Class"); if (property != null) { if (property instanceof ReferenceType reftype) { - setValue(path, "Class", reftype.name()); + setValue(path, ATTR_CLASS, reftype.name()); } } property = req.getProperty("Instance"); if (property != null) { if (property instanceof ObjectReference ref) { - setValue(path, "Instance", ref.toString()); + setValue(path, ATTR_INSTANCE, ref.toString()); } } property = req.getProperty("Thread"); if (property != null) { if (property instanceof ThreadReference ref) { - setValue(path, "Thread", ref.name()); + setValue(path, ATTR_THREAD, ref.name()); } } } @@ -1946,7 +2105,7 @@ public class TraceJdiCommands { public void ghidraTraceSyncEnable() { try (RmiTransaction tx = state.trace.startTx("ghidraTraceSyncEnable", false)) { - TraceJdiHooks hooks = manager.getHooks(); + JdiHooks hooks = manager.getHooks(); hooks.installHooks(); hooks.enableCurrentVM(); } @@ -1981,6 +2140,28 @@ public class TraceJdiCommands { } } + public void execute(ClassType ct, ThreadReference thread, Method method, List args, + int options) { + try { + Value val = ct.invokeMethod(thread, method, args, options); + System.err.println(val); + } + catch (Exception e) { + throw new RuntimeException(e.getMessage()); + } + } + + public void execute(ObjectReference ref, ThreadReference thread, Method method, + List args, int options) { + try { + Value val = ref.invokeMethod(thread, method, args, options); + System.out.println(val); + } + catch (Exception e) { + throw new RuntimeException(e.getMessage()); + } + } + private int getSize(ReferenceType reftype) { byte[] cp = reftype.constantPool(); int sz = 1; @@ -1998,7 +2179,7 @@ public class TraceJdiCommands { return manager.pathForObj(obj); } - RmiTraceObject proxyObject(Object obj) { + public RmiTraceObject proxyObject(Object obj) { String path = getPath(obj); return path == null ? null : RmiTraceObject.fromPath(state.trace, path); } @@ -2038,7 +2219,8 @@ public class TraceJdiCommands { if (child instanceof Method m) { key = m.name(); } - createObject(child, key, ppath + "." + label); + String lpath = createObject(child, key, ppath + "." + label); + insertObject(lpath); } } @@ -2070,12 +2252,13 @@ public class TraceJdiCommands { String shortName = vm.name().substring(0, vm.name().indexOf(" ")); name = currentEvent == null ? shortName : shortName + " [" + currentEvent + "]"; } - setValue(path, TraceJdiManager.ACCESSIBLE_ATTRIBUTE_NAME, suspended); + setValue(path, ATTR_ACCESSIBLE, suspended); String annotation = suspended ? "(S)" : "(R)"; - setValue(path, TraceJdiManager.DISPLAY_ATTRIBUTE_NAME, name + " " + annotation); + setValue(path, ATTR_DISPLAY, name + " " + annotation); String tstate = suspended ? "STOPPED" : "RUNNING"; - setValue(path, TraceJdiManager.STATE_ATTRIBUTE_NAME, tstate); + setValue(path, ATTR_STATE, tstate); stopped |= suspended; return stopped; } + } diff --git a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/TraceJdiHooks.java b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/JdiHooks.java similarity index 87% rename from Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/TraceJdiHooks.java rename to Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/JdiHooks.java index 3375788ab1..e5e5a8484f 100644 --- a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/TraceJdiHooks.java +++ b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/JdiHooks.java @@ -15,47 +15,35 @@ */ package ghidra.dbg.jdi.rmi.jpda; +import static ghidra.dbg.jdi.rmi.jpda.JdiManager.*; + import java.util.*; import com.sun.jdi.*; import com.sun.jdi.event.*; -import ghidra.app.plugin.core.debug.client.tracermi.RmiTrace; -import ghidra.app.plugin.core.debug.client.tracermi.RmiTransaction; +import ghidra.app.plugin.core.debug.client.tracermi.*; import ghidra.dbg.jdi.manager.*; import ghidra.dbg.jdi.manager.impl.DebugStatus; import ghidra.dbg.jdi.manager.impl.JdiManagerImpl; class HookState { - private TraceJdiCommands cmds; - private Object batch; + private JdiCommands cmds; - public HookState(TraceJdiCommands cmds) { + public HookState(JdiCommands cmds) { this.cmds = cmds; - this.batch = null; } - public void ensureBatch() { - if (batch == null) { - batch = cmds.state.client.startBatch(); - } + public RmiBatch batch() { + return cmds.state.client.startBatch(); } - - public void endBatch() { - if (batch == null) { - return; - } - batch = null; - cmds.state.client.endBatch(); - } - } class VmState { - private TraceJdiManager manager; - private TraceJdiCommands cmds; + private JdiManager manager; + private JdiCommands cmds; private boolean firstPass; boolean classes; boolean modules; @@ -65,7 +53,7 @@ class VmState { boolean events; Set visited; - public VmState(TraceJdiManager manager) { + public VmState(JdiManager manager) { this.manager = manager; this.cmds = manager.getCommands(); this.firstPass = true; @@ -109,9 +97,14 @@ class VmState { } StackFrame frame = manager.getJdi().getCurrentFrame(); if (frame != null) { - if (first || !visited.contains(frame)) { - cmds.putReg(frame); - visited.add(frame); + try { + if (first || !visited.contains(frame)) { + cmds.putReg(frame); + visited.add(frame); + } + } + catch (InvalidStackFrameException e) { + manager.getJdi().setCurrentFrame(null); } } } @@ -154,7 +147,7 @@ class VmState { Process proc = vm.process(); String path = cmds.getPath(proc); if (path != null) { - cmds.setValue(path, "Alive", proc.isAlive()); + cmds.setValue(path, ATTR_ALIVE, proc.isAlive()); } setState(vm); } @@ -168,8 +161,8 @@ class VmState { if (process != null) { exitCode = process.exitValue(); String procpath = cmds.getPath(vm.process()); - cmds.setValue(procpath, "ExitCode", exitCode); - cmds.setValue(procpath, TraceJdiManager.STATE_ATTRIBUTE_NAME, "TERMINATED"); + cmds.setValue(procpath, ATTR_EXIT_CODE, exitCode); + cmds.setValue(procpath, ATTR_STATE, "TERMINATED"); } } catch (IllegalThreadStateException e) { @@ -178,25 +171,25 @@ class VmState { if (description != null) { cmds.state.trace.snapshot(description, "", null); } - cmds.setValue(path, "ExitCode", exitCode); - cmds.setValue(path, TraceJdiManager.STATE_ATTRIBUTE_NAME, "TERMINATED"); + cmds.setValue(path, ATTR_EXIT_CODE, exitCode); + cmds.setValue(path, ATTR_STATE, "TERMINATED"); } } -public class TraceJdiHooks implements JdiEventsListenerAdapter { +public class JdiHooks implements JdiEventsListenerAdapter { - private TraceJdiManager manager; - private TraceJdiCommands cmds; + private JdiManager manager; + private JdiCommands cmds; private HookState hookState; private Map vmStates = new HashMap<>(); - public TraceJdiHooks(TraceJdiManager manager) { + public JdiHooks(JdiManager manager, JdiCommands cmds) { this.manager = manager; - this.cmds = manager.getCommands(); + this.cmds = cmds; } - private void setCommands(TraceJdiCommands commands) { + private void setCommands(JdiCommands commands) { this.cmds = commands; hookState = new HookState(commands); } @@ -204,17 +197,19 @@ public class TraceJdiHooks implements JdiEventsListenerAdapter { @Override public DebugStatus vmStarted(VMStartEvent event, JdiCause cause) { setCommands(manager.getCommands()); - hookState.ensureBatch(); - RmiTrace trace = cmds.state.trace; JdiManagerImpl jdi = manager.getJdi(); VirtualMachine vm = event == null ? jdi.getCurrentVM() : event.virtualMachine(); - try (RmiTransaction tx = trace.openTx("New VM " + vm.description())) { - jdi.setCurrentVM(vm); - jdi.addVM(vm); + jdi.setCurrentVM(vm); + jdi.addVM(vm); + RmiTrace trace = cmds.state.trace; + if (trace == null) { + return DebugStatus.NO_CHANGE; + } + try (RmiBatch batch = hookState.batch(); + RmiTransaction tx = trace.openTx("New VM " + vm.description())) { cmds.putVMs(); enableCurrentVM(); } - hookState.endBatch(); return DebugStatus.NO_CHANGE; } @@ -417,12 +412,11 @@ public class TraceJdiHooks implements JdiEventsListenerAdapter { } VmState state = vmStates.get(vm); state.visited.clear(); - hookState.ensureBatch(); - try (RmiTransaction tx = trace.openTx("Stopped")) { + try (RmiBatch batch = hookState.batch(); + RmiTransaction tx = trace.openTx("Stopped")) { state.recordState("Stopped"); cmds.activate(null); } - hookState.endBatch(); } private void setCurrent(Event event) { @@ -446,12 +440,11 @@ public class TraceJdiHooks implements JdiEventsListenerAdapter { void onContinue() { VirtualMachine currentVM = manager.getJdi().getCurrentVM(); VmState state = vmStates.get(currentVM); - hookState.ensureBatch(); - try (RmiTransaction tx = cmds.state.trace.openTx("Continue")) { + try (RmiBatch batch = hookState.batch(); + RmiTransaction tx = cmds.state.trace.openTx("Continue")) { state.recordStateContinued(currentVM); cmds.activate(null); } - hookState.endBatch(); } public void installHooks() { diff --git a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/TraceJdiManager.java b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/JdiManager.java similarity index 57% rename from Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/TraceJdiManager.java rename to Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/JdiManager.java index eec55960f5..ce7ba8a173 100644 --- a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/TraceJdiManager.java +++ b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/JdiManager.java @@ -21,6 +21,7 @@ import java.util.Map; import com.sun.jdi.*; import ghidra.app.plugin.core.debug.client.tracermi.*; +import ghidra.app.plugin.core.debug.client.tracermi.RmiMethodRegistry.TraceMethod; import ghidra.dbg.jdi.manager.impl.DebugStatus; import ghidra.dbg.jdi.manager.impl.JdiManagerImpl; import ghidra.dbg.target.schema.EnumerableTargetObjectSchema; @@ -28,65 +29,87 @@ import ghidra.dbg.target.schema.TargetObjectSchema; import ghidra.program.model.address.*; import ghidra.util.Msg; -public class TraceJdiManager { +public class JdiManager { private static final int STATIC_METHOD_SEPARATION = 3; public static final long BLOCK_SIZE = 0x1000L; public static final long DEFAULT_SECTION = 0x0000L; - public static final String PREFIX_INVISIBLE = "_"; - public static final String DISPLAY_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "display"; - public static final String STATE_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "state"; - public static final String MODULE_NAME_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "module_name"; - public static final String ARCH_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "arch"; - public static final String DEBUGGER_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "debugger"; - public static final String OS_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "os"; - public static final String ENDIAN_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "endian"; - public static final String ACCESSIBLE_ATTRIBUTE_NAME = PREFIX_INVISIBLE + "accessible"; + public static final String ATTR_DISPLAY = "_display"; + public static final String ATTR_STATE = "_state"; + public static final String ATTR_MODULE_NAME = "_module_name"; + public static final String ATTR_ARCH = "_arch"; + public static final String ATTR_DEBUGGER = "_debugger"; + public static final String ATTR_OS = "_os"; + public static final String ATTR_ENDIAN = "_endian"; + public static final String ATTR_ACCESSIBLE = "_accessible"; + public static final String ATTR_ADDRESS = "Address"; + public static final String ATTR_ALIVE = "Alive"; + public static final String ATTR_CLASS = "Class"; + public static final String ATTR_COMMAND_LINE = "CommandLine"; + public static final String ATTR_COUNT = "Count"; + public static final String ATTR_ENABLED = "Enabled"; + public static final String ATTR_EXECUTABLE = "Executable"; + public static final String ATTR_EXIT_CODE = "ExitCode"; + public static final String ATTR_INDEX = "Index"; + public static final String ATTR_INSTANCE = "Instance"; + public static final String ATTR_LENGTH = "Length"; + public static final String ATTR_LINENO = "LineNo"; + public static final String ATTR_LOCATION = "Location"; + public static final String ATTR_NAME = "Name"; + public static final String ATTR_PC = "PC"; + public static final String ATTR_PLATFORM_ONLY = "PlatformOnly"; + public static final String ATTR_RANGE = "Range"; + public static final String ATTR_RANGE_CP = "RangeCP"; // Constant pool + public static final String ATTR_SIGNATURE = "Signature"; + public static final String ATTR_THREAD = "Thread"; + public static final String ATTR_TYPE = "Type"; + public static final String ATTR_VALUE = "Value"; + public static final String ATTR_EXCLUDE = "Exclude"; + public static final String ATTR_INCLUDE = "Include"; - private JdiManagerImpl manager; - private TraceJdiArch arch; - private TraceJdiHooks hooks; - private TraceJdiMethods methods; - private TraceJdiCommands commands; + private final JdiManagerImpl manager; + private final JdiArch arch; + private final JdiHooks hooks; + private final JdiMethods methods; + private final JdiCommands commands; - Map objectRegistry = new HashMap<>(); - Map reverseRegistry = new HashMap<>(); - RmiMethodRegistry remoteMethodRegistry = new RmiMethodRegistry(); - Map scopeRegistry = new HashMap<>(); + final Map objectRegistry = new HashMap<>(); + final Map reverseRegistry = new HashMap<>(); + final RmiMethodRegistry remoteMethodRegistry = new RmiMethodRegistry(); + final Map scopeRegistry = new HashMap<>(); protected final AddressSpace ram = new GenericAddressSpace("ram", 64, AddressSpace.TYPE_RAM, 0); - protected Long ramIndex = Long.valueOf(BLOCK_SIZE); + protected Long ramIndex = BLOCK_SIZE; protected final AddressSpace pool = new GenericAddressSpace("constantPool", 64, AddressSpace.TYPE_RAM, 0); - protected Long poolIndex = Long.valueOf(0x0L); - public AddressRangeImpl defaultRange; + protected Long poolIndex = 0x0L; + public final AddressRangeImpl defaultRange; - private Map addressRangeByMethod = new HashMap<>(); - private Map methodsByKey = new HashMap<>(); - private Map addressRangeByClass = new HashMap<>(); - private Map cpAddressRangeByClass = new HashMap<>(); + private final Map addressRangeByMethod = new HashMap<>(); + private final Map methodsByKey = new HashMap<>(); + private final Map addressRangeByClass = new HashMap<>(); + private final Map cpAddressRangeByClass = new HashMap<>(); - private Map returnStatusMap = new HashMap<>(); - TargetObjectSchema rootSchema; + private final Map returnStatusMap = new HashMap<>(); + final TargetObjectSchema rootSchema; - public TraceJdiManager(JdiManagerImpl manager, Map env) { + public JdiManager(JdiManagerImpl manager, Map env) { this(manager); commands.ghidraTraceConnect(env.get("GHIDRA_TRACE_RMI_ADDR")); commands.ghidraTraceStart(env.get("OPT_TARGET_CLASS")); } - // NB: Needed for testing - public TraceJdiManager(JdiManagerImpl manager) { + public JdiManager(JdiManagerImpl manager) { this.manager = manager; Address start = ram.getAddress(DEFAULT_SECTION); defaultRange = new AddressRangeImpl(start, start.add(BLOCK_SIZE - 1)); rootSchema = RmiClient.loadSchema("jdi_schema.xml", "Debugger"); - arch = new TraceJdiArch(); - commands = new TraceJdiCommands(this); // Must precede methods/hooks - methods = new TraceJdiMethods(this); - hooks = new TraceJdiHooks(this); + arch = new JdiArch(); + commands = new JdiCommands(this); // Must precede methods/hooks + methods = new JdiMethods(this, commands); + hooks = new JdiHooks(this, commands); hooks.installHooks(); } @@ -94,19 +117,19 @@ public class TraceJdiManager { return manager; } - public TraceJdiArch getArch() { + public JdiArch getArch() { return arch; } - public TraceJdiCommands getCommands() { + public JdiCommands getCommands() { return commands; } - public TraceJdiMethods getMethods() { + public JdiMethods getMethods() { return methods; } - public TraceJdiHooks getHooks() { + public JdiHooks getHooks() { return hooks; } @@ -114,12 +137,11 @@ public class TraceJdiManager { return commands.state.client; } - public void registerRemoteMethod(TraceJdiMethods methods, java.lang.reflect.Method m, - String name) { + public void registerRemoteMethod(JdiMethods methods, java.lang.reflect.Method m, String name) { String action = name; String display = name; String description = name; - RmiMethodRegistry.TraceMethod annot = m.getAnnotation(RmiMethodRegistry.TraceMethod.class); + TraceMethod annot = m.getAnnotation(TraceMethod.class); if (annot == null) { return; } @@ -134,6 +156,10 @@ public class TraceJdiManager { if (pcount < 1) { return; } + /** + * TODO: The return type should be reflected from the method; however, none of the parameter + * collection routines currently use the return type, so just use ANY for now. + */ TargetObjectSchema schema = EnumerableTargetObjectSchema.ANY; RmiRemoteMethod method = new RmiRemoteMethod(rootSchema.getContext(), name, action, display, description, schema, methods, m); @@ -152,27 +178,33 @@ public class TraceJdiManager { } public AddressRange putAddressRange(ReferenceType cls, AddressSet set) { - if (set.isEmpty()) { - addressRangeByClass.put(cls, defaultRange); - return defaultRange; + synchronized (addressRangeByClass) { + if (set.isEmpty()) { + addressRangeByClass.put(cls, defaultRange); + return defaultRange; + } + AddressRange range = new AddressRangeImpl(set.getMinAddress(), set.getMaxAddress()); + addressRangeByClass.put(cls, range); + return range; } - AddressRange range = new AddressRangeImpl(set.getMinAddress(), set.getMaxAddress()); - addressRangeByClass.put(cls, range); - return range; } public AddressRange getAddressRange(ReferenceType cls) { if (cls == null) { return defaultRange; } - return addressRangeByClass.get(cls); + synchronized (addressRangeByClass) { + return addressRangeByClass.get(cls); + } } public ReferenceType getReferenceTypeForAddress(Address address) { - for (ReferenceType ref : addressRangeByClass.keySet()) { - AddressRange range = addressRangeByClass.get(ref); - if (range.contains(address)) { - return ref; + synchronized (addressRangeByClass) { + for (ReferenceType ref : addressRangeByClass.keySet()) { + AddressRange range = addressRangeByClass.get(ref); + if (range.contains(address)) { + return ref; + } } } return null; @@ -182,19 +214,21 @@ public class TraceJdiManager { if (cls == null) { return defaultRange; } - AddressRange range = cpAddressRangeByClass.get(cls); - if (range == null) { - registerConstantPool(cls, sz); - range = cpAddressRangeByClass.get(cls); + synchronized (cpAddressRangeByClass) { + AddressRange range = cpAddressRangeByClass.get(cls); + if (range == null) { + registerConstantPool(cls, sz); + range = cpAddressRangeByClass.get(cls); + } + return range; } - return range; } public void registerConstantPool(ReferenceType declaringType, int sz) { - if (!cpAddressRangeByClass.containsKey(declaringType)) { - if (manager.getCurrentVM().canGetConstantPool()) { - long length = sz == 0 ? 2 : sz; - synchronized (cpAddressRangeByClass) { + synchronized (cpAddressRangeByClass) { + if (!cpAddressRangeByClass.containsKey(declaringType)) { + if (manager.getCurrentVM().canGetConstantPool()) { + long length = sz == 0 ? 2 : sz; Address start = pool.getAddress(poolIndex); AddressRangeImpl range = new AddressRangeImpl(start, start.add(length - 1)); @@ -208,10 +242,12 @@ public class TraceJdiManager { } public ReferenceType getReferenceTypeForPoolAddress(Address address) { - for (ReferenceType ref : cpAddressRangeByClass.keySet()) { - AddressRange range = cpAddressRangeByClass.get(ref); - if (range.contains(address)) { - return ref; + synchronized (cpAddressRangeByClass) { + for (ReferenceType ref : cpAddressRangeByClass.keySet()) { + AddressRange range = cpAddressRangeByClass.get(ref); + if (range.contains(address)) { + return ref; + } } } return null; @@ -221,21 +257,25 @@ public class TraceJdiManager { if (method == null) { return defaultRange; } - AddressRange range = addressRangeByMethod.get(methodToKey(method)); - if (range == null) { - return defaultRange; + synchronized (addressRangeByMethod) { + AddressRange range = addressRangeByMethod.get(methodToKey(method)); + if (range == null) { + return defaultRange; + } + return range; } - return range; } public Method getMethodForAddress(Address address) { - for (String methodName : addressRangeByMethod.keySet()) { - AddressRange range = addressRangeByMethod.get(methodName); - if (range.contains(address)) { - return methodsByKey.get(methodName); + synchronized (addressRangeByMethod) { + for (String methodName : addressRangeByMethod.keySet()) { + AddressRange range = addressRangeByMethod.get(methodName); + if (range.contains(address)) { + return methodsByKey.get(methodName); + } } + return null; } - return null; } public Address getAddressFromLocation(Location location) { @@ -364,5 +404,4 @@ public class TraceJdiManager { } } } - } diff --git a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/JdiMethods.java b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/JdiMethods.java new file mode 100644 index 0000000000..1ed7dabdfc --- /dev/null +++ b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/JdiMethods.java @@ -0,0 +1,1618 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.dbg.jdi.rmi.jpda; + +import static ghidra.dbg.jdi.rmi.jpda.JdiManager.*; + +import java.io.IOException; +import java.util.*; + +import com.sun.jdi.*; +import com.sun.jdi.request.*; + +import ghidra.app.plugin.core.debug.client.tracermi.*; +import ghidra.app.plugin.core.debug.client.tracermi.RmiMethodRegistry.TraceMethod; +import ghidra.dbg.target.TargetMethod.Param; +import ghidra.program.model.address.Address; +import ghidra.program.model.address.AddressRange; +import ghidra.rmi.trace.TraceRmi.MemoryState; +import ghidra.util.Msg; + +public class JdiMethods implements RmiMethods { + + private JdiManager manager; + private JdiCommands cmds; + + public JdiMethods(JdiManager manager, JdiCommands cmds) { + this.manager = manager; + this.cmds = cmds; + registerMethods(); + } + + public void registerMethods() { + Class cls = this.getClass(); + for (java.lang.reflect.Method m : cls.getMethods()) { + TraceMethod annot = m.getAnnotation(TraceMethod.class); + if (annot != null) { + manager.registerRemoteMethod(this, m, m.getName()); + } + } + } + + @TraceMethod(action = "refresh", display = "Refresh VM") + public void refresh_vm(@Param(schema = "VirtualMachine", name = "vm") RmiTraceObject obj) { + try (RmiTransaction tx = cmds.state.trace.openTx("RefreshVM")) { + String path = obj.getPath(); + VirtualMachine vm = (VirtualMachine) getObjectFromPath(path); + cmds.putVMDetails(path, vm); + } + } + + @TraceMethod(action = "refresh", display = "Refresh process") + public void refresh_process( + @Param(schema = "ProcessRef", name = "process") RmiTraceObject obj) { + try (RmiTransaction tx = cmds.state.trace.openTx("RefreshProcess")) { + String path = obj.getPath(); + Process proc = (Process) getObjectFromPath(path); + cmds.putProcessDetails(path, proc); + } + } + + @TraceMethod(action = "refresh", display = "Refresh thread groups") + public void refresh_thread_groups( + @Param( + schema = "ThreadGroupReferenceContainer", + name = "container") RmiTraceObject obj) { + try (RmiTransaction tx = cmds.state.trace.openTx("RefreshThreadGroups")) { + String path = obj.getPath(); + String ppath = cmds.getParentPath(path); + Object parent = getObjectFromPath(ppath); + if (parent instanceof VirtualMachine vm) { + cmds.putThreadGroupContainer(ppath, vm.topLevelThreadGroups()); + } + if (parent instanceof ThreadGroupReference group) { + cmds.putThreadGroupContainer(ppath, group.threadGroups()); + } + } + } + + @TraceMethod(action = "refresh", display = "Refresh thread group") + public void refresh_thread_group_proxy( + @Param(schema = "ThreadGroupReferenceProxy", name = "proxy") RmiTraceObject obj) { + try (RmiTransaction tx = cmds.state.trace.openTx("RefreshThreadGroup")) { + String path = obj.getPath(); + String ppath = cmds.getParentPath(path); + Object parent = getObjectFromPath(ppath); + if (parent instanceof ThreadGroupReference group) { + cmds.putThreadGroupReference(path, group.parent()); + } + if (parent instanceof ThreadReference ref) { + cmds.putThreadGroupReference(path, ref.threadGroup()); + } + } + } + + @TraceMethod(action = "refresh", display = "Refresh thread group") + public void refresh_thread_group( + @Param(schema = "ThreadGroupReference", name = "group") RmiTraceObject obj) { + try (RmiTransaction tx = cmds.state.trace.openTx("RefreshThreadGroup")) { + String path = obj.getPath(); + ThreadGroupReference ref = (ThreadGroupReference) getObjectFromPath(path); + cmds.putThreadGroupReferenceDetails(path, ref); + } + } + + @TraceMethod(action = "refresh", display = "Refresh threads") + public void refresh_threads( + @Param(schema = "ThreadContainer", name = "container") RmiTraceObject obj) { + try (RmiTransaction tx = cmds.state.trace.openTx("RefreshThreads")) { + String path = obj.getPath(); + String ppath = cmds.getParentPath(path); + VirtualMachine vm = (VirtualMachine) getObjectFromPath(ppath); + cmds.putThreadContainer(ppath, vm.allThreads(), false); + } + } + + @TraceMethod(action = "refresh", display = "Refresh threads") + public void refresh_threadrefs( + @Param(schema = "ThreadReferenceContainer", name = "container") RmiTraceObject obj) { + try (RmiTransaction tx = cmds.state.trace.openTx("RefreshThreads")) { + String path = obj.getPath(); + String ppath = cmds.getParentPath(path); + Object parent = getObjectFromPath(ppath); + if (parent instanceof ThreadGroupReference group && path.endsWith(".Threads")) { + cmds.putThreadContainer(ppath, group.threads(), true); + } + if (parent instanceof ObjectReference ref && !path.endsWith(".Threads")) { + try { + cmds.putThreadContainer(ppath, ref.waitingThreads(), true); + } + catch (IncompatibleThreadStateException e) { + // IGNORE + } + } + } + } + + @TraceMethod(action = "refresh", display = "Refresh thread") + public void refresh_thread(@Param(schema = "Thread", name = "thread") RmiTraceObject obj) { + try (RmiTransaction tx = cmds.state.trace.openTx("RefreshThread")) { + String path = obj.getPath(); + ThreadReference ref = (ThreadReference) getObjectFromPath(path); + cmds.putThreadReferenceDetails(path, ref); + } + } + + @TraceMethod(action = "refresh", display = "Refresh stack") + public void refresh_stack(@Param(schema = "Stack", name = "stack") RmiTraceObject obj) { + try (RmiTransaction tx = cmds.state.trace.openTx("RefreshStack")) { + cmds.ghidraTracePutFrames(); + } + } + + @TraceMethod(action = "refresh", display = "Refresh registers") + public void refresh_registers( + @Param(schema = "RegisterContainer", name = "container") RmiTraceObject obj) { + try (RmiTransaction tx = cmds.state.trace.openTx("RefreshRegisters")) { + cmds.ghidraTracePutFrames(); + } + } + + @TraceMethod(action = "refresh", display = "Refresh modules") + public void refresh_modules( + @Param(schema = "ModuleReferenceContainer", name = "container") RmiTraceObject obj) { + try (RmiTransaction tx = cmds.state.trace.openTx("RefreshModules")) { + cmds.putModuleReferenceContainer(); + } + } + + @TraceMethod(action = "refresh", display = "Refresh module") + public void refresh_module( + @Param(schema = "ModuleReference", name = "module") RmiTraceObject obj) { + try (RmiTransaction tx = cmds.state.trace.openTx("RefreshModule")) { + String path = obj.getPath(); + ModuleReference ref = (ModuleReference) getObjectFromPath(path); + cmds.putModuleReferenceDetails(path, ref); + } + } + + @TraceMethod(action = "refresh", display = "Refresh monitor info") + public void refresh_monitors( + @Param(schema = "MonitorInfoContainer", name = "container") RmiTraceObject obj) { + try (RmiTransaction tx = cmds.state.trace.openTx("RefreshMonitorInfo")) { + String path = obj.getPath(); + String ppath = cmds.getParentPath(path); + ThreadReference ref = (ThreadReference) getObjectFromPath(ppath); + cmds.putMonitorInfoContainer(path, ref.ownedMonitorsAndFrames()); + } + catch (IncompatibleThreadStateException e) { + // IGNORE + } + } + + @TraceMethod(action = "refresh", display = "Refresh monitor info") + public void refresh_monitor_info( + @Param(schema = "MonitorInfo", name = "monitor_info") RmiTraceObject obj) { + try (RmiTransaction tx = cmds.state.trace.openTx("RefreshMonitorInfo")) { + String path = obj.getPath(); + MonitorInfo mi = (MonitorInfo) getObjectFromPath(path); + cmds.putMonitorInfoDetails(path, mi); + } + } + + @TraceMethod(action = "refresh", display = "Refresh fields") + public void refresh_canonical_fields( + @Param(schema = "CanonicalFieldContainer", name = "container") RmiTraceObject obj) { + refresh_fields(obj); + } + + @TraceMethod(action = "refresh", display = "Refresh fields") + public void refresh_fields( + @Param(schema = "FieldContainer", name = "container") RmiTraceObject obj) { + try (RmiTransaction tx = cmds.state.trace.openTx("RefreshFields")) { + String path = obj.getPath(); + String ppath = cmds.getParentPath(path); + Object parent = getObjectFromPath(ppath); + if (parent instanceof ReferenceType refType) { + cmds.putFieldContainer(path, refType); + } + else if (parent instanceof ObjectReference ref) { + cmds.putVariableContainer(path, ref); + } + } + } + + @TraceMethod(action = "refresh", display = "Refresh objects") + public void refresh_objects( + @Param(schema = "ObjectReferenceContainer", name = "container") RmiTraceObject obj) { + try (RmiTransaction tx = cmds.state.trace.openTx("RefreshObjects")) { + String path = obj.getPath(); + String ppath = cmds.getParentPath(path); + Object parent = getObjectFromPath(ppath); + if (parent instanceof ReferenceType refType) { + cmds.putObjectContainer(path, refType.instances(cmds.MAX_REFS)); + } + if (parent instanceof ThreadReference thread) { + try { + if (path.endsWith("OwnedMonitors")) { + cmds.putObjectContainer(path, thread.ownedMonitors()); + } + } + catch (IncompatibleThreadStateException e) { + // IGNORE + } + } + if (parent instanceof ObjectReference ref && path.endsWith("ReferringObjects")) { + cmds.putObjectContainer(path, ref.referringObjects(cmds.MAX_REFS)); + } + } + } + + @TraceMethod(action = "refresh", display = "Refresh object") + public void refresh_object_proxy( + @Param(schema = "ObjectReferenceProxy", name = "proxy") RmiTraceObject obj) { + try (RmiTransaction tx = cmds.state.trace.openTx("RefreshObject")) { + String path = obj.getPath(); + String ppath = cmds.getParentPath(path); + Object parent = getObjectFromPath(ppath); + if (parent instanceof ThreadReference thread && + path.endsWith("CurrentContendedMonitor")) { + try { + cmds.putObjectReference(path, thread.currentContendedMonitor()); + } + catch (IncompatibleThreadStateException e) { + // IGNORE + } + } + if (parent instanceof StackFrame frame) { + cmds.putObjectReference(path, frame.thisObject()); + } + } + } + + @TraceMethod(action = "refresh", display = "Refresh object") + public void refresh_object( + @Param(schema = "ObjectReference", name = "object") RmiTraceObject obj) { + try (RmiTransaction tx = cmds.state.trace.openTx("RefreshInstance")) { + String path = obj.getPath(); + ObjectReference method = (ObjectReference) getObjectFromPath(path); + cmds.putObjectReferenceDetails(path, method); + } + } + + @TraceMethod(action = "refresh", display = "Refresh methods") + public void refresh_canonical_methods( + @Param(schema = "CanonicalMethodContainer", name = "container") RmiTraceObject obj) { + refresh_methods(obj); + } + + @TraceMethod(action = "refresh", display = "Refresh methods") + public void refresh_methods( + @Param(schema = "MethodContainer", name = "container") RmiTraceObject obj) { + try (RmiTransaction tx = cmds.state.trace.openTx("RefreshMethods")) { + String path = obj.getPath(); + String ppath = cmds.getParentPath(path); + ReferenceType refType = (ReferenceType) getObjectFromPath(ppath); + cmds.putMethodContainer(path, refType); + } + } + + @TraceMethod(action = "refresh", display = "Refresh method") + public void refresh_method(@Param(schema = "Method", name = "method") RmiTraceObject obj) { + try (RmiTransaction tx = cmds.state.trace.openTx("RefreshMethod")) { + String path = obj.getPath(); + Method method = (Method) getObjectFromPath(path); + cmds.putMethodDetails(path, method, false); + } + } + + @TraceMethod(action = "refresh", display = "Refresh arguments") + public void refresh_arguments( + @Param(schema = "ArgumentContainer", name = "container") RmiTraceObject obj) { + try (RmiTransaction tx = cmds.state.trace.openTx("RefreshArguments")) { + String path = obj.getPath(); + String ppath = cmds.getParentPath(path); + Method method = (Method) getObjectFromPath(ppath); + cmds.putMethodTypeContainer(path, method); + } + } + + @TraceMethod(display = "Load class") + public boolean find_class( + @Param( + schema = "ReferenceTypeContainer", + description = "Container", + display = "Container", + name = "container") RmiTraceObject obj, + @Param( + description = "Class to open", + display = "Class", + name = "find") String targetClass) { + try (RmiTransaction tx = cmds.state.trace.openTx("FindClass")) { + String path = obj.getPath(); + String ppath = cmds.getParentPath(path); + Object parent = getObjectFromPath(ppath); + if (parent instanceof VirtualMachine vm) { + return cmds.loadReferenceType(path, vm.allClasses(), targetClass); + } + return false; + } + } + + /** + * NB. Did not assign action="refresh" because this method is expensive. Assigning that action + * name will cause the UI to do it upon expanding the node, which we do not want. + */ + @TraceMethod(display = "Refresh memory") + public void refresh_memory(@Param(schema = "Memory", name = "memory") RmiTraceObject obj) { + refresh_reference_types(obj); + } + + @TraceMethod(display = "Refresh reference types") + public void refresh_canonical_reference_types( + @Param(schema = "CanonicalReferenceTypeContainer", name = "container") RmiTraceObject obj) { + refresh_reference_types(obj); + } + + /** + * NB. Did not assign action="refresh" because this method is expensive. Assigning that action + * name will cause the UI to do it upon expanding the node, which we do not want. + */ + @TraceMethod(display = "Refresh reference types") + public void refresh_reference_types( + @Param(schema = "ReferenceTypeContainer", name = "container") RmiTraceObject obj) { + try (RmiTransaction tx = cmds.state.trace.openTx("RefreshReferenceTypes")) { + String path = obj.getPath(); + String ppath = cmds.getParentPath(path); + Object parent = getObjectFromPath(ppath); + if (parent instanceof VirtualMachine vm) { + cmds.putReferenceTypeContainer(path, vm.allClasses()); + } + if (parent instanceof ClassLoaderReference ref) { + if (path.endsWith("DefinedClasses")) { + cmds.putReferenceTypeContainer(path, ref.definedClasses()); + } + if (path.endsWith("VisibleClasses")) { + cmds.putReferenceTypeContainer(path, ref.visibleClasses()); + } + } + if (parent instanceof ClassType ct) { + if (path.endsWith("AllInterfaces")) { + cmds.putInterfaceTypes(path, ct.allInterfaces()); + } + if (path.endsWith("Interfaces")) { + cmds.putInterfaceTypes(path, ct.interfaces()); + } + if (path.endsWith("SubClasses")) { + cmds.putClassTypes(path, ct.subclasses()); + } + } + if (parent instanceof InterfaceType it) { + if (path.endsWith("Implementors")) { + cmds.putClassTypes(path, it.implementors()); + } + if (path.endsWith("SubInterfaces")) { + cmds.putInterfaceTypes(path, it.subinterfaces()); + } + if (path.endsWith("SuperInterfaces")) { + cmds.putInterfaceTypes(path, it.superinterfaces()); + } + } + } + } + + @TraceMethod(action = "refresh", display = "Refresh reference type") + public void refresh_reference_type_proxy( + @Param(schema = "ReferenceTypeProxy", name = "proxy") RmiTraceObject obj) { + try (RmiTransaction tx = cmds.state.trace.openTx("RefreshReferenceType")) { + String path = obj.getPath(); + String ppath = cmds.getParentPath(path); + Object parent = getObjectFromPath(ppath); + if (parent instanceof ObjectReference ref) { + cmds.putReferenceType(path, ref.referenceType(), false); + } + if (parent instanceof ClassObjectReference ref && path.endsWith("ReflectedType")) { + cmds.putReferenceType(path, ref.reflectedType(), false); + } + if (parent instanceof ClassType ct) { + cmds.putReferenceType(path, ct.superclass(), false); + } + if (parent instanceof Method method) { + cmds.putReferenceType(path, method.declaringType(), false); + } + } + } + + @TraceMethod(action = "refresh", display = "Refresh reference type") + public void refresh_canonical_reference_type( + @Param(schema = "CanonicalReferenceType", name = "container") RmiTraceObject obj) { + refresh_reference_type(obj); + } + + @TraceMethod(action = "refresh", display = "Refresh reference type") + public void refresh_reference_type( + @Param(schema = "ReferenceType", name = "reference_type") RmiTraceObject obj) { + try (RmiTransaction tx = cmds.state.trace.openTx("RefreshReferenceType")) { + String path = obj.getPath(); + ReferenceType refType = (ReferenceType) getObjectFromPath(path); + cmds.putReferenceType(path, refType, false); + } + } + + @TraceMethod(display = "Load reference type") + public void load_reftype( + @Param(schema = "ReferenceType", name = "reference_type") RmiTraceObject obj) { + try (RmiTransaction tx = cmds.state.trace.openTx("RefreshReferenceType")) { + VirtualMachine vm = manager.getJdi().getCurrentVM(); + String path = obj.getPath(); + String mempath = cmds.getPath(vm) + ".Classes"; + ReferenceType refType = (ReferenceType) getObjectFromPath(path); + cmds.putReferenceType(mempath, refType, true); + } + } + + @TraceMethod(action = "refresh", display = "Refresh variables") + public void refresh_canonical_variables( + @Param(schema = "CanonicalVariableContainer", name = "container") RmiTraceObject obj) { + refresh_variables(obj); + } + + @TraceMethod(action = "refresh", display = "Refresh variables") + public void refresh_variables( + @Param(schema = "VariableContainer", name = "container") RmiTraceObject obj) { + try (RmiTransaction tx = cmds.state.trace.openTx("RefreshVariables")) { + String path = obj.getPath(); + String ppath = cmds.getParentPath(path); + Object parent = getObjectFromPath(ppath); + try { + if (parent instanceof Method method) { + if (path.endsWith("Arguments")) { + cmds.putLocalVariableContainer(path, method.arguments()); + } + if (path.endsWith("Variables")) { + cmds.putLocalVariableContainer(path, method.variables()); + } + } + if (parent instanceof StackFrame frame) { + Map map = frame.getValues(frame.visibleVariables()); + cmds.putLocalVariableContainer(path, map); + } + } + catch (AbsentInformationException e) { + // IGNORE + } + } + } + + @TraceMethod(action = "refresh", display = "Refresh variable") + public void refresh_variable( + @Param(schema = "Variable", name = "variable") RmiTraceObject obj) { + try (RmiTransaction tx = cmds.state.trace.openTx("RefreshVariable")) { + String path = obj.getPath(); + Object object = getObjectFromPath(path); + if (object instanceof LocalVariable var) { + cmds.putLocalVariableDetails(path, var); + } + } + } + + @TraceMethod(action = "refresh", display = "Refresh locations") + public void refresh_locations( + @Param(schema = "LocationContainer", name = "container") RmiTraceObject obj) { + try (RmiTransaction tx = cmds.state.trace.openTx("RefreshLocations")) { + String path = obj.getPath(); + String ppath = cmds.getParentPath(path); + Object parent = getObjectFromPath(ppath); + if (parent instanceof Method) { + Method method = (Method) parent; + cmds.putLocationContainer(path, method); + } + if (parent instanceof ReferenceType) { + ReferenceType ref = (ReferenceType) parent; + cmds.putLocationContainer(path, ref); + } + } + } + + @TraceMethod(action = "refresh", display = "Refresh location") + public void refresh_location( + @Param(schema = "Location", name = "location") RmiTraceObject obj) { + try (RmiTransaction tx = cmds.state.trace.openTx("RefreshLocation")) { + String path = obj.getPath(); + Location loc = (Location) getObjectFromPath(path); + cmds.putLocationDetails(path, loc); + } + } + + @TraceMethod(action = "refresh", display = "Refresh breakpoints") + public void refresh_breakpoints( + @Param(schema = "BreakpointContainer", name = "container") RmiTraceObject obj) { + try (RmiTransaction tx = cmds.state.trace.openTx("RefreshBreakpoints")) { + cmds.putBreakpoints(); + } + } + + @TraceMethod(action = "refresh", display = "Refresh events") + public void refresh_events( + @Param(schema = "EventContainer", name = "container") RmiTraceObject obj) { + try (RmiTransaction tx = cmds.state.trace.openTx("RefreshEvents")) { + cmds.putEvents(); + } + } + + @TraceMethod(action = "refresh", display = "Refresh values") + public void refresh_values( + @Param(schema = "ValueContainer", name = "container") RmiTraceObject obj) { + try (RmiTransaction tx = cmds.state.trace.openTx("RefreshValues")) { + String path = obj.getPath(); + String ppath = cmds.getParentPath(path); + Object parent = getObjectFromPath(ppath); + if (parent instanceof ArrayReference arr) { + cmds.putValueContainer(path, arr.getValues()); + } + } + } + + @TraceMethod(action = "refresh", display = "Refresh value") + public void refresh_value(@Param(schema = "Value", name = "value") RmiTraceObject obj) { + try (RmiTransaction tx = cmds.state.trace.openTx("RefreshLocation")) { + String path = obj.getPath(); + Value val = (Value) getObjectFromPath(path); + cmds.putValueDetailsByType(path, val); + } + } + + @TraceMethod(display = "Set value") + public void set_value_lvar( + @Param( + schema = "Variable", + description = "Variable", + display = "Variable", + name = "variable") RmiTraceObject obj, + @Param( + description = "Value", + display = "Value", + name = "value") String value) { + try (RmiTransaction tx = cmds.state.trace.openTx("RefreshLocation")) { + String path = obj.getPath(); + LocalVariable lvar = (LocalVariable) getObjectFromPath(path); + cmds.modifyValue(lvar, value); + } + } + + @TraceMethod(display = "Set value") + public void set_value_field( + @Param( + schema = "Field", + description = "Field", + display = "Field", + name = "field") RmiTraceObject obj, + @Param( + description = "Value", + display = "Value", + name = "value") String value) { + try (RmiTransaction tx = cmds.state.trace.openTx("RefreshLocation")) { + String path = obj.getPath(); + Field field = (Field) getObjectFromPath(path); + cmds.modifyValue(field, value); + } + } + + @TraceMethod(action = "activate", display = "Activate") + public void activate(@Param(schema = "OBJECT", name = "object") RmiTraceObject obj) { + try (RmiTransaction tx = cmds.state.trace.openTx("Activate")) { + String path = obj.getPath(); + cmds.activate(path); + } + } + + @TraceMethod(action = "kill", display = "Terminate") + public void kill(@Param(schema = "VirtualMachine", name = "vm") RmiTraceObject obj) { + VirtualMachine vm = (VirtualMachine) getObjectFromPath(obj.getPath()); + vm.exit(143); + try { + manager.getJdi().sendInterruptNow(); + } + catch (IOException e) { + e.printStackTrace(); + } + } + + @TraceMethod(action = "resume", display = "Resume") + public void resume_vm(@Param(schema = "VirtualMachine", name = "vm") RmiTraceObject obj) { + VirtualMachine vm = (VirtualMachine) getObjectFromPath(obj.getPath()); + vm.resume(); + manager.getHooks().setState(vm); + } + + @TraceMethod(action = "resume", display = "Resume") + public void resume_thread(@Param(schema = "Thread", name = "thread") RmiTraceObject obj) { + ThreadReference thread = (ThreadReference) getObjectFromPath(obj.getPath()); + thread.resume(); + manager.getHooks().setState(thread.virtualMachine()); + } + + @TraceMethod(action = "interrupt", display = "Suspend") + public void suspend_vm(@Param(schema = "VirtualMachine", name = "vm") RmiTraceObject obj) { + VirtualMachine vm = (VirtualMachine) getObjectFromPath(obj.getPath()); + vm.suspend(); + manager.getHooks().setState(vm); + } + + @TraceMethod(action = "interrupt", display = "Suspend") + public void suspend_thread(@Param(schema = "Thread", name = "thread") RmiTraceObject obj) { + ThreadReference thread = (ThreadReference) getObjectFromPath(obj.getPath()); + thread.suspend(); + manager.getHooks().setState(thread.virtualMachine()); + } + + /** + * NB: For the VirtualMachine, the step methods add requests for break-on-step for all threads. + * These requests will remain pending until the VM is resumed. + */ + @TraceMethod(action = "step_into", display = "Step into") + public void step_vm_into(@Param(schema = "VirtualMachine", name = "vm") RmiTraceObject obj) { + VirtualMachine vm = manager.getJdi().getCurrentVM(); + List threads = getThreadsFromValue(obj); + for (ThreadReference thread : threads) { + try { + StepRequest stepReq = vm.eventRequestManager() + .createStepRequest(thread, StepRequest.STEP_MIN, + StepRequest.STEP_INTO); + stepReq.enable(); + } + catch (DuplicateRequestException dre) { + // IGNORE + } + } + vm.resume(); + } + + @TraceMethod(action = "step_over", display = "Step over") + public void step_vm_over(@Param(schema = "VirtualMachine", name = "vm") RmiTraceObject obj) { + VirtualMachine vm = manager.getJdi().getCurrentVM(); + List threads = getThreadsFromValue(obj); + for (ThreadReference thread : threads) { + try { + StepRequest stepReq = vm.eventRequestManager() + .createStepRequest(thread, StepRequest.STEP_MIN, + StepRequest.STEP_OVER); + stepReq.enable(); + } + catch (DuplicateRequestException dre) { + // IGNORE + } + } + vm.resume(); + } + + @TraceMethod(action = "step_out", display = "Step out") + public void step_vm_out(@Param(schema = "VirtualMachine", name = "vm") RmiTraceObject obj) { + VirtualMachine vm = manager.getJdi().getCurrentVM(); + List threads = getThreadsFromValue(obj); + for (ThreadReference thread : threads) { + try { + StepRequest stepReq = vm.eventRequestManager() + .createStepRequest(thread, StepRequest.STEP_MIN, + StepRequest.STEP_OUT); + stepReq.enable(); + } + catch (DuplicateRequestException dre) { + // IGNORE + } + } + vm.resume(); + } + + @TraceMethod(action = "step_into", display = "Step into") + public void step_into(@Param(schema = "Thread", name = "thread") RmiTraceObject obj) { + VirtualMachine vm = manager.getJdi().getCurrentVM(); + ThreadReference thread = (ThreadReference) getObjectFromPath(obj.getPath()); + StepRequest stepReq = vm.eventRequestManager() + .createStepRequest(thread, StepRequest.STEP_MIN, + StepRequest.STEP_INTO); + stepReq.enable(); + vm.resume(); + } + + @TraceMethod(action = "step_over", display = "Step over") + public void step_over(@Param(schema = "Thread", name = "thread") RmiTraceObject obj) { + VirtualMachine vm = manager.getJdi().getCurrentVM(); + ThreadReference thread = (ThreadReference) getObjectFromPath(obj.getPath()); + StepRequest stepReq = vm.eventRequestManager() + .createStepRequest(thread, StepRequest.STEP_MIN, + StepRequest.STEP_OVER); + stepReq.enable(); + vm.resume(); + } + + @TraceMethod(action = "step_out", display = "Step out") + public void step_out(@Param(schema = "Thread", name = "thread") RmiTraceObject obj) { + VirtualMachine vm = manager.getJdi().getCurrentVM(); + ThreadReference thread = (ThreadReference) getObjectFromPath(obj.getPath()); + StepRequest stepReq = vm.eventRequestManager() + .createStepRequest(thread, StepRequest.STEP_MIN, + StepRequest.STEP_OUT); + stepReq.enable(); + vm.resume(); + } + + @TraceMethod(display = "Thread Interrupt") + public void thread_interrupt(@Param(schema = "Thread", name = "thread") RmiTraceObject obj) { + Object object = getObjectFromPath(obj.getPath()); + if (object instanceof ThreadReference thread) { + thread.interrupt(); + manager.getHooks().setState(thread.virtualMachine()); + } + } + + @TraceMethod(action = "step_ext", display = "Pop stack") + public void pop_stack(@Param(schema = "StackFrame", name = "frame") RmiTraceObject obj) { + StackFrame frame = (StackFrame) getObjectFromPath(obj.getPath()); + ThreadReference thread = frame.thread(); + try { + thread.popFrames(frame); + } + catch (IncompatibleThreadStateException e) { + Msg.out("Incompatible thread state for pop"); + } + } + + @TraceMethod(display = "Break on execute") + public void break_location(@Param(schema = "Location", name = "location") RmiTraceObject obj) { + VirtualMachine vm = manager.getJdi().getCurrentVM(); + Object ctxt = getObjectFromPath(obj.getPath()); + if (ctxt instanceof Location loc) { + BreakpointRequest brkReq = vm.eventRequestManager() + .createBreakpointRequest(loc); + brkReq.enable(); + cmds.putBreakpoints(); + } + } + + @TraceMethod(display = "Break on access") + public void break_access(@Param(schema = "Field", name = "field") RmiTraceObject obj) { + VirtualMachine vm = manager.getJdi().getCurrentVM(); + Object ctxt = getObjectFromPath(obj.getPath()); + if (ctxt instanceof Field field) { + AccessWatchpointRequest brkReq = vm.eventRequestManager() + .createAccessWatchpointRequest(field); + brkReq.enable(); + cmds.putBreakpoints(); + } + } + + @TraceMethod(display = "Break on modify") + public void break_modify(@Param(schema = "Field", name = "field") RmiTraceObject obj) { + VirtualMachine vm = manager.getJdi().getCurrentVM(); + Object ctxt = getObjectFromPath(obj.getPath()); + if (ctxt instanceof Field field) { + ModificationWatchpointRequest brkReq = vm.eventRequestManager() + .createModificationWatchpointRequest(field); + brkReq.enable(); + cmds.putBreakpoints(); + } + } + + @TraceMethod(display = "Break on exception") + public void break_exception( + @Param( + schema = "ReferenceType", + description = "Reference Type (Class)", + display = "Type", + name = "reference_type") RmiTraceObject obj, + @Param( + description = "Caught exceptions will be notified", + display = "NotifyCaught", + name = "notify_caught") boolean notifyCaught, + @Param( + description = "Uncaught exceptions will be notified", + display = "NotifyUncaught", + name = "notify_uncaught") boolean notifyUncaught) { + VirtualMachine vm = manager.getJdi().getCurrentVM(); + Object ctxt = getObjectFromPath(obj.getPath()); + if (ctxt instanceof ReferenceType reftype) { + ExceptionRequest excReq = vm.eventRequestManager() + .createExceptionRequest(reftype, notifyCaught, notifyUncaught); + excReq.enable(); + cmds.putEvents(); + } + } + + private void break_started(RmiTraceObject obj) { + VirtualMachine vm = manager.getJdi().getCurrentVM(); + ThreadStartRequest brkReq = vm.eventRequestManager() + .createThreadStartRequest(); + Object ctxt = getObjectFromPath(obj.getPath()); + if (ctxt instanceof ThreadReference ref) { + brkReq.putProperty("Thread", ref); + brkReq.addThreadFilter(ref); + } + brkReq.enable(); + cmds.putEvents(); + } + + @TraceMethod(display = "Break on thread start") + public void break_started_container( + @Param(schema = "EventContainer", name = "container") RmiTraceObject obj) { + break_started(obj); + } + + @TraceMethod(display = "Break on thread start") + public void break_started_thread( + @Param(schema = "Thread", name = "thread") RmiTraceObject obj) { + break_started(obj); + } + + private void break_death(RmiTraceObject obj) { + VirtualMachine vm = manager.getJdi().getCurrentVM(); + ThreadDeathRequest brkReq = vm.eventRequestManager() + .createThreadDeathRequest(); + Object ctxt = getObjectFromPath(obj.getPath()); + if (ctxt instanceof ThreadReference ref) { + brkReq.putProperty("Thread", ref); + brkReq.addThreadFilter(ref); + } + brkReq.enable(); + cmds.putEvents(); + } + + @TraceMethod(display = "Break on thread exit") + public void break_death_container( + @Param(schema = "EventContainer", name = "container") RmiTraceObject obj) { + break_death(obj); + } + + @TraceMethod(display = "Break on thread exit") + public void break_death_thread(@Param(schema = "Thread", name = "thread") RmiTraceObject obj) { + break_death(obj); + } + + @TraceMethod(display = "Break on VM death") + public void break_vm_death(@Param(schema = "VirtualMachine", name = "vm") RmiTraceObject obj) { + VirtualMachine vm = manager.getJdi().getCurrentVM(); + VMDeathRequest brkReq = vm.eventRequestManager() + .createVMDeathRequest(); + brkReq.enable(); + cmds.putEvents(); + } + + private void break_enter(RmiTraceObject obj) { + VirtualMachine vm = manager.getJdi().getCurrentVM(); + MethodEntryRequest brkReq = vm.eventRequestManager() + .createMethodEntryRequest(); + Object ctxt = getObjectFromPath(obj.getPath()); + if (ctxt instanceof ReferenceType reftype) { + brkReq.putProperty("Class", reftype); + brkReq.addClassFilter(reftype); + } + if (ctxt instanceof ObjectReference ref) { + brkReq.putProperty("Instance", ref); + brkReq.addInstanceFilter(ref); + } + if (ctxt instanceof ThreadReference ref) { + brkReq.putProperty("Thread", ref); + brkReq.addThreadFilter(ref); + } + brkReq.enable(); + cmds.putEvents(); + } + + @TraceMethod(display = "Break on method enter") + public void break_enter_container( + @Param(schema = "EventContainer", name = "container") RmiTraceObject obj) { + break_enter(obj); + } + + @TraceMethod(display = "Break on method enter") + public void break_enter_reftype( + @Param(schema = "ReferenceType", name = "class") RmiTraceObject obj) { + break_enter(obj); + } + + @TraceMethod(display = "Break on method enter") + public void break_enter_instance( + @Param(schema = "ObjectReference", name = "instance") RmiTraceObject obj) { + break_enter(obj); + } + + @TraceMethod(display = "Break on method enter") + public void break_enter_thread(@Param(schema = "Thread", name = "thread") RmiTraceObject obj) { + break_enter(obj); + } + + private void break_exit(RmiTraceObject obj) { + VirtualMachine vm = manager.getJdi().getCurrentVM(); + MethodExitRequest brkReq = vm.eventRequestManager() + .createMethodExitRequest(); + Object ctxt = getObjectFromPath(obj.getPath()); + if (ctxt instanceof ReferenceType reftype) { + brkReq.putProperty("Class", reftype); + brkReq.addClassFilter(reftype); + } + if (ctxt instanceof ObjectReference ref) { + brkReq.putProperty("Instance", ref); + brkReq.addInstanceFilter(ref); + } + if (ctxt instanceof ThreadReference ref) { + brkReq.putProperty("Thread", ref); + brkReq.addThreadFilter(ref); + } + brkReq.enable(); + cmds.putEvents(); + } + + @TraceMethod(display = "Break on method exit") + public void break_exit_container( + @Param(schema = "EventContainer", name = "container") RmiTraceObject obj) { + break_exit(obj); + } + + @TraceMethod(display = "Break on method exit") + public void break_exit_reftype( + @Param(schema = "ReferenceType", name = "class") RmiTraceObject obj) { + break_exit(obj); + } + + @TraceMethod(display = "Break on method exit") + public void break_exit_instance( + @Param(schema = "ObjectReference", name = "instance") RmiTraceObject obj) { + break_exit(obj); + } + + @TraceMethod(display = "Break on method exit") + public void break_exit_thread(@Param(schema = "Thread", name = "thread") RmiTraceObject obj) { + break_exit(obj); + } + + private void break_load(RmiTraceObject obj) { + VirtualMachine vm = manager.getJdi().getCurrentVM(); + ClassPrepareRequest brkReq = vm.eventRequestManager() + .createClassPrepareRequest(); + Object ctxt = getObjectFromPath(obj.getPath()); + if (ctxt instanceof ReferenceType reftype) { + brkReq.putProperty("Class", reftype); + brkReq.addClassFilter(reftype); + } + brkReq.enable(); + cmds.putEvents(); + } + + @TraceMethod(display = "Break on class load") + public void break_load_container( + @Param(schema = "EventContainer", name = "container") RmiTraceObject obj) { + break_load(obj); + } + + @TraceMethod(display = "Break on class load") + public void break_load_reftype( + @Param(schema = "ReferenceType", name = "class") RmiTraceObject obj) { + break_load(obj); + } + + private void break_unload(RmiTraceObject obj) { + VirtualMachine vm = manager.getJdi().getCurrentVM(); + ClassUnloadRequest brkReq = vm.eventRequestManager() + .createClassUnloadRequest(); + brkReq.enable(); + cmds.putEvents(); + } + + @TraceMethod(display = "Break on class unload") + public void break_unload_container( + @Param(schema = "EventContainer", name = "container") RmiTraceObject obj) { + break_unload(obj); + } + + private void break_mon_enter_contention(RmiTraceObject obj) { + VirtualMachine vm = manager.getJdi().getCurrentVM(); + MonitorContendedEnterRequest brkReq = vm.eventRequestManager() + .createMonitorContendedEnterRequest(); + Object ctxt = getObjectFromPath(obj.getPath()); + if (ctxt instanceof ReferenceType reftype) { + brkReq.putProperty("Class", reftype); + brkReq.addClassFilter(reftype); + } + if (ctxt instanceof ObjectReference ref) { + brkReq.putProperty("Instance", ref); + brkReq.addInstanceFilter(ref); + } + if (ctxt instanceof ThreadReference ref) { + brkReq.putProperty("Thread", ref); + brkReq.addThreadFilter(ref); + } + brkReq.enable(); + cmds.putEvents(); + } + + @TraceMethod(display = "Break on monitor contended enter") + public void break_mon_enter_contention_container( + @Param(schema = "EventContainer", name = "container") RmiTraceObject obj) { + break_mon_enter_contention(obj); + } + + @TraceMethod(display = "Break on monitor contended enter") + public void break_mon_enter_contention_reftype( + @Param(schema = "ReferenceType", name = "class") RmiTraceObject obj) { + break_mon_enter_contention(obj); + } + + @TraceMethod(display = "Break on monitor contended enter") + public void break_mon_enter_contention_instance( + @Param(schema = "ObjectReference", name = "instance") RmiTraceObject obj) { + break_mon_enter_contention(obj); + } + + @TraceMethod(display = "Break on monitor contended enter") + public void break_mon_enter_contention_thread( + @Param(schema = "Thread", name = "thread") RmiTraceObject obj) { + break_mon_enter_contention(obj); + } + + private void break_mon_entered_contention(RmiTraceObject obj) { + VirtualMachine vm = manager.getJdi().getCurrentVM(); + MonitorContendedEnteredRequest brkReq = vm.eventRequestManager() + .createMonitorContendedEnteredRequest(); + Object ctxt = getObjectFromPath(obj.getPath()); + if (ctxt instanceof ReferenceType reftype) { + brkReq.putProperty("Class", reftype); + brkReq.addClassFilter(reftype); + } + if (ctxt instanceof ObjectReference ref) { + brkReq.putProperty("Instance", ref); + brkReq.addInstanceFilter(ref); + } + if (ctxt instanceof ThreadReference ref) { + brkReq.putProperty("Thread", ref); + brkReq.addThreadFilter(ref); + } + brkReq.enable(); + cmds.putEvents(); + } + + @TraceMethod(display = "Break on monitor contented entered") + public void break_mon_entered_contention_container( + @Param(schema = "EventContainer", name = "container") RmiTraceObject obj) { + break_mon_entered_contention(obj); + } + + @TraceMethod(display = "Break on monitor contented entered") + public void break_mon_entered_contention_reftype( + @Param(schema = "ReferenceType", name = "class") RmiTraceObject obj) { + break_mon_entered_contention(obj); + } + + @TraceMethod(display = "Break on monitor contented entered") + public void break_mon_entered_contention_instance( + @Param(schema = "ObjectReference", name = "instance") RmiTraceObject obj) { + break_mon_entered_contention(obj); + } + + @TraceMethod(display = "Break on monitor contented entered") + public void break_mon_entered_contention_thread( + @Param(schema = "Thread", name = "thread") RmiTraceObject obj) { + break_mon_entered_contention(obj); + } + + private void break_mon_wait(RmiTraceObject obj) { + VirtualMachine vm = manager.getJdi().getCurrentVM(); + MonitorWaitRequest brkReq = vm.eventRequestManager() + .createMonitorWaitRequest(); + Object ctxt = getObjectFromPath(obj.getPath()); + if (ctxt instanceof ReferenceType reftype) { + brkReq.putProperty("Class", reftype); + brkReq.addClassFilter(reftype); + } + if (ctxt instanceof ObjectReference ref) { + brkReq.putProperty("Instance", ref); + brkReq.addInstanceFilter(ref); + } + if (ctxt instanceof ThreadReference ref) { + brkReq.putProperty("Thread", ref); + brkReq.addThreadFilter(ref); + } + brkReq.enable(); + cmds.putEvents(); + } + + @TraceMethod(display = "Break on monitor wait") + public void break_mon_wait_container( + @Param(schema = "EventContainer", name = "container") RmiTraceObject obj) { + break_mon_wait(obj); + } + + @TraceMethod(display = "Break on monitor wait") + public void break_mon_wait_reftype( + @Param(schema = "ReferenceType", name = "class") RmiTraceObject obj) { + break_mon_wait(obj); + } + + @TraceMethod(display = "Break on monitor wait") + public void break_mon_wait_instance( + @Param(schema = "ObjectReference", name = "instance") RmiTraceObject obj) { + break_mon_wait(obj); + } + + @TraceMethod(display = "Break on monitor wait") + public void break_mon_wait_thread( + @Param(schema = "Thread", name = "thread") RmiTraceObject obj) { + break_mon_wait(obj); + } + + private void break_mon_waited(RmiTraceObject obj) { + VirtualMachine vm = manager.getJdi().getCurrentVM(); + MonitorWaitedRequest brkReq = vm.eventRequestManager() + .createMonitorWaitedRequest(); + Object ctxt = getObjectFromPath(obj.getPath()); + if (ctxt instanceof ReferenceType reftype) { + brkReq.putProperty("Class", reftype); + brkReq.addClassFilter(reftype); + } + if (ctxt instanceof ObjectReference ref) { + brkReq.putProperty("Instance", ref); + brkReq.addInstanceFilter(ref); + } + if (ctxt instanceof ThreadReference ref) { + brkReq.putProperty("Thread", ref); + brkReq.addThreadFilter(ref); + } + brkReq.enable(); + cmds.putEvents(); + } + + @TraceMethod(display = "Break on monitor waited") + public void break_mon_waited_container( + @Param(schema = "EventContainer", name = "container") RmiTraceObject obj) { + break_mon_waited(obj); + } + + @TraceMethod(display = "Break on monitor waited") + public void break_mon_waited_reftype( + @Param(schema = "ReferenceType", name = "class") RmiTraceObject obj) { + break_mon_waited(obj); + } + + @TraceMethod(display = "Break on monitor waited") + public void break_mon_waited_instance( + @Param(schema = "ObjectReference", name = "instance") RmiTraceObject obj) { + break_mon_waited(obj); + } + + @TraceMethod(display = "Break on monitor waited") + public void break_mon_waited_thread( + @Param(schema = "Thread", name = "thread") RmiTraceObject obj) { + break_mon_waited(obj); + } + + @TraceMethod(display = "Add count filter") + public void add_count_filter( + @Param( + schema = "Event", + description = "Event", + display = "Event", + name = "event") RmiTraceObject obj, + @Param( + description = "Count", + display = "MaxCount", + name = "count") int count) { + Object ctxt = getObjectFromPath(obj.getPath()); + if (ctxt instanceof EventRequest req) { + req.disable(); + req.addCountFilter(count); + cmds.setValue(obj.getPath(), "Count", count); + req.enable(); + cmds.putEvents(); + } + } + + @TraceMethod(display = "Set class filter") + public void set_class_filter( + @Param( + schema = "Event", + description = "Event", + display = "Event", + name = "event") RmiTraceObject obj, + @Param( + description = "Filter Pattern", + display = "Filter", + name = "filter") String filter, + @Param( + description = "Exclude", + display = "Exclude", + name = "exclude") boolean exclude) { + Object ctxt = getObjectFromPath(obj.getPath()); + if (ctxt instanceof MethodEntryRequest req) { + req.disable(); + if (exclude) { + req.addClassExclusionFilter(filter); + cmds.setValue(obj.getPath(), ATTR_EXCLUDE, filter); + } + else { + req.addClassFilter(filter); + cmds.setValue(obj.getPath(), ATTR_INCLUDE, filter); + } + req.enable(); + } + if (ctxt instanceof MethodExitRequest req) { + req.disable(); + if (exclude) { + req.addClassExclusionFilter(filter); + cmds.setValue(obj.getPath(), ATTR_EXCLUDE, filter); + } + else { + req.addClassFilter(filter); + cmds.setValue(obj.getPath(), ATTR_INCLUDE, filter); + } + req.enable(); + } + if (ctxt instanceof ClassPrepareRequest req) { + req.disable(); + if (exclude) { + req.addClassExclusionFilter(filter); + cmds.setValue(obj.getPath(), ATTR_EXCLUDE, filter); + } + else { + req.addClassFilter(filter); + cmds.setValue(obj.getPath(), ATTR_INCLUDE, filter); + } + req.enable(); + } + if (ctxt instanceof ClassUnloadRequest req) { + req.disable(); + if (exclude) { + req.addClassExclusionFilter(filter); + cmds.setValue(obj.getPath(), ATTR_EXCLUDE, filter); + } + else { + req.addClassFilter(filter); + cmds.setValue(obj.getPath(), ATTR_INCLUDE, filter); + } + req.enable(); + } + if (ctxt instanceof MonitorContendedEnterRequest req) { + req.disable(); + if (exclude) { + req.addClassExclusionFilter(filter); + cmds.setValue(obj.getPath(), ATTR_EXCLUDE, filter); + } + else { + req.addClassFilter(filter); + cmds.setValue(obj.getPath(), ATTR_INCLUDE, filter); + } + req.enable(); + } + if (ctxt instanceof MonitorContendedEnteredRequest req) { + req.disable(); + if (exclude) { + req.addClassExclusionFilter(filter); + cmds.setValue(obj.getPath(), ATTR_EXCLUDE, filter); + } + else { + req.addClassFilter(filter); + cmds.setValue(obj.getPath(), ATTR_INCLUDE, filter); + } + req.enable(); + } + if (ctxt instanceof MonitorWaitRequest req) { + req.disable(); + if (exclude) { + req.addClassExclusionFilter(filter); + cmds.setValue(obj.getPath(), ATTR_EXCLUDE, filter); + } + else { + req.addClassFilter(filter); + cmds.setValue(obj.getPath(), ATTR_INCLUDE, filter); + } + req.enable(); + } + if (ctxt instanceof MonitorWaitedRequest req) { + req.disable(); + if (exclude) { + req.addClassExclusionFilter(filter); + cmds.setValue(obj.getPath(), ATTR_EXCLUDE, filter); + } + else { + req.addClassFilter(filter); + cmds.setValue(obj.getPath(), ATTR_INCLUDE, filter); + } + req.enable(); + } + cmds.putEvents(); + } + + @TraceMethod(display = "Set source filter") + public void set_source_filter( + @Param( + schema = "Event", + description = "Event", + display = "Event", + name = "event") RmiTraceObject obj, + @Param( + description = "Source Name Pattern", + display = "SourceName", + name = "source_name") String srcname) { + Object ctxt = getObjectFromPath(obj.getPath()); + if (ctxt instanceof ClassPrepareRequest req) { + req.disable(); + req.addSourceNameFilter(srcname); + cmds.setValue(obj.getPath(), "SourceMatches", srcname); + req.enable(); + } + cmds.putEvents(); + } + + @TraceMethod(display = "Set platform filter") + public void set_platform_filter(@Param(schema = "Event", name = "event") RmiTraceObject obj) { + Object ctxt = getObjectFromPath(obj.getPath()); + if (ctxt instanceof ThreadStartRequest req) { + req.disable(); + req.addPlatformThreadsOnlyFilter(); + cmds.setValue(obj.getPath(), ATTR_PLATFORM_ONLY, true); + req.enable(); + } + if (ctxt instanceof ThreadDeathRequest req) { + req.disable(); + req.addPlatformThreadsOnlyFilter(); + cmds.setValue(obj.getPath(), ATTR_PLATFORM_ONLY, true); + req.enable(); + } + cmds.putEvents(); + } + + @TraceMethod(action = "toggle", display = "Toggle breakpoint") + public void toggle_breakpoint( + @Param(schema = "BreakpointSpec", name = "breakpoint") RmiTraceObject obj) { + VirtualMachine vm = manager.getJdi().getCurrentVM(); + Object ctxt = getObjectFromPath(obj.getPath()); + if (ctxt instanceof Field field) { + ModificationWatchpointRequest brkReq = vm.eventRequestManager() + .createModificationWatchpointRequest(field); + brkReq.enable(); + } + if (ctxt instanceof EventRequest req) { + if (req.isEnabled()) { + req.disable(); + } + else { + req.enable(); + } + } + cmds.putBreakpoints(); + } + + @TraceMethod(action = "delete", display = "Delete breakpoint") + public void delete_breakpoint( + @Param(schema = "BreakpointSpec", name = "breakpoint") RmiTraceObject obj) { + VirtualMachine vm = manager.getJdi().getCurrentVM(); + Object ctxt = getObjectFromPath(obj.getPath()); + if (ctxt instanceof EventRequest req) { + vm.eventRequestManager().deleteEventRequest(req); + } + cmds.putBreakpoints(); + } + + @TraceMethod(action = "toggle", display = "Toggle event") + public void toggle_event(@Param(schema = "Event", name = "event") RmiTraceObject obj) { + Object ctxt = getObjectFromPath(obj.getPath()); + if (ctxt instanceof EventRequest req) { + if (req.isEnabled()) { + req.disable(); + } + else { + req.enable(); + } + cmds.putEvents(); + } + } + + @TraceMethod(action = "delete", display = "Delete Event") + public void delete_event(@Param(schema = "Event", name = "event") RmiTraceObject obj) { + VirtualMachine vm = manager.getJdi().getCurrentVM(); + Object ctxt = getObjectFromPath(obj.getPath()); + if (ctxt instanceof EventRequest req) { + vm.eventRequestManager().deleteEventRequest(req); + } + cmds.putEvents(); + } + + @TraceMethod(action = "toggle", display = "Toggle scope") + public void toggle_scope_methods( + @Param(schema = "MethodContainer", name = "container") RmiTraceObject obj) { + String ppath = cmds.getParentPath(obj.getPath()); + Object parent = getObjectFromPath(ppath); + manager.toggleScope(parent); + refresh_methods(obj); + } + + @TraceMethod(action = "toggle", display = "Toggle scope") + public void toggle_scope_fields( + @Param(schema = "FieldContainer", name = "container") RmiTraceObject obj) { + String ppath = cmds.getParentPath(obj.getPath()); + Object parent = getObjectFromPath(ppath); + manager.toggleScope(parent); + if (obj.getPath().endsWith("Fields")) { + refresh_fields(obj); + } + if (obj.getPath().endsWith("Variables")) { + refresh_fields(obj); + } + } + + @TraceMethod(action = "read_mem", display = "Read Memory") + public long read_mem( + @Param( + schema = "VirtualMachine", + description = "VirtualMachine", + display = "VirtualMachine", + name = "vm") RmiTraceObject obj, + @Param( + description = "Range", + display = "Range", + name = "range") AddressRange range) { + VirtualMachine vm = manager.getJdi().getCurrentVM(); + MemoryMapper mapper = cmds.state.trace.memoryMapper; + Address start = mapper.mapBack(range.getMinAddress()); + try (RmiTransaction tx = cmds.state.trace.openTx("ReadMemory")) { + cmds.putMem(start, range.getLength(), true); + cmds.putMemState(start, range.getLength(), MemoryState.MS_KNOWN, true); + } + catch (Exception e) { + cmds.putMemState(start, range.getLength(), MemoryState.MS_ERROR, true); + } + return range.getLength(); + } + + @TraceMethod(display = "Invoke method (no args)") + public void execute_on_instance( + @Param( + schema = "ObjectReference", + description = "Object Reference", + display = "Object", + name = "object") RmiTraceObject obj, + @Param( + description = "Thread Name", + display = "ThreadName", + name = "thread_name") String threadName, + @Param( + description = "Method Name", + display = "MethodName", + name = "method_name") String methodName) { + VirtualMachine vm = manager.getJdi().getCurrentVM(); + ObjectReference ref = (ObjectReference) getObjectFromPath(obj.getPath()); + List methods = ref.referenceType().methodsByName(methodName); + if (methods.size() > 1) { + Msg.warn(this, "Method " + methodName + " is not unique - using first variant"); + } + for (ThreadReference thread : vm.allThreads()) { + if (thread.name().equals(threadName)) { + cmds.execute(ref, thread, methods.get(0), new ArrayList(), 0); + } + } + } + + @TraceMethod(display = "Invoke static method (no args)") + public void execute_on_class( + @Param( + schema = "ReferenceType", + description = "Class", + display = "Class", + name = "class") RmiTraceObject obj, + @Param( + description = "Thread Name", + display = "ThreadName", + name = "thread_name") String threadName, + @Param( + description = "Method Name", + display = "MethodName", + name = "method_name") String methodName) { + VirtualMachine vm = manager.getJdi().getCurrentVM(); + ReferenceType reftype = (ReferenceType) getObjectFromPath(obj.getPath()); + if (reftype instanceof ClassType cls) { + List methods = cls.methodsByName(methodName); + if (methods.size() > 1) { + Msg.warn(this, "Method " + methodName + " is not unique - using first variant"); + } + if (!methods.get(0).isStatic()) { + Msg.error(this, "Method " + methodName + " is not static"); + return; + } + for (ThreadReference thread : vm.allThreads()) { + if (thread.name().equals(threadName)) { + cmds.execute(cls, thread, methods.get(0), new ArrayList(), 0); + } + } + } + } + + @TraceMethod(display = "Invoke method (no args)") + public void execute_method( + @Param( + schema = "Method", + description = "Method", + display = "Method", + name = "method") RmiTraceObject obj, + @Param( + description = "Instance Pattern", + display = "InstancePattern", + name = "instance_pattern") String instancePattern, + @Param( + description = "Thread Name", + display = "ThreadName", + name = "thread_name") String threadName) { + VirtualMachine vm = manager.getJdi().getCurrentVM(); + String path = obj.getPath(); + Method method = (Method) getObjectFromPath(path); + ReferenceType declaringType = method.declaringType(); + List instances = declaringType.instances(0); + for (ObjectReference ref : instances) { + if (ref.toString().contains(instancePattern)) { + for (ThreadReference thread : vm.allThreads()) { + if (thread.name().equals(threadName)) { + cmds.execute(ref, thread, method, new ArrayList(), 0); + } + } + } + } + } + + @TraceMethod(display = "Invoke static method (no args)") + public void execute_static_method( + @Param( + schema = "Method", + description = "Method", + display = "Method", + name = "method") RmiTraceObject obj, + @Param( + description = "Thread Name", + display = "ThreadName", + name = "thread_name") String threadName) { + VirtualMachine vm = manager.getJdi().getCurrentVM(); + String path = obj.getPath(); + Method method = (Method) getObjectFromPath(path); + if (!method.isStatic()) { + Msg.error(this, "Method " + method.name() + " is not static"); + return; + } + ReferenceType reftype = method.declaringType(); + if (reftype instanceof ClassType ct) { + for (ThreadReference thread : vm.allThreads()) { + if (thread.name().equals(threadName)) { + cmds.execute(ct, thread, method, new ArrayList(), 0); + } + } + } + } + + private List getThreadsFromValue(RmiTraceObject obj) { + Object object = getObjectFromPath(obj.getPath()); + if (object instanceof VirtualMachine vm) { + return vm.allThreads(); + } + List threads = new ArrayList<>(); + if (object instanceof ThreadReference thread) { + threads.add(thread); + } + else { + threads.add(manager.getJdi().getCurrentThread()); + } + return threads; + } + + private Object getObjectFromPath(String path) { + return manager.objForPath(path); + } + +} diff --git a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/TraceJdiMethods.java b/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/TraceJdiMethods.java deleted file mode 100644 index fcf597c7e8..0000000000 --- a/Ghidra/Debug/Debugger-jpda/src/main/java/ghidra/dbg/jdi/rmi/jpda/TraceJdiMethods.java +++ /dev/null @@ -1,1306 +0,0 @@ -/* ### - * IP: GHIDRA - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ghidra.dbg.jdi.rmi.jpda; - -import java.io.IOException; -import java.util.*; - -import com.sun.jdi.*; -import com.sun.jdi.request.*; - -import ghidra.app.plugin.core.debug.client.tracermi.*; -import ghidra.dbg.target.TargetMethod; -import ghidra.program.model.address.Address; -import ghidra.program.model.address.AddressRange; -import ghidra.rmi.trace.TraceRmi.MemoryState; -import ghidra.util.Msg; - -public class TraceJdiMethods implements RmiMethods { - - private TraceJdiManager manager; - private TraceJdiCommands cmds; - - public TraceJdiMethods(TraceJdiManager manager) { - this.manager = manager; - this.cmds = manager.getCommands(); - registerMethods(); - } - - public void registerMethods() { - Class cls = this.getClass(); - for (java.lang.reflect.Method m : cls.getMethods()) { - RmiMethodRegistry.TraceMethod annot = - m.getAnnotation(RmiMethodRegistry.TraceMethod.class); - if (annot != null) { - manager.registerRemoteMethod(this, m, m.getName()); - } - } - } - -// public void execute(String cmd) { -// -// } - -// public void refresh_available(Object obj) { -// -// } - - @RmiMethodRegistry.TraceMethod(action = "refresh", display = "Refresh VM", schema = "VirtualMachine") - public void refresh_vm(RmiTraceObject obj) { - try (RmiTransaction tx = cmds.state.trace.openTx("RefreshVM")) { - String path = obj.getPath(); - VirtualMachine vm = (VirtualMachine) getObjectFromPath(path); - cmds.putVMDetails(path, vm); - } - } - - @RmiMethodRegistry.TraceMethod(action = "refresh", display = "Refresh process", schema = "ProcessRef") - public void refresh_process(RmiTraceObject obj) { - try (RmiTransaction tx = cmds.state.trace.openTx("RefreshProcess")) { - String path = obj.getPath(); - Process proc = (Process) getObjectFromPath(path); - cmds.putProcessDetails(path, proc); - } - } - - @RmiMethodRegistry.TraceMethod(action = "refresh", display = "Refresh thread groups", schema = "ThreadGroupReferenceContainer") - public void refresh_thread_groups(RmiTraceObject obj) { - try (RmiTransaction tx = cmds.state.trace.openTx("RefreshThreadGroups")) { - String path = obj.getPath(); - String ppath = cmds.getParentPath(path); - Object parent = getObjectFromPath(ppath); - if (parent instanceof VirtualMachine vm) { - cmds.putThreadGroupContainer(ppath, vm.topLevelThreadGroups()); - } - if (parent instanceof ThreadGroupReference group) { - cmds.putThreadGroupContainer(ppath, group.threadGroups()); - } - } - } - - @RmiMethodRegistry.TraceMethod(action = "refresh", display = "Refresh thread group", schema = "ThreadGroupReferenceProxy") - public void refresh_thread_group_proxy(RmiTraceObject obj) { - try (RmiTransaction tx = cmds.state.trace.openTx("RefreshThreadGroup")) { - String path = obj.getPath(); - String ppath = cmds.getParentPath(path); - Object parent = getObjectFromPath(ppath); - if (parent instanceof ThreadGroupReference group) { - cmds.putThreadGroupReference(path, group.parent()); - } - if (parent instanceof ThreadReference ref) { - cmds.putThreadGroupReference(path, ref.threadGroup()); - } - } - } - - @RmiMethodRegistry.TraceMethod(action = "refresh", display = "Refresh thread group", schema = "ThreadGroupReference") - public void refresh_thread_group(RmiTraceObject obj) { - try (RmiTransaction tx = cmds.state.trace.openTx("RefreshThreadGroup")) { - String path = obj.getPath(); - ThreadGroupReference ref = (ThreadGroupReference) getObjectFromPath(path); - cmds.putThreadGroupReferenceDetails(path, ref); - } - } - - @RmiMethodRegistry.TraceMethod(action = "refresh", display = "Refresh threads", schema = "ThreadContainer") - public void refresh_threads(RmiTraceObject obj) { - try (RmiTransaction tx = cmds.state.trace.openTx("RefreshThreads")) { - String path = obj.getPath(); - String ppath = cmds.getParentPath(path); - VirtualMachine vm = (VirtualMachine) getObjectFromPath(ppath); - cmds.putThreadContainer(ppath, vm.allThreads(), false); - } - } - - @RmiMethodRegistry.TraceMethod(action = "refresh", display = "Refresh threads", schema = "ThreadReferenceContainer") - public void refresh_threadrefs(RmiTraceObject obj) { - try (RmiTransaction tx = cmds.state.trace.openTx("RefreshThreads")) { - String path = obj.getPath(); - String ppath = cmds.getParentPath(path); - Object parent = getObjectFromPath(ppath); - if (parent instanceof ThreadGroupReference group && path.endsWith(".Threads")) { - cmds.putThreadContainer(ppath, group.threads(), true); - } - if (parent instanceof ObjectReference ref && !path.endsWith(".Threads")) { - try { - cmds.putThreadContainer(ppath, ref.waitingThreads(), true); - } - catch (IncompatibleThreadStateException e) { - // IGNORE - } - } - } - } - - @RmiMethodRegistry.TraceMethod(action = "refresh", display = "Refresh Thread", schema = "Thread") - public void refresh_thread(RmiTraceObject obj) { - try (RmiTransaction tx = cmds.state.trace.openTx("RefreshThread")) { - String path = obj.getPath(); - ThreadReference ref = (ThreadReference) getObjectFromPath(path); - cmds.putThreadReferenceDetails(path, ref); - } - } - - @RmiMethodRegistry.TraceMethod(action = "refresh", display = "Refresh Stack", schema = "Stack") - public void refresh_stack(RmiTraceObject obj) { - try (RmiTransaction tx = cmds.state.trace.openTx("RefreshStack")) { - cmds.ghidraTracePutFrames(); - } - } - - @RmiMethodRegistry.TraceMethod(action = "refresh", display = "Refresh registers", schema = "RegisterContainer") - public void refresh_registers(RmiTraceObject obj) { - try (RmiTransaction tx = cmds.state.trace.openTx("RefreshRegisters")) { - cmds.ghidraTracePutFrames(); - } - } - - @RmiMethodRegistry.TraceMethod(action = "refresh", display = "Refresh modules", schema = "ModuleReferenceContainer") - public void refresh_modules(RmiTraceObject obj) { - try (RmiTransaction tx = cmds.state.trace.openTx("RefreshModules")) { - cmds.putModuleReferenceContainer(); - } - } - - @RmiMethodRegistry.TraceMethod(action = "refresh", display = "Refresh module", schema = "ModuleReference") - public void refresh_module(RmiTraceObject obj) { - try (RmiTransaction tx = cmds.state.trace.openTx("RefreshModule")) { - String path = obj.getPath(); - ModuleReference ref = (ModuleReference) getObjectFromPath(path); - cmds.putModuleReferenceDetails(path, ref); - } - } - - @RmiMethodRegistry.TraceMethod(action = "refresh", display = "Refresh monitor info", schema = "MonitorInfoContainer") - public void refresh_monitors(RmiTraceObject obj) { - try (RmiTransaction tx = cmds.state.trace.openTx("RefreshMonitorInfo")) { - String path = obj.getPath(); - String ppath = cmds.getParentPath(path); - ThreadReference ref = (ThreadReference) getObjectFromPath(ppath); - cmds.putMonitorInfoContainer(path, ref.ownedMonitorsAndFrames()); - } - catch (IncompatibleThreadStateException e) { - // IGNORE - } - } - - @RmiMethodRegistry.TraceMethod(action = "refresh", display = "Refresh monitor info", schema = "MonitorInfo") - public void refresh_monitor_info(RmiTraceObject obj) { - try (RmiTransaction tx = cmds.state.trace.openTx("RefreshMonitorInfo")) { - String path = obj.getPath(); - MonitorInfo mi = (MonitorInfo) getObjectFromPath(path); - cmds.putMonitorInfoDetails(path, mi); - } - } - - @RmiMethodRegistry.TraceMethod(action = "refresh", display = "Refresh fields", schema = "FieldContainer") - public void refresh_fields(RmiTraceObject obj) { - try (RmiTransaction tx = cmds.state.trace.openTx("RefreshFields")) { - String path = obj.getPath(); - String ppath = cmds.getParentPath(path); - Object parent = getObjectFromPath(ppath); - if (parent instanceof ReferenceType refType) { - cmds.putFieldContainer(path, refType); - } - else if (parent instanceof ObjectReference ref) { - cmds.putVariableContainer(path, ref); - } - } - } - -// @RmiMethodRegistry.method(action = "refresh", display = "Refresh Field", schema = "Field") -// public void refresh_field(RmiTraceObject obj) { -// try (RmiTransaction tx = cmds.state.trace.openTx("RefreshField")) { -// String path = obj.getPath(); -// Field field = (Field) getObjectFromPath(path); -// cmds.putFieldDetails(path, field); -// } -// } - - @RmiMethodRegistry.TraceMethod(action = "refresh", display = "Refresh objects", schema = "ObjectReferenceContainer") - public void refresh_objects(RmiTraceObject obj) { - try (RmiTransaction tx = cmds.state.trace.openTx("RefreshObjects")) { - String path = obj.getPath(); - String ppath = cmds.getParentPath(path); - Object parent = getObjectFromPath(ppath); - if (parent instanceof ReferenceType refType) { - cmds.putObjectContainer(path, refType.instances(cmds.MAX_REFS)); - } - if (parent instanceof ThreadReference thread) { - try { - if (path.endsWith("OwnedMonitors")) { - cmds.putObjectContainer(path, thread.ownedMonitors()); - } - } - catch (IncompatibleThreadStateException e) { - // IGNORE - } - } - if (parent instanceof ObjectReference ref && path.endsWith("ReferringObjects")) { - cmds.putObjectContainer(path, ref.referringObjects(cmds.MAX_REFS)); - } - } - } - - @RmiMethodRegistry.TraceMethod(action = "refresh", display = "Refresh object", schema = "ObjectReferenceProxy") - public void refresh_object_proxy(RmiTraceObject obj) { - try (RmiTransaction tx = cmds.state.trace.openTx("RefreshObject")) { - String path = obj.getPath(); - String ppath = cmds.getParentPath(path); - Object parent = getObjectFromPath(ppath); - if (parent instanceof ThreadReference thread && - path.endsWith("CurrentContendedMonitor")) { - try { - cmds.putObjectReference(path, thread.currentContendedMonitor()); - } - catch (IncompatibleThreadStateException e) { - // IGNORE - } - } - if (parent instanceof StackFrame frame) { - cmds.putObjectReference(path, frame.thisObject()); - } - } - } - - @RmiMethodRegistry.TraceMethod(action = "refresh", display = "Refresh object", schema = "ObjectReference") - public void refresh_object(RmiTraceObject obj) { - try (RmiTransaction tx = cmds.state.trace.openTx("RefreshInstance")) { - String path = obj.getPath(); - ObjectReference method = (ObjectReference) getObjectFromPath(path); - cmds.putObjectReferenceDetails(path, method); - } - } - - @RmiMethodRegistry.TraceMethod(action = "refresh", display = "Refresh methods", schema = "MethodContainer") - public void refresh_methods(RmiTraceObject obj) { - try (RmiTransaction tx = cmds.state.trace.openTx("RefreshMethods")) { - String path = obj.getPath(); - String ppath = cmds.getParentPath(path); - ReferenceType refType = (ReferenceType) getObjectFromPath(ppath); - cmds.putMethodContainer(path, refType); - } - } - - @RmiMethodRegistry.TraceMethod(action = "refresh", display = "Refresh method", schema = "Method") - public void refresh_method(RmiTraceObject obj) { - try (RmiTransaction tx = cmds.state.trace.openTx("RefreshMethod")) { - String path = obj.getPath(); - Method method = (Method) getObjectFromPath(path); - cmds.putMethodDetails(path, method, false); - } - } - - @RmiMethodRegistry.TraceMethod(action = "refresh", display = "Refresh arguments", schema = "ArgumentContainer") - public void refresh_arguments(RmiTraceObject obj) { - try (RmiTransaction tx = cmds.state.trace.openTx("RefreshArguments")) { - String path = obj.getPath(); - String ppath = cmds.getParentPath(path); - Method method = (Method) getObjectFromPath(ppath); - cmds.putMethodTypeContainer(path, method); - } - } - - @RmiMethodRegistry.TraceMethod(action = "load_class", display = "Load class", schema = "ReferenceTypeContainer") - public void find_class(RmiTraceObject obj, - @TargetMethod.Param(description = "Class to open", display = "Class", name = "find") String targetClass) { - try (RmiTransaction tx = cmds.state.trace.openTx("FindClass")) { - String path = obj.getPath(); - String ppath = cmds.getParentPath(path); - Object parent = getObjectFromPath(ppath); - if (parent instanceof VirtualMachine vm) { - cmds.loadReferenceType(path, vm.allClasses(), targetClass); - } - } - } - - @RmiMethodRegistry.TraceMethod(action = "refresh_memory", display = "Refresh memory", schema = "Memory") - public void refresh_memory(RmiTraceObject obj) { - refresh_reference_types(obj); - } - - @RmiMethodRegistry.TraceMethod(action = "refresh_types", display = "Refresh reference types", schema = "ReferenceTypeContainer") - public void refresh_reference_types(RmiTraceObject obj) { - try (RmiTransaction tx = cmds.state.trace.openTx("RefreshReferenceTypes")) { - String path = obj.getPath(); - String ppath = cmds.getParentPath(path); - Object parent = getObjectFromPath(ppath); - if (parent instanceof VirtualMachine vm) { - cmds.putReferenceTypeContainer(path, vm.allClasses()); - } - if (parent instanceof ClassLoaderReference ref) { - if (path.endsWith("DefinedClasses")) { - cmds.putReferenceTypeContainer(path, ref.definedClasses()); - } - if (path.endsWith("VisibleClasses")) { - cmds.putReferenceTypeContainer(path, ref.visibleClasses()); - } - } - if (parent instanceof ClassType ct) { - if (path.endsWith("AllInterfaces")) { - cmds.putInterfaceTypes(path, ct.allInterfaces()); - } - if (path.endsWith("Interfaces")) { - cmds.putInterfaceTypes(path, ct.interfaces()); - } - if (path.endsWith("SubClasses")) { - cmds.putClassTypes(path, ct.subclasses()); - } - } - if (parent instanceof InterfaceType it) { - if (path.endsWith("Implementors")) { - cmds.putClassTypes(path, it.implementors()); - } - if (path.endsWith("SubInterfaces")) { - cmds.putInterfaceTypes(path, it.subinterfaces()); - } - if (path.endsWith("SuperInterfaces")) { - cmds.putInterfaceTypes(path, it.superinterfaces()); - } - } - } - } - - @RmiMethodRegistry.TraceMethod(action = "refresh", display = "Refresh reference type", schema = "ReferenceTypeProxy") - public void refresh_reference_type_proxy(RmiTraceObject obj) { - try (RmiTransaction tx = cmds.state.trace.openTx("RefreshReferenceType")) { - String path = obj.getPath(); - String ppath = cmds.getParentPath(path); - Object parent = getObjectFromPath(ppath); - if (parent instanceof ObjectReference ref) { - cmds.putReferenceType(path, ref.referenceType(), false); - } - if (parent instanceof ClassObjectReference ref && path.endsWith("ReflectedType")) { - cmds.putReferenceType(path, ref.reflectedType(), false); - } - if (parent instanceof ClassType ct) { - cmds.putReferenceType(path, ct.superclass(), false); - } - if (parent instanceof Method method) { - cmds.putReferenceType(path, method.declaringType(), false); - } - } - } - - @RmiMethodRegistry.TraceMethod(action = "refresh", display = "Refresh reference type", schema = "ReferenceType") - public void refresh_reference_type(RmiTraceObject obj) { - try (RmiTransaction tx = cmds.state.trace.openTx("RefreshReferenceType")) { - String path = obj.getPath(); - ReferenceType refType = (ReferenceType) getObjectFromPath(path); - cmds.putReferenceType(path, refType, false); - } - } - - @RmiMethodRegistry.TraceMethod(action = "load", display = "Load reference", schema = "ReferenceType") - public void load_reftype(RmiTraceObject obj) { - try (RmiTransaction tx = cmds.state.trace.openTx("RefreshReferenceType")) { - VirtualMachine vm = manager.getJdi().getCurrentVM(); - String path = obj.getPath(); - String mempath = cmds.getPath(vm) + ".Classes"; - ReferenceType refType = (ReferenceType) getObjectFromPath(path); - cmds.putReferenceType(mempath, refType, true); - } - } - - @RmiMethodRegistry.TraceMethod(action = "refresh", display = "Refresh variables", schema = "VariableContainer") - public void refresh_variables(RmiTraceObject obj) { - try (RmiTransaction tx = cmds.state.trace.openTx("RefreshVariables")) { - String path = obj.getPath(); - String ppath = cmds.getParentPath(path); - Object parent = getObjectFromPath(ppath); - try { - if (parent instanceof Method method) { - if (path.endsWith("Arguments")) { - cmds.putLocalVariableContainer(path, method.arguments()); - } - if (path.endsWith("Variables")) { - cmds.putLocalVariableContainer(path, method.variables()); - } - } - if (parent instanceof StackFrame frame) { - Map map = frame.getValues(frame.visibleVariables()); - cmds.putLocalVariableContainer(path, map); - } - } - catch (AbsentInformationException e) { - // IGNORE - } - } - } - - @RmiMethodRegistry.TraceMethod(action = "refresh", display = "Refresh variable", schema = "Variable") - public void refresh_variable(RmiTraceObject obj) { - try (RmiTransaction tx = cmds.state.trace.openTx("RefreshVariable")) { - String path = obj.getPath(); - Object object = getObjectFromPath(path); - if (object instanceof LocalVariable var) { - cmds.putLocalVariableDetails(path, var); - } - } - } - - @RmiMethodRegistry.TraceMethod(action = "refresh", display = "Refresh locations", schema = "LocationContainer") - public void refresh_locations(RmiTraceObject obj) { - try (RmiTransaction tx = cmds.state.trace.openTx("RefreshLocations")) { - String path = obj.getPath(); - String ppath = cmds.getParentPath(path); - Object parent = getObjectFromPath(ppath); - if (parent instanceof Method) { - Method method = (Method) parent; - cmds.putLocationContainer(path, method); - } - if (parent instanceof ReferenceType) { - ReferenceType ref = (ReferenceType) parent; - cmds.putLocationContainer(path, ref); - } - } - } - - @RmiMethodRegistry.TraceMethod(action = "refresh", display = "Refresh location", schema = "Location") - public void refresh_location(RmiTraceObject obj) { - try (RmiTransaction tx = cmds.state.trace.openTx("RefreshLocation")) { - String path = obj.getPath(); - Location loc = (Location) getObjectFromPath(path); - cmds.putLocationDetails(path, loc); - } - } - - @RmiMethodRegistry.TraceMethod(action = "refresh", display = "Refresh breakpoints", schema = "BreakpointContainer") - public void refresh_breakpoints(RmiTraceObject obj) { - try (RmiTransaction tx = cmds.state.trace.openTx("RefreshBreakpoints")) { - cmds.putBreakpoints(); - } - } - - @RmiMethodRegistry.TraceMethod(action = "refresh", display = "Refresh events", schema = "EventContainer") - public void refresh_events(RmiTraceObject obj) { - try (RmiTransaction tx = cmds.state.trace.openTx("RefreshEvents")) { - cmds.putEvents(); - } - } - - @RmiMethodRegistry.TraceMethod(action = "refresh", display = "Refresh values", schema = "ValueContainer") - public void refresh_values(RmiTraceObject obj) { - try (RmiTransaction tx = cmds.state.trace.openTx("RefreshValues")) { - String path = obj.getPath(); - String ppath = cmds.getParentPath(path); - Object parent = getObjectFromPath(ppath); - if (parent instanceof ArrayReference arr) { - cmds.putValueContainer(path, arr.getValues()); - } - } - } - - @RmiMethodRegistry.TraceMethod(action = "refresh", display = "Refresh value", schema = "Value") - public void refresh_value(RmiTraceObject obj) { - try (RmiTransaction tx = cmds.state.trace.openTx("RefreshLocation")) { - String path = obj.getPath(); - Value val = (Value) getObjectFromPath(path); - cmds.putValueDetailsByType(path, val); - } - } - - @RmiMethodRegistry.TraceMethod(action = "set", display = "Set value", schema = "Variable") - public void set_value_lvar(RmiTraceObject obj, String value) { - try (RmiTransaction tx = cmds.state.trace.openTx("RefreshLocation")) { - String path = obj.getPath(); - LocalVariable lvar = (LocalVariable) getObjectFromPath(path); - cmds.modifyValue(lvar, value); - } - } - - @RmiMethodRegistry.TraceMethod(action = "set", display = "Set value", schema = "Field") - public void set_value_field(RmiTraceObject obj, String value) { - try (RmiTransaction tx = cmds.state.trace.openTx("RefreshLocation")) { - String path = obj.getPath(); - Field field = (Field) getObjectFromPath(path); - cmds.modifyValue(field, value); - } - } - - @RmiMethodRegistry.TraceMethod(action = "activate", display = "Activate", schema = "ANY") - public void activate(RmiTraceObject obj) { - try (RmiTransaction tx = cmds.state.trace.openTx("Activate")) { - String path = obj.getPath(); - cmds.activate(path); - } - } - - @RmiMethodRegistry.TraceMethod(action = "kill", display = "Kill", schema = "VirtualMachine") - public void kill(RmiTraceObject obj) { - try { - manager.getJdi().sendInterruptNow(); - } - catch (IOException e) { - e.printStackTrace(); - } - } - - @RmiMethodRegistry.TraceMethod(action = "resume", display = "Resume", schema = "VirtualMachine") - public void resume_vm(RmiTraceObject obj) { - VirtualMachine vm = (VirtualMachine) getObjectFromPath(obj.getPath()); - vm.resume(); - manager.getHooks().setState(vm); - } - - @RmiMethodRegistry.TraceMethod(action = "resume", display = "Resume", schema = "Thread") - public void resume(RmiTraceObject obj) { - ThreadReference thread = (ThreadReference) getObjectFromPath(obj.getPath()); - thread.resume(); - manager.getHooks().setState(thread.virtualMachine()); - } - - @RmiMethodRegistry.TraceMethod(action = "suspend", display = "Suspend", schema = "VirtualMachine") - public void suspend(RmiTraceObject obj) { - Object object = getObjectFromPath(obj.getPath()); - if (object instanceof ThreadReference thread) { - thread.suspend(); - manager.getHooks().setState(thread.virtualMachine()); - } - else { - VirtualMachine vm = manager.getJdi().getCurrentVM(); - vm.suspend(); - manager.getHooks().setState(vm); - } - } - - @RmiMethodRegistry.TraceMethod(action = "interrupt", display = "Interrupt", schema = "VirtualMachine") - public void interrupt(RmiTraceObject obj) { - suspend(obj); - } - - // NB: For the VirtualMachine, the step methods add requests for break-on-step for all threads. - // These requests will remain pending until the VM is resumed. - @RmiMethodRegistry.TraceMethod(action = "step_into", display = "Step into", schema = "VirtualMachine") - public void step_vm_into(RmiTraceObject obj) { - VirtualMachine vm = manager.getJdi().getCurrentVM(); - List threads = getThreadsFromValue(obj); - for (ThreadReference thread : threads) { - try { - StepRequest stepReq = vm.eventRequestManager() - .createStepRequest(thread, StepRequest.STEP_MIN, StepRequest.STEP_INTO); - stepReq.enable(); - } - catch (DuplicateRequestException dre) { - // IGNORE - } - } - vm.resume(); - } - - @RmiMethodRegistry.TraceMethod(action = "step_over", display = "Step over", schema = "VirtualMachine") - public void step_vm_over(RmiTraceObject obj) { - VirtualMachine vm = manager.getJdi().getCurrentVM(); - List threads = getThreadsFromValue(obj); - for (ThreadReference thread : threads) { - try { - StepRequest stepReq = vm.eventRequestManager() - .createStepRequest(thread, StepRequest.STEP_MIN, StepRequest.STEP_OVER); - stepReq.enable(); - } - catch (DuplicateRequestException dre) { - // IGNORE - } - } - vm.resume(); - } - - @RmiMethodRegistry.TraceMethod(action = "step_out", display = "Step out", schema = "VirtualMachine") - public void step_vm_out(RmiTraceObject obj) { - VirtualMachine vm = manager.getJdi().getCurrentVM(); - List threads = getThreadsFromValue(obj); - for (ThreadReference thread : threads) { - try { - StepRequest stepReq = vm.eventRequestManager() - .createStepRequest(thread, StepRequest.STEP_MIN, StepRequest.STEP_OUT); - stepReq.enable(); - } - catch (DuplicateRequestException dre) { - // IGNORE - } - } - vm.resume(); - } - - @RmiMethodRegistry.TraceMethod(action = "step_into", display = "Step into", schema = "Thread") - public void step_into(RmiTraceObject obj) { - VirtualMachine vm = manager.getJdi().getCurrentVM(); - ThreadReference thread = (ThreadReference) getObjectFromPath(obj.getPath()); - StepRequest stepReq = vm.eventRequestManager() - .createStepRequest(thread, StepRequest.STEP_MIN, StepRequest.STEP_INTO); - stepReq.enable(); - vm.resume(); - } - - @RmiMethodRegistry.TraceMethod(action = "step_over", display = "Step over", schema = "Thread") - public void step_over(RmiTraceObject obj) { - VirtualMachine vm = manager.getJdi().getCurrentVM(); - ThreadReference thread = (ThreadReference) getObjectFromPath(obj.getPath()); - StepRequest stepReq = vm.eventRequestManager() - .createStepRequest(thread, StepRequest.STEP_OVER, StepRequest.STEP_INTO); - stepReq.enable(); - vm.resume(); - } - - @RmiMethodRegistry.TraceMethod(action = "step_out", display = "Step out", schema = "Thread") - public void step_out(RmiTraceObject obj) { - VirtualMachine vm = manager.getJdi().getCurrentVM(); - ThreadReference thread = (ThreadReference) getObjectFromPath(obj.getPath()); - StepRequest stepReq = vm.eventRequestManager() - .createStepRequest(thread, StepRequest.STEP_OUT, StepRequest.STEP_INTO); - stepReq.enable(); - vm.resume(); - } - -// public void step_advance(Object obj) {} -// public void step_return(Object obj) {} - - @RmiMethodRegistry.TraceMethod(action = "thread_interrupt", display = "Thread Interrupt", schema = "Thread") - public void thread_interrupt(RmiTraceObject obj) { - Object object = getObjectFromPath(obj.getPath()); - if (object instanceof ThreadReference thread) { - thread.interrupt(); - manager.getHooks().setState(thread.virtualMachine()); - } - } - - @RmiMethodRegistry.TraceMethod(action = "pop_stack", display = "Pop stack", schema = "StackFrame") - public void pop_stack(RmiTraceObject obj) { - StackFrame frame = (StackFrame) getObjectFromPath(obj.getPath()); - ThreadReference thread = frame.thread(); - try { - thread.popFrames(frame); - } - catch (IncompatibleThreadStateException e) { - Msg.error(this, "Incompatible thread state for pop"); - } - } - - @RmiMethodRegistry.TraceMethod(action = "break_location", display = "Break on execute", schema = "Location") - public void break_location(RmiTraceObject obj) { - VirtualMachine vm = manager.getJdi().getCurrentVM(); - Object ctxt = getObjectFromPath(obj.getPath()); - if (ctxt instanceof Location loc) { - BreakpointRequest brkReq = vm.eventRequestManager().createBreakpointRequest(loc); - brkReq.enable(); - cmds.putBreakpoints(); - } - } - - @RmiMethodRegistry.TraceMethod(action = "break_field_access", display = "Break on access", schema = "Field") - public void break_access(RmiTraceObject obj) { - VirtualMachine vm = manager.getJdi().getCurrentVM(); - Object ctxt = getObjectFromPath(obj.getPath()); - if (ctxt instanceof Field field) { - AccessWatchpointRequest brkReq = - vm.eventRequestManager().createAccessWatchpointRequest(field); - brkReq.enable(); - cmds.putBreakpoints(); - } - } - - @RmiMethodRegistry.TraceMethod(action = "break_field_modified", display = "Break on modify", schema = "Field") - public void break_modify(RmiTraceObject obj) { - VirtualMachine vm = manager.getJdi().getCurrentVM(); - Object ctxt = getObjectFromPath(obj.getPath()); - if (ctxt instanceof Field field) { - ModificationWatchpointRequest brkReq = - vm.eventRequestManager().createModificationWatchpointRequest(field); - brkReq.enable(); - cmds.putBreakpoints(); - } - } - - @RmiMethodRegistry.TraceMethod(action = "break_exception", display = "Break on exception", schema = "ReferenceType") - public void break_exception(RmiTraceObject obj, - @TargetMethod.Param(description = "Caught exceptions will be notified", display = "NotifyCaught", name = "notifyC") Boolean notifyCaught, - @TargetMethod.Param(description = "Uncaught exceptions will be notified", display = "NotifyUncaught", name = "notifyU") Boolean notifyUncaught) { - VirtualMachine vm = manager.getJdi().getCurrentVM(); - Object ctxt = getObjectFromPath(obj.getPath()); - if (ctxt instanceof ReferenceType reftype) { - ExceptionRequest excReq = vm.eventRequestManager() - .createExceptionRequest(reftype, notifyCaught, notifyUncaught); - excReq.enable(); - cmds.putEvents(); - } - } - - private void break_started(RmiTraceObject obj) { - VirtualMachine vm = manager.getJdi().getCurrentVM(); - ThreadStartRequest brkReq = vm.eventRequestManager().createThreadStartRequest(); - Object ctxt = getObjectFromPath(obj.getPath()); - if (ctxt instanceof ThreadReference ref) { - brkReq.putProperty("Thread", ref); - brkReq.addThreadFilter(ref); - } - brkReq.enable(); - cmds.putEvents(); - } - - @RmiMethodRegistry.TraceMethod(action = "break_started", display = "Break on thread start", schema = "EventContainer") - public void break_started_container(RmiTraceObject obj) { - break_started(obj); - } - - @RmiMethodRegistry.TraceMethod(action = "break_started", display = "Break on thread start", schema = "Thread") - public void break_started_thread(RmiTraceObject obj) { - break_started(obj); - } - - private void break_death(RmiTraceObject obj) { - VirtualMachine vm = manager.getJdi().getCurrentVM(); - ThreadDeathRequest brkReq = vm.eventRequestManager().createThreadDeathRequest(); - Object ctxt = getObjectFromPath(obj.getPath()); - if (ctxt instanceof ThreadReference ref) { - brkReq.putProperty("Thread", ref); - brkReq.addThreadFilter(ref); - } - brkReq.enable(); - cmds.putEvents(); - } - - @RmiMethodRegistry.TraceMethod(action = "break_death", display = "Break on thread exit", schema = "EventContainer") - public void break_death_container(RmiTraceObject obj) { - break_death(obj); - } - - @RmiMethodRegistry.TraceMethod(action = "break_death", display = "Break on thread exit", schema = "Thread") - public void break_death_thread(RmiTraceObject obj) { - break_death(obj); - } - - @RmiMethodRegistry.TraceMethod(action = "break_vm_death", display = "Break on VM death", schema = "VirtualMachine") - public void break_vm_death(RmiTraceObject obj) { - VirtualMachine vm = manager.getJdi().getCurrentVM(); - VMDeathRequest brkReq = vm.eventRequestManager().createVMDeathRequest(); - brkReq.enable(); - cmds.putEvents(); - } - - private void break_enter(RmiTraceObject obj) { - VirtualMachine vm = manager.getJdi().getCurrentVM(); - MethodEntryRequest brkReq = vm.eventRequestManager().createMethodEntryRequest(); - Object ctxt = getObjectFromPath(obj.getPath()); - if (ctxt instanceof ReferenceType reftype) { - brkReq.putProperty("Class", reftype); - brkReq.addClassFilter(reftype); - } - if (ctxt instanceof ObjectReference ref) { - brkReq.putProperty("Instance", ref); - brkReq.addInstanceFilter(ref); - } - if (ctxt instanceof ThreadReference ref) { - brkReq.putProperty("Thread", ref); - brkReq.addThreadFilter(ref); - } - brkReq.enable(); - cmds.putEvents(); - } - - @RmiMethodRegistry.TraceMethod(action = "break_enter", display = "Break on method enter", schema = "EventContainer") - public void break_enter_container(RmiTraceObject obj) { - break_enter(obj); - } - - @RmiMethodRegistry.TraceMethod(action = "break_enter", display = "Break on method enter", schema = "ReferenceType") - public void break_enter_reftype(RmiTraceObject obj) { - break_enter(obj); - } - - @RmiMethodRegistry.TraceMethod(action = "break_enter_instance", display = "Break on method enter", schema = "ObjectReference") - public void break_enter_instance(RmiTraceObject obj) { - break_enter(obj); - } - - @RmiMethodRegistry.TraceMethod(action = "break_enter_thread", display = "Break on method enter", schema = "Thread") - public void break_enter_thread(RmiTraceObject obj) { - break_enter(obj); - } - - private void break_exit(RmiTraceObject obj) { - VirtualMachine vm = manager.getJdi().getCurrentVM(); - MethodExitRequest brkReq = vm.eventRequestManager().createMethodExitRequest(); - Object ctxt = getObjectFromPath(obj.getPath()); - if (ctxt instanceof ReferenceType reftype) { - brkReq.putProperty("Class", reftype); - brkReq.addClassFilter(reftype); - } - if (ctxt instanceof ObjectReference ref) { - brkReq.putProperty("Instance", ref); - brkReq.addInstanceFilter(ref); - } - if (ctxt instanceof ThreadReference ref) { - brkReq.putProperty("Thread", ref); - brkReq.addThreadFilter(ref); - } - brkReq.enable(); - cmds.putEvents(); - } - - @RmiMethodRegistry.TraceMethod(action = "break_exit", display = "Break on method exit", schema = "EventContainer") - public void break_exit_container(RmiTraceObject obj) { - break_exit(obj); - } - - @RmiMethodRegistry.TraceMethod(action = "break_exit", display = "Break on method exit", schema = "ReferenceType") - public void break_exit_reftype(RmiTraceObject obj) { - break_exit(obj); - } - - @RmiMethodRegistry.TraceMethod(action = "break_exit", display = "Break on method exit", schema = "ObjectReference") - public void break_exit_instance(RmiTraceObject obj) { - break_exit(obj); - } - - @RmiMethodRegistry.TraceMethod(action = "break_exit", display = "Break on method exit", schema = "Thread") - public void break_exit_thread(RmiTraceObject obj) { - break_exit(obj); - } - - private void break_load(RmiTraceObject obj) { - VirtualMachine vm = manager.getJdi().getCurrentVM(); - ClassPrepareRequest brkReq = vm.eventRequestManager().createClassPrepareRequest(); - Object ctxt = getObjectFromPath(obj.getPath()); - if (ctxt instanceof ReferenceType reftype) { - brkReq.putProperty("Class", reftype); - brkReq.addClassFilter(reftype); - } - brkReq.enable(); - cmds.putEvents(); - } - - @RmiMethodRegistry.TraceMethod(action = "break_load", display = "Break on class load", schema = "EventContainer") - public void break_load_container(RmiTraceObject obj) { - break_load(obj); - } - - @RmiMethodRegistry.TraceMethod(action = "break_load", display = "Break on class load", schema = "ReferenceType") - public void break_load_reftype(RmiTraceObject obj) { - break_load(obj); - } - - private void break_unload(RmiTraceObject obj) { - VirtualMachine vm = manager.getJdi().getCurrentVM(); - ClassUnloadRequest brkReq = vm.eventRequestManager().createClassUnloadRequest(); - brkReq.enable(); - cmds.putEvents(); - } - - @RmiMethodRegistry.TraceMethod(action = "break_unload", display = "Break on class unload", schema = "EventContainer") - public void break_unload_container(RmiTraceObject obj) { - break_unload(obj); - } - - private void break_mon_enter_contention(RmiTraceObject obj) { - VirtualMachine vm = manager.getJdi().getCurrentVM(); - MonitorContendedEnterRequest brkReq = - vm.eventRequestManager().createMonitorContendedEnterRequest(); - Object ctxt = getObjectFromPath(obj.getPath()); - if (ctxt instanceof ReferenceType reftype) { - brkReq.putProperty("Class", reftype); - brkReq.addClassFilter(reftype); - } - if (ctxt instanceof ObjectReference ref) { - brkReq.putProperty("Instance", ref); - brkReq.addInstanceFilter(ref); - } - if (ctxt instanceof ThreadReference ref) { - brkReq.putProperty("Thread", ref); - brkReq.addThreadFilter(ref); - } - brkReq.enable(); - cmds.putEvents(); - } - - @RmiMethodRegistry.TraceMethod(action = "break_mon_enter_contention", display = "Break on monitor contended enter", schema = "EventContainer") - public void break_mon_enter_contention_container(RmiTraceObject obj) { - break_mon_enter_contention(obj); - } - - @RmiMethodRegistry.TraceMethod(action = "break_mon_enter_contention", display = "Break on monitor contended enter", schema = "ReferenceType") - public void break_mon_enter_contention_reftype(RmiTraceObject obj) { - break_mon_enter_contention(obj); - } - - @RmiMethodRegistry.TraceMethod(action = "break_mon_enter_contention", display = "Break on monitor contended enter", schema = "ObjectReference") - public void break_mon_enter_contention_instance(RmiTraceObject obj) { - break_mon_enter_contention(obj); - } - - @RmiMethodRegistry.TraceMethod(action = "break_mon_enter_contention", display = "Break on monitor contended enter", schema = "Thread") - public void break_mon_enter_contention_thread(RmiTraceObject obj) { - break_mon_enter_contention(obj); - } - - private void break_mon_entered_contention(RmiTraceObject obj) { - VirtualMachine vm = manager.getJdi().getCurrentVM(); - MonitorContendedEnteredRequest brkReq = - vm.eventRequestManager().createMonitorContendedEnteredRequest(); - Object ctxt = getObjectFromPath(obj.getPath()); - if (ctxt instanceof ReferenceType reftype) { - brkReq.putProperty("Class", reftype); - brkReq.addClassFilter(reftype); - } - if (ctxt instanceof ObjectReference ref) { - brkReq.putProperty("Instance", ref); - brkReq.addInstanceFilter(ref); - } - if (ctxt instanceof ThreadReference ref) { - brkReq.putProperty("Thread", ref); - brkReq.addThreadFilter(ref); - } - brkReq.enable(); - cmds.putEvents(); - } - - @RmiMethodRegistry.TraceMethod(action = "break_mon_entered_contention", display = "Break on monitor contented entered", schema = "EventContainer") - public void break_mon_entered_contention_container(RmiTraceObject obj) { - break_mon_entered_contention(obj); - } - - @RmiMethodRegistry.TraceMethod(action = "break_mon_entered_contention", display = "Break on monitor contented entered", schema = "ReferenceType") - public void break_mon_entered_contention_reftype(RmiTraceObject obj) { - break_mon_entered_contention(obj); - } - - @RmiMethodRegistry.TraceMethod(action = "break_mon_entered_contention", display = "Break on monitor contented entered", schema = "ObjectReference") - public void break_mon_entered_contention_instance(RmiTraceObject obj) { - break_mon_entered_contention(obj); - } - - @RmiMethodRegistry.TraceMethod(action = "break_mon_entered_contention", display = "Break on monitor contented entered", schema = "Thread") - public void break_mon_entered_contention_thread(RmiTraceObject obj) { - break_mon_entered_contention(obj); - } - - private void break_mon_wait(RmiTraceObject obj) { - VirtualMachine vm = manager.getJdi().getCurrentVM(); - MonitorWaitRequest brkReq = vm.eventRequestManager().createMonitorWaitRequest(); - Object ctxt = getObjectFromPath(obj.getPath()); - if (ctxt instanceof ReferenceType reftype) { - brkReq.putProperty("Class", reftype); - brkReq.addClassFilter(reftype); - } - if (ctxt instanceof ObjectReference ref) { - brkReq.putProperty("Instance", ref); - brkReq.addInstanceFilter(ref); - } - if (ctxt instanceof ThreadReference ref) { - brkReq.putProperty("Thread", ref); - brkReq.addThreadFilter(ref); - } - brkReq.enable(); - cmds.putEvents(); - } - - @RmiMethodRegistry.TraceMethod(action = "break_mon_wait", display = "Break on monitor wait", schema = "EventContainer") - public void break_mon_wait_container(RmiTraceObject obj) { - break_mon_wait(obj); - } - - @RmiMethodRegistry.TraceMethod(action = "break_mon_wait", display = "Break on monitor wait", schema = "ReferenceType") - public void break_mon_wait_reftype(RmiTraceObject obj) { - break_mon_wait(obj); - } - - @RmiMethodRegistry.TraceMethod(action = "break_mon_wait", display = "Break on monitor wait", schema = "ObjectReference") - public void break_mon_wait_instance(RmiTraceObject obj) { - break_mon_wait(obj); - } - - @RmiMethodRegistry.TraceMethod(action = "break_mon_wait", display = "Break on monitor wait", schema = "Thread") - public void break_mon_wait_thread(RmiTraceObject obj) { - break_mon_wait(obj); - } - - private void break_mon_waited(RmiTraceObject obj) { - VirtualMachine vm = manager.getJdi().getCurrentVM(); - MonitorWaitedRequest brkReq = vm.eventRequestManager().createMonitorWaitedRequest(); - Object ctxt = getObjectFromPath(obj.getPath()); - if (ctxt instanceof ReferenceType reftype) { - brkReq.putProperty("Class", reftype); - brkReq.addClassFilter(reftype); - } - if (ctxt instanceof ObjectReference ref) { - brkReq.putProperty("Instance", ref); - brkReq.addInstanceFilter(ref); - } - if (ctxt instanceof ThreadReference ref) { - brkReq.putProperty("Thread", ref); - brkReq.addThreadFilter(ref); - } - brkReq.enable(); - cmds.putEvents(); - } - - @RmiMethodRegistry.TraceMethod(action = "break_mon_waited", display = "Break on monitor waited", schema = "EventContainer") - public void break_mon_waited_container(RmiTraceObject obj) { - break_mon_waited(obj); - } - - @RmiMethodRegistry.TraceMethod(action = "break_mon_waited", display = "Break on monitor waited", schema = "ReferenceType") - public void break_mon_waited_reftype(RmiTraceObject obj) { - break_mon_waited(obj); - } - - @RmiMethodRegistry.TraceMethod(action = "break_mon_waited", display = "Break on monitor waited", schema = "ObjectReference") - public void break_mon_waited_instance(RmiTraceObject obj) { - break_mon_waited(obj); - } - - @RmiMethodRegistry.TraceMethod(action = "break_mon_waited", display = "Break on monitor waited", schema = "Thread") - public void break_mon_waited_thread(RmiTraceObject obj) { - break_mon_waited(obj); - } - - @RmiMethodRegistry.TraceMethod(action = "add_count_filter", display = "Add count filter", schema = "Event") - public void add_count_filter(RmiTraceObject obj, - @TargetMethod.Param(description = "Count", display = "MaxCount", name = "count") Integer count) { - Object ctxt = getObjectFromPath(obj.getPath()); - if (ctxt instanceof EventRequest req) { - req.disable(); - req.addCountFilter(count); - cmds.setValue(obj.getPath(), "Count", count); - req.enable(); - cmds.putEvents(); - } - } - - @RmiMethodRegistry.TraceMethod(action = "set_class_filter", display = "Set class filter", schema = "Event") - public void set_class_filter(RmiTraceObject obj, - @TargetMethod.Param(description = "Filter Pattern", display = "Filter", name = "filter") String filter, - @TargetMethod.Param(description = "Exclude", display = "Exclude", name = "exclude") String exclude) { - Object ctxt = getObjectFromPath(obj.getPath()); - if (ctxt instanceof MethodEntryRequest req) { - req.disable(); - if (exclude.equals("true")) { - req.addClassExclusionFilter(filter); - cmds.setValue(obj.getPath(), "Exclude", filter); - } - else { - req.addClassFilter(filter); - cmds.setValue(obj.getPath(), "Include", filter); - } - req.enable(); - } - if (ctxt instanceof MethodExitRequest req) { - req.disable(); - if (exclude.equals("true")) { - req.addClassExclusionFilter(filter); - cmds.setValue(obj.getPath(), "Exclude", filter); - } - else { - req.addClassFilter(filter); - cmds.setValue(obj.getPath(), "Include", filter); - } - req.enable(); - } - if (ctxt instanceof ClassPrepareRequest req) { - req.disable(); - if (exclude.equals("true")) { - req.addClassExclusionFilter(filter); - cmds.setValue(obj.getPath(), "Exclude", filter); - } - else { - req.addClassFilter(filter); - cmds.setValue(obj.getPath(), "Include", filter); - } - req.enable(); - } - if (ctxt instanceof ClassUnloadRequest req) { - req.disable(); - if (exclude.equals("true")) { - req.addClassExclusionFilter(filter); - cmds.setValue(obj.getPath(), "Exclude", filter); - } - else { - req.addClassFilter(filter); - cmds.setValue(obj.getPath(), "Include", filter); - } - req.enable(); - } - if (ctxt instanceof MonitorContendedEnterRequest req) { - req.disable(); - if (exclude.equals("true")) { - req.addClassExclusionFilter(filter); - cmds.setValue(obj.getPath(), "Exclude", filter); - } - else { - req.addClassFilter(filter); - cmds.setValue(obj.getPath(), "Include", filter); - } - req.enable(); - } - if (ctxt instanceof MonitorContendedEnteredRequest req) { - req.disable(); - if (exclude.equals("true")) { - req.addClassExclusionFilter(filter); - cmds.setValue(obj.getPath(), "Exclude", filter); - } - else { - req.addClassFilter(filter); - cmds.setValue(obj.getPath(), "Include", filter); - } - req.enable(); - } - if (ctxt instanceof MonitorWaitRequest req) { - req.disable(); - if (exclude.equals("true")) { - req.addClassExclusionFilter(filter); - cmds.setValue(obj.getPath(), "Exclude", filter); - } - else { - req.addClassFilter(filter); - cmds.setValue(obj.getPath(), "Include", filter); - } - req.enable(); - } - if (ctxt instanceof MonitorWaitedRequest req) { - req.disable(); - if (exclude.equals("true")) { - req.addClassExclusionFilter(filter); - cmds.setValue(obj.getPath(), "Exclude", filter); - } - else { - req.addClassFilter(filter); - cmds.setValue(obj.getPath(), "Include", filter); - } - req.enable(); - } - cmds.putEvents(); - } - - @RmiMethodRegistry.TraceMethod(action = "set_source_filter", display = "Set source filter", schema = "Event") - public void set_source_filter(RmiTraceObject obj, - @TargetMethod.Param(description = "Source Name Pattern", display = "SourceName", name = "srcname") String srcname) { - Object ctxt = getObjectFromPath(obj.getPath()); - if (ctxt instanceof ClassPrepareRequest req) { - req.disable(); - req.addSourceNameFilter(srcname); - cmds.setValue(obj.getPath(), "SourceMatches", srcname); - req.enable(); - } - cmds.putEvents(); - } - - @RmiMethodRegistry.TraceMethod(action = "set_platform_filter", display = "Set platform filter", schema = "Event") - public void set_platform_filter(RmiTraceObject obj) { - Object ctxt = getObjectFromPath(obj.getPath()); - if (ctxt instanceof ThreadStartRequest req) { - req.disable(); - req.addPlatformThreadsOnlyFilter(); - cmds.setValue(obj.getPath(), "PlatformOnly", true); - req.enable(); - } - if (ctxt instanceof ThreadDeathRequest req) { - req.disable(); - req.addPlatformThreadsOnlyFilter(); - cmds.setValue(obj.getPath(), "PlatformOnly", true); - req.enable(); - } - cmds.putEvents(); - } - - @RmiMethodRegistry.TraceMethod(action = "toggle_breakpoint", display = "Toggle breakpoint", schema = "BreakpointSpec") - public void toggle_breakpoint(RmiTraceObject obj) { - VirtualMachine vm = manager.getJdi().getCurrentVM(); - Object ctxt = getObjectFromPath(obj.getPath()); - if (ctxt instanceof Field field) { - ModificationWatchpointRequest brkReq = - vm.eventRequestManager().createModificationWatchpointRequest(field); - brkReq.enable(); - } - if (ctxt instanceof EventRequest req) { - if (req.isEnabled()) { - req.disable(); - } - else { - req.enable(); - } - } - cmds.putBreakpoints(); - } - - @RmiMethodRegistry.TraceMethod(action = "toggle_event", display = "Toggle event", schema = "Event") - public void toggle_event(RmiTraceObject obj) { - Object ctxt = getObjectFromPath(obj.getPath()); - if (ctxt instanceof EventRequest req) { - if (req.isEnabled()) { - req.disable(); - } - else { - req.enable(); - } - cmds.putEvents(); - } - } - - @RmiMethodRegistry.TraceMethod(action = "toggle_scope", display = "Toggle scope", schema = "MethodContainer") - public void toggle_scope_methods(RmiTraceObject obj) { - String ppath = cmds.getParentPath(obj.getPath()); - Object parent = getObjectFromPath(ppath); - manager.toggleScope(parent); - refresh_methods(obj); - } - - @RmiMethodRegistry.TraceMethod(action = "toggle_scope", display = "Toggle scope", schema = "FieldContainer") - public void toggle_scope_fields(RmiTraceObject obj) { - String ppath = cmds.getParentPath(obj.getPath()); - Object parent = getObjectFromPath(ppath); - manager.toggleScope(parent); - if (obj.getPath().endsWith("Fields")) { - refresh_fields(obj); - } - if (obj.getPath().endsWith("Variables")) { - refresh_fields(obj); - } - } - - @RmiMethodRegistry.TraceMethod(action = "read_mem", display = "", schema = "VirtualMachine") - public long read_mem(RmiTraceObject obj, AddressRange range) { - VirtualMachine vm = manager.getJdi().getCurrentVM(); - MemoryMapper mapper = cmds.state.trace.memoryMapper; - Address start = mapper.mapBack(range.getMinAddress()); - try (RmiTransaction tx = cmds.state.trace.openTx("ReadMemory")) { - cmds.putMem(start, range.getLength(), true); - cmds.putMemState(start, range.getLength(), MemoryState.MS_KNOWN, true); - } - catch (Exception e) { - cmds.putMemState(start, range.getLength(), MemoryState.MS_ERROR, true); - } - return range.getLength(); - } - - private List getThreadsFromValue(RmiTraceObject obj) { - Object object = getObjectFromPath(obj.getPath()); - if (object instanceof VirtualMachine vm) { - return vm.allThreads(); - } - List threads = new ArrayList<>(); - if (object instanceof ThreadReference thread) { - threads.add(thread); - } - else { - threads.add(manager.getJdi().getCurrentThread()); - } - return threads; - } - - private Object getObjectFromPath(String path) { - return manager.objForPath(path); - } - -} diff --git a/Ghidra/Debug/Debugger-jpda/src/main/resources/ghidra/app/plugin/core/debug/client/tracermi/jdi_schema.xml b/Ghidra/Debug/Debugger-jpda/src/main/resources/ghidra/app/plugin/core/debug/client/tracermi/jdi_schema.xml index 14b0cee484..b17969eb38 100644 --- a/Ghidra/Debug/Debugger-jpda/src/main/resources/ghidra/app/plugin/core/debug/client/tracermi/jdi_schema.xml +++ b/Ghidra/Debug/Debugger-jpda/src/main/resources/ghidra/app/plugin/core/debug/client/tracermi/jdi_schema.xml @@ -162,7 +162,7 @@ - + @@ -361,7 +361,7 @@