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
index 46771fdb6a..fcf597c7e8 100644
--- 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
@@ -58,10 +58,7 @@ public class TraceJdiMethods implements RmiMethods {
//
// }
- @RmiMethodRegistry.TraceMethod(
- action = "refresh",
- display = "Refresh VM",
- schema = "VirtualMachine")
+ @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();
@@ -70,10 +67,7 @@ public class TraceJdiMethods implements RmiMethods {
}
}
- @RmiMethodRegistry.TraceMethod(
- action = "refresh",
- display = "Refresh process",
- schema = "ProcessRef")
+ @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();
@@ -82,10 +76,7 @@ public class TraceJdiMethods implements RmiMethods {
}
}
- @RmiMethodRegistry.TraceMethod(
- action = "refresh",
- display = "Refresh thread groups",
- schema = "ThreadGroupReferenceContainer")
+ @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();
@@ -100,10 +91,7 @@ public class TraceJdiMethods implements RmiMethods {
}
}
- @RmiMethodRegistry.TraceMethod(
- action = "refresh",
- display = "Refresh thread group",
- schema = "ThreadGroupReferenceProxy")
+ @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();
@@ -118,10 +106,7 @@ public class TraceJdiMethods implements RmiMethods {
}
}
- @RmiMethodRegistry.TraceMethod(
- action = "refresh",
- display = "Refresh thread group",
- schema = "ThreadGroupReference")
+ @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();
@@ -130,10 +115,7 @@ public class TraceJdiMethods implements RmiMethods {
}
}
- @RmiMethodRegistry.TraceMethod(
- action = "refresh",
- display = "Refresh threads",
- schema = "ThreadContainer")
+ @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();
@@ -143,10 +125,7 @@ public class TraceJdiMethods implements RmiMethods {
}
}
- @RmiMethodRegistry.TraceMethod(
- action = "refresh",
- display = "Refresh threads",
- schema = "ThreadReferenceContainer")
+ @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();
@@ -166,10 +145,7 @@ public class TraceJdiMethods implements RmiMethods {
}
}
- @RmiMethodRegistry.TraceMethod(
- action = "refresh",
- display = "Refresh Thread",
- schema = "Thread")
+ @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();
@@ -185,30 +161,21 @@ public class TraceJdiMethods implements RmiMethods {
}
}
- @RmiMethodRegistry.TraceMethod(
- action = "refresh",
- display = "Refresh registers",
- schema = "RegisterContainer")
+ @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")
+ @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")
+ @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();
@@ -217,10 +184,7 @@ public class TraceJdiMethods implements RmiMethods {
}
}
- @RmiMethodRegistry.TraceMethod(
- action = "refresh",
- display = "Refresh monitor info",
- schema = "MonitorInfoContainer")
+ @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();
@@ -233,10 +197,7 @@ public class TraceJdiMethods implements RmiMethods {
}
}
- @RmiMethodRegistry.TraceMethod(
- action = "refresh",
- display = "Refresh monitor info",
- schema = "MonitorInfo")
+ @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();
@@ -245,10 +206,7 @@ public class TraceJdiMethods implements RmiMethods {
}
}
- @RmiMethodRegistry.TraceMethod(
- action = "refresh",
- display = "Refresh fields",
- schema = "FieldContainer")
+ @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();
@@ -272,10 +230,7 @@ public class TraceJdiMethods implements RmiMethods {
// }
// }
- @RmiMethodRegistry.TraceMethod(
- action = "refresh",
- display = "Refresh objects",
- schema = "ObjectReferenceContainer")
+ @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();
@@ -300,10 +255,7 @@ public class TraceJdiMethods implements RmiMethods {
}
}
- @RmiMethodRegistry.TraceMethod(
- action = "refresh",
- display = "Refresh object",
- schema = "ObjectReferenceProxy")
+ @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();
@@ -324,10 +276,7 @@ public class TraceJdiMethods implements RmiMethods {
}
}
- @RmiMethodRegistry.TraceMethod(
- action = "refresh",
- display = "Refresh object",
- schema = "ObjectReference")
+ @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();
@@ -336,10 +285,7 @@ public class TraceJdiMethods implements RmiMethods {
}
}
- @RmiMethodRegistry.TraceMethod(
- action = "refresh",
- display = "Refresh methods",
- schema = "MethodContainer")
+ @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();
@@ -349,10 +295,7 @@ public class TraceJdiMethods implements RmiMethods {
}
}
- @RmiMethodRegistry.TraceMethod(
- action = "refresh",
- display = "Refresh method",
- schema = "Method")
+ @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();
@@ -361,10 +304,7 @@ public class TraceJdiMethods implements RmiMethods {
}
}
- @RmiMethodRegistry.TraceMethod(
- action = "refresh",
- display = "Refresh arguments",
- schema = "ArgumentContainer")
+ @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();
@@ -374,15 +314,9 @@ public class TraceJdiMethods implements RmiMethods {
}
}
- @RmiMethodRegistry.TraceMethod(
- action = "load_class",
- display = "Load class",
- schema = "ReferenceTypeContainer")
+ @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) {
+ @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);
@@ -393,18 +327,12 @@ public class TraceJdiMethods implements RmiMethods {
}
}
- @RmiMethodRegistry.TraceMethod(
- action = "refresh_memory",
- display = "Refresh memory",
- schema = "Memory")
+ @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")
+ @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();
@@ -446,10 +374,7 @@ public class TraceJdiMethods implements RmiMethods {
}
}
- @RmiMethodRegistry.TraceMethod(
- action = "refresh",
- display = "Refresh reference type",
- schema = "ReferenceTypeProxy")
+ @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();
@@ -470,10 +395,7 @@ public class TraceJdiMethods implements RmiMethods {
}
}
- @RmiMethodRegistry.TraceMethod(
- action = "refresh",
- display = "Refresh reference type",
- schema = "ReferenceType")
+ @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();
@@ -482,10 +404,7 @@ public class TraceJdiMethods implements RmiMethods {
}
}
- @RmiMethodRegistry.TraceMethod(
- action = "load",
- display = "Load reference",
- schema = "ReferenceType")
+ @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();
@@ -496,10 +415,7 @@ public class TraceJdiMethods implements RmiMethods {
}
}
- @RmiMethodRegistry.TraceMethod(
- action = "refresh",
- display = "Refresh variables",
- schema = "VariableContainer")
+ @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();
@@ -525,10 +441,7 @@ public class TraceJdiMethods implements RmiMethods {
}
}
- @RmiMethodRegistry.TraceMethod(
- action = "refresh",
- display = "Refresh variable",
- schema = "Variable")
+ @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();
@@ -539,10 +452,7 @@ public class TraceJdiMethods implements RmiMethods {
}
}
- @RmiMethodRegistry.TraceMethod(
- action = "refresh",
- display = "Refresh locations",
- schema = "LocationContainer")
+ @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();
@@ -559,10 +469,7 @@ public class TraceJdiMethods implements RmiMethods {
}
}
- @RmiMethodRegistry.TraceMethod(
- action = "refresh",
- display = "Refresh location",
- schema = "Location")
+ @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();
@@ -571,30 +478,21 @@ public class TraceJdiMethods implements RmiMethods {
}
}
- @RmiMethodRegistry.TraceMethod(
- action = "refresh",
- display = "Refresh breakpoints",
- schema = "BreakpointContainer")
+ @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")
+ @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")
+ @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();
@@ -606,10 +504,7 @@ public class TraceJdiMethods implements RmiMethods {
}
}
- @RmiMethodRegistry.TraceMethod(
- action = "refresh",
- display = "Refresh value",
- schema = "Value")
+ @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();
@@ -618,10 +513,7 @@ public class TraceJdiMethods implements RmiMethods {
}
}
- @RmiMethodRegistry.TraceMethod(
- action = "set",
- display = "Set value",
- schema = "Variable")
+ @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();
@@ -630,10 +522,7 @@ public class TraceJdiMethods implements RmiMethods {
}
}
- @RmiMethodRegistry.TraceMethod(
- action = "set",
- display = "Set value",
- schema = "Field")
+ @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();
@@ -674,10 +563,7 @@ public class TraceJdiMethods implements RmiMethods {
manager.getHooks().setState(thread.virtualMachine());
}
- @RmiMethodRegistry.TraceMethod(
- action = "suspend",
- display = "Suspend",
- schema = "VirtualMachine")
+ @RmiMethodRegistry.TraceMethod(action = "suspend", display = "Suspend", schema = "VirtualMachine")
public void suspend(RmiTraceObject obj) {
Object object = getObjectFromPath(obj.getPath());
if (object instanceof ThreadReference thread) {
@@ -691,28 +577,21 @@ public class TraceJdiMethods implements RmiMethods {
}
}
- @RmiMethodRegistry.TraceMethod(
- action = "interrupt",
- display = "Interrupt",
- schema = "VirtualMachine")
+ @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")
+ @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);
+ .createStepRequest(thread, StepRequest.STEP_MIN, StepRequest.STEP_INTO);
stepReq.enable();
}
catch (DuplicateRequestException dre) {
@@ -722,18 +601,14 @@ public class TraceJdiMethods implements RmiMethods {
vm.resume();
}
- @RmiMethodRegistry.TraceMethod(
- action = "step_over",
- display = "Step over",
- schema = "VirtualMachine")
+ @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);
+ .createStepRequest(thread, StepRequest.STEP_MIN, StepRequest.STEP_OVER);
stepReq.enable();
}
catch (DuplicateRequestException dre) {
@@ -743,18 +618,14 @@ public class TraceJdiMethods implements RmiMethods {
vm.resume();
}
- @RmiMethodRegistry.TraceMethod(
- action = "step_out",
- display = "Step out",
- schema = "VirtualMachine")
+ @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);
+ .createStepRequest(thread, StepRequest.STEP_MIN, StepRequest.STEP_OUT);
stepReq.enable();
}
catch (DuplicateRequestException dre) {
@@ -769,8 +640,7 @@ public class TraceJdiMethods implements RmiMethods {
VirtualMachine vm = manager.getJdi().getCurrentVM();
ThreadReference thread = (ThreadReference) getObjectFromPath(obj.getPath());
StepRequest stepReq = vm.eventRequestManager()
- .createStepRequest(thread, StepRequest.STEP_MIN,
- StepRequest.STEP_INTO);
+ .createStepRequest(thread, StepRequest.STEP_MIN, StepRequest.STEP_INTO);
stepReq.enable();
vm.resume();
}
@@ -780,8 +650,7 @@ public class TraceJdiMethods implements RmiMethods {
VirtualMachine vm = manager.getJdi().getCurrentVM();
ThreadReference thread = (ThreadReference) getObjectFromPath(obj.getPath());
StepRequest stepReq = vm.eventRequestManager()
- .createStepRequest(thread, StepRequest.STEP_OVER,
- StepRequest.STEP_INTO);
+ .createStepRequest(thread, StepRequest.STEP_OVER, StepRequest.STEP_INTO);
stepReq.enable();
vm.resume();
}
@@ -791,8 +660,7 @@ public class TraceJdiMethods implements RmiMethods {
VirtualMachine vm = manager.getJdi().getCurrentVM();
ThreadReference thread = (ThreadReference) getObjectFromPath(obj.getPath());
StepRequest stepReq = vm.eventRequestManager()
- .createStepRequest(thread, StepRequest.STEP_OUT,
- StepRequest.STEP_INTO);
+ .createStepRequest(thread, StepRequest.STEP_OUT, StepRequest.STEP_INTO);
stepReq.enable();
vm.resume();
}
@@ -800,10 +668,7 @@ public class TraceJdiMethods implements RmiMethods {
// public void step_advance(Object obj) {}
// public void step_return(Object obj) {}
- @RmiMethodRegistry.TraceMethod(
- action = "thread_interrupt",
- display = "Thread Interrupt",
- schema = "Thread")
+ @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) {
@@ -812,10 +677,7 @@ public class TraceJdiMethods implements RmiMethods {
}
}
- @RmiMethodRegistry.TraceMethod(
- action = "pop_stack",
- display = "Pop stack",
- schema = "StackFrame")
+ @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();
@@ -823,68 +685,49 @@ public class TraceJdiMethods implements RmiMethods {
thread.popFrames(frame);
}
catch (IncompatibleThreadStateException e) {
- Msg.out("Incompatible thread state for pop");
+ Msg.error(this, "Incompatible thread state for pop");
}
}
- @RmiMethodRegistry.TraceMethod(
- action = "break_location",
- display = "Break on execute",
- schema = "Location")
+ @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);
+ BreakpointRequest brkReq = vm.eventRequestManager().createBreakpointRequest(loc);
brkReq.enable();
cmds.putBreakpoints();
}
}
- @RmiMethodRegistry.TraceMethod(
- action = "break_field_access",
- display = "Break on access",
- schema = "Field")
+ @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);
+ AccessWatchpointRequest brkReq =
+ vm.eventRequestManager().createAccessWatchpointRequest(field);
brkReq.enable();
cmds.putBreakpoints();
}
}
- @RmiMethodRegistry.TraceMethod(
- action = "break_field_modified",
- display = "Break on modify",
- schema = "Field")
+ @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);
+ ModificationWatchpointRequest brkReq =
+ vm.eventRequestManager().createModificationWatchpointRequest(field);
brkReq.enable();
cmds.putBreakpoints();
}
}
- @RmiMethodRegistry.TraceMethod(
- action = "break_exception",
- display = "Break on exception",
- schema = "ReferenceType")
+ @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) {
+ @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) {
@@ -897,8 +740,7 @@ public class TraceJdiMethods implements RmiMethods {
private void break_started(RmiTraceObject obj) {
VirtualMachine vm = manager.getJdi().getCurrentVM();
- ThreadStartRequest brkReq = vm.eventRequestManager()
- .createThreadStartRequest();
+ ThreadStartRequest brkReq = vm.eventRequestManager().createThreadStartRequest();
Object ctxt = getObjectFromPath(obj.getPath());
if (ctxt instanceof ThreadReference ref) {
brkReq.putProperty("Thread", ref);
@@ -908,26 +750,19 @@ public class TraceJdiMethods implements RmiMethods {
cmds.putEvents();
}
- @RmiMethodRegistry.TraceMethod(
- action = "break_started",
- display = "Break on thread start",
- schema = "EventContainer")
+ @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")
+ @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();
+ ThreadDeathRequest brkReq = vm.eventRequestManager().createThreadDeathRequest();
Object ctxt = getObjectFromPath(obj.getPath());
if (ctxt instanceof ThreadReference ref) {
brkReq.putProperty("Thread", ref);
@@ -937,38 +772,27 @@ public class TraceJdiMethods implements RmiMethods {
cmds.putEvents();
}
- @RmiMethodRegistry.TraceMethod(
- action = "break_death",
- display = "Break on thread exit",
- schema = "EventContainer")
+ @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")
+ @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")
+ @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();
+ 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();
+ MethodEntryRequest brkReq = vm.eventRequestManager().createMethodEntryRequest();
Object ctxt = getObjectFromPath(obj.getPath());
if (ctxt instanceof ReferenceType reftype) {
brkReq.putProperty("Class", reftype);
@@ -986,42 +810,29 @@ public class TraceJdiMethods implements RmiMethods {
cmds.putEvents();
}
- @RmiMethodRegistry.TraceMethod(
- action = "break_enter",
- display = "Break on method enter",
- schema = "EventContainer")
+ @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")
+ @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")
+ @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")
+ @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();
+ MethodExitRequest brkReq = vm.eventRequestManager().createMethodExitRequest();
Object ctxt = getObjectFromPath(obj.getPath());
if (ctxt instanceof ReferenceType reftype) {
brkReq.putProperty("Class", reftype);
@@ -1039,42 +850,29 @@ public class TraceJdiMethods implements RmiMethods {
cmds.putEvents();
}
- @RmiMethodRegistry.TraceMethod(
- action = "break_exit",
- display = "Break on method exit",
- schema = "EventContainer")
+ @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")
+ @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")
+ @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")
+ @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();
+ ClassPrepareRequest brkReq = vm.eventRequestManager().createClassPrepareRequest();
Object ctxt = getObjectFromPath(obj.getPath());
if (ctxt instanceof ReferenceType reftype) {
brkReq.putProperty("Class", reftype);
@@ -1084,42 +882,32 @@ public class TraceJdiMethods implements RmiMethods {
cmds.putEvents();
}
- @RmiMethodRegistry.TraceMethod(
- action = "break_load",
- display = "Break on class load",
- schema = "EventContainer")
+ @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")
+ @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();
+ ClassUnloadRequest brkReq = vm.eventRequestManager().createClassUnloadRequest();
brkReq.enable();
cmds.putEvents();
}
- @RmiMethodRegistry.TraceMethod(
- action = "break_unload",
- display = "Break on class unload",
- schema = "EventContainer")
+ @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();
+ MonitorContendedEnterRequest brkReq =
+ vm.eventRequestManager().createMonitorContendedEnterRequest();
Object ctxt = getObjectFromPath(obj.getPath());
if (ctxt instanceof ReferenceType reftype) {
brkReq.putProperty("Class", reftype);
@@ -1137,42 +925,30 @@ public class TraceJdiMethods implements RmiMethods {
cmds.putEvents();
}
- @RmiMethodRegistry.TraceMethod(
- action = "break_mon_enter_contention",
- display = "Break on monitor contended enter",
- schema = "EventContainer")
+ @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")
+ @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")
+ @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")
+ @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();
+ MonitorContendedEnteredRequest brkReq =
+ vm.eventRequestManager().createMonitorContendedEnteredRequest();
Object ctxt = getObjectFromPath(obj.getPath());
if (ctxt instanceof ReferenceType reftype) {
brkReq.putProperty("Class", reftype);
@@ -1190,42 +966,29 @@ public class TraceJdiMethods implements RmiMethods {
cmds.putEvents();
}
- @RmiMethodRegistry.TraceMethod(
- action = "break_mon_entered_contention",
- display = "Break on monitor contented entered",
- schema = "EventContainer")
+ @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")
+ @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")
+ @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")
+ @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();
+ MonitorWaitRequest brkReq = vm.eventRequestManager().createMonitorWaitRequest();
Object ctxt = getObjectFromPath(obj.getPath());
if (ctxt instanceof ReferenceType reftype) {
brkReq.putProperty("Class", reftype);
@@ -1243,42 +1006,29 @@ public class TraceJdiMethods implements RmiMethods {
cmds.putEvents();
}
- @RmiMethodRegistry.TraceMethod(
- action = "break_mon_wait",
- display = "Break on monitor wait",
- schema = "EventContainer")
+ @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")
+ @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")
+ @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")
+ @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();
+ MonitorWaitedRequest brkReq = vm.eventRequestManager().createMonitorWaitedRequest();
Object ctxt = getObjectFromPath(obj.getPath());
if (ctxt instanceof ReferenceType reftype) {
brkReq.putProperty("Class", reftype);
@@ -1296,47 +1046,29 @@ public class TraceJdiMethods implements RmiMethods {
cmds.putEvents();
}
- @RmiMethodRegistry.TraceMethod(
- action = "break_mon_waited",
- display = "Break on monitor waited",
- schema = "EventContainer")
+ @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")
+ @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")
+ @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")
+ @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")
+ @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) {
+ @TargetMethod.Param(description = "Count", display = "MaxCount", name = "count") Integer count) {
Object ctxt = getObjectFromPath(obj.getPath());
if (ctxt instanceof EventRequest req) {
req.disable();
@@ -1347,19 +1079,10 @@ public class TraceJdiMethods implements RmiMethods {
}
}
- @RmiMethodRegistry.TraceMethod(
- action = "set_class_filter",
- display = "Set class filter",
- schema = "Event")
+ @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) {
+ @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();
@@ -1460,15 +1183,9 @@ public class TraceJdiMethods implements RmiMethods {
cmds.putEvents();
}
- @RmiMethodRegistry.TraceMethod(
- action = "set_source_filter",
- display = "Set source filter",
- schema = "Event")
+ @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) {
+ @TargetMethod.Param(description = "Source Name Pattern", display = "SourceName", name = "srcname") String srcname) {
Object ctxt = getObjectFromPath(obj.getPath());
if (ctxt instanceof ClassPrepareRequest req) {
req.disable();
@@ -1479,10 +1196,7 @@ public class TraceJdiMethods implements RmiMethods {
cmds.putEvents();
}
- @RmiMethodRegistry.TraceMethod(
- action = "set_platform_filter",
- display = "Set platform filter",
- schema = "Event")
+ @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) {
@@ -1500,16 +1214,13 @@ public class TraceJdiMethods implements RmiMethods {
cmds.putEvents();
}
- @RmiMethodRegistry.TraceMethod(
- action = "toggle_breakpoint",
- display = "Toggle breakpoint",
- schema = "BreakpointSpec")
+ @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);
+ ModificationWatchpointRequest brkReq =
+ vm.eventRequestManager().createModificationWatchpointRequest(field);
brkReq.enable();
}
if (ctxt instanceof EventRequest req) {
@@ -1523,10 +1234,7 @@ public class TraceJdiMethods implements RmiMethods {
cmds.putBreakpoints();
}
- @RmiMethodRegistry.TraceMethod(
- action = "toggle_event",
- display = "Toggle event",
- schema = "Event")
+ @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) {
@@ -1540,10 +1248,7 @@ public class TraceJdiMethods implements RmiMethods {
}
}
- @RmiMethodRegistry.TraceMethod(
- action = "toggle_scope",
- display = "Toggle scope",
- schema = "MethodContainer")
+ @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);
@@ -1551,10 +1256,7 @@ public class TraceJdiMethods implements RmiMethods {
refresh_methods(obj);
}
- @RmiMethodRegistry.TraceMethod(
- action = "toggle_scope",
- display = "Toggle scope",
- schema = "FieldContainer")
+ @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);
diff --git a/Ghidra/Features/Base/src/main/help/help/topics/BookmarkPlugin/Bookmarks.htm b/Ghidra/Features/Base/src/main/help/help/topics/BookmarkPlugin/Bookmarks.htm
index f6a703ad73..7f2ec2600f 100644
--- a/Ghidra/Features/Base/src/main/help/help/topics/BookmarkPlugin/Bookmarks.htm
+++ b/Ghidra/Features/Base/src/main/help/help/topics/BookmarkPlugin/Bookmarks.htm
@@ -290,7 +290,7 @@
only the entry point bookmarks, you would enter "entry" in the filter field. The results
would show only those bookmarks with a Category or Description containing the word "entry".
The text filter is not case sensitive, nor does it support regular expressions .
+ "help/topics/Glossary/glossary.htm#RegularExpression">Regular Expressions.
Reorder Columns
diff --git a/Ghidra/Features/Base/src/main/help/help/topics/Glossary/glossary.htm b/Ghidra/Features/Base/src/main/help/help/topics/Glossary/glossary.htm
index 3ced47cc76..652ec485a1 100644
--- a/Ghidra/Features/Base/src/main/help/help/topics/Glossary/glossary.htm
+++ b/Ghidra/Features/Base/src/main/help/help/topics/Glossary/glossary.htm
@@ -1111,7 +1111,10 @@ xmlns:w="urn:schemas-microsoft-com:office:word" xmlns="http://www.w3.org/TR/REC-
Regular Expression
- A character sequence used to match patterns in strings.
+ A character sequence used to match patterns in strings. See
+ Regular Expression
+ for examples.
+
Relocation Table
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/context/ProgramLocationActionContext.java b/Ghidra/Features/Base/src/main/java/ghidra/app/context/ProgramLocationActionContext.java
index 0f89d4738d..dce04ed743 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/context/ProgramLocationActionContext.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/context/ProgramLocationActionContext.java
@@ -124,7 +124,7 @@ public class ProgramLocationActionContext extends ProgramActionContext
return functions;
}
- private Function getFunctionForLocation() {
+ protected Function getFunctionForLocation() {
if (location instanceof FunctionLocation functionLocation) {
Address functionAddress = functionLocation.getFunctionAddress();
return program.getFunctionManager().getFunctionAt(functionAddress);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/calltree/CallTreePlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/calltree/CallTreePlugin.java
index 381a9a64ad..89e7ae4aff 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/calltree/CallTreePlugin.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/calltree/CallTreePlugin.java
@@ -4,9 +4,9 @@
* 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.
@@ -25,6 +25,7 @@ import docking.action.DockingAction;
import docking.action.MenuData;
import generic.theme.GIcon;
import ghidra.app.CorePluginPackage;
+import ghidra.app.context.FunctionSupplierContext;
import ghidra.app.context.ListingActionContext;
import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.plugin.ProgramPlugin;
@@ -145,7 +146,15 @@ public class CallTreePlugin extends ProgramPlugin {
@Override
public boolean isAddToPopup(ActionContext context) {
- return (context instanceof ListingActionContext);
+ if (context instanceof ListingActionContext) {
+ return true;
+ }
+
+ if (context instanceof FunctionSupplierContext functionContext) {
+ return functionContext.hasFunctions();
+ }
+
+ return false;
}
};
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferenceContext.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferenceContext.java
index efc85f3b15..1784d1884e 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferenceContext.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferenceContext.java
@@ -4,9 +4,9 @@
* 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.
@@ -92,6 +92,18 @@ public class LocationReferenceContext {
return buffy.toString();
}
+ /**
+ * Returns text that is helpful for debugging, such as printing to a console.
+ * @return the text
+ */
+ public String getDebugText() {
+ StringBuilder buffy = new StringBuilder();
+ for (Part part : parts) {
+ buffy.append(part.getDebugText());
+ }
+ return buffy.toString();
+ }
+
/**
* Returns HTML text for this context. Any matching items embedded in the returned string will
* be bold.
@@ -142,7 +154,7 @@ public class LocationReferenceContext {
abstract String getHtmlText();
- abstract String getText(String start, String end);
+ abstract String getDebugText();
static String fixBreakingSpaces(String s) {
String updated = s.replaceAll("\\s", " ");
@@ -165,8 +177,8 @@ public class LocationReferenceContext {
}
@Override
- String getText(String start, String end) {
- return text; // we don't decorate
+ String getDebugText() {
+ return text;
}
@Override
@@ -187,8 +199,8 @@ public class LocationReferenceContext {
}
@Override
- String getText(String start, String end) {
- return start + text + end;
+ String getDebugText() {
+ return " [[ " + text + " ]] ";
}
@Override
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferenceContextBuilder.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferenceContextBuilder.java
index 2240778b50..a99a9d0b9f 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferenceContextBuilder.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferenceContextBuilder.java
@@ -4,9 +4,9 @@
* 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.
@@ -58,6 +58,19 @@ public class LocationReferenceContextBuilder {
return this;
}
+ /**
+ * Adds a newline character to the previously added text.
+ * @return this builder
+ */
+ public LocationReferenceContextBuilder newline() {
+ if (parts.isEmpty()) {
+ throw new IllegalStateException("Cannot add a newline without first appending text");
+ }
+ Part last = parts.get(parts.size() - 1);
+ last.text += '\n';
+ return this;
+ }
+
/**
* Builds a {@link LocationReferenceContext} using the text supplied via the {@code append}
* methods.
@@ -67,6 +80,14 @@ public class LocationReferenceContextBuilder {
return new LocationReferenceContext(parts);
}
+ /**
+ * Returns true if no text has been added to this builder.
+ * @return true if no text has been added to this builder
+ */
+ public boolean isEmpty() {
+ return parts.isEmpty();
+ }
+
@Override
public String toString() {
return Json.toString(this);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/SearchTextPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/SearchTextPlugin.java
index eacc2d6ba6..2f78643573 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/SearchTextPlugin.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/SearchTextPlugin.java
@@ -150,8 +150,7 @@ public class SearchTextPlugin extends ProgramPlugin implements OptionsChangeList
if (result == null) {
searchDialog.setStatusText("Not found");
}
- else if (result.programLocation()
- .equals(currentLocation)) {
+ else if (result.programLocation().equals(currentLocation)) {
searchNext(searchTask.getProgram(), searchNavigatable, textSearcher);
}
else {
@@ -376,8 +375,9 @@ public class SearchTextPlugin extends ProgramPlugin implements OptionsChangeList
* Create the action for to pop up the search dialog.
*/
private void createActions() {
- String subGroup = getClass().getName();
+ String subGroup = "d"; // Memory Search uses groups 'a', 'b', and 'c'
+ //@formatter:off
new ActionBuilder("Search Text", getName())
.menuPath("&Search", "Program &Text...")
.menuGroup("search", subGroup)
@@ -406,6 +406,7 @@ public class SearchTextPlugin extends ProgramPlugin implements OptionsChangeList
searchDialog.repeatSearch();
})
.buildAndInstall(tool);
+ //@formatter:on
}
protected void updateNavigatable(ActionContext context) {
@@ -467,8 +468,7 @@ public class SearchTextPlugin extends ProgramPlugin implements OptionsChangeList
String textSelection = navigatable.getTextSelection();
ProgramLocation location = navigatable.getLocation();
Address address = location.getAddress();
- Listing listing = context.getProgram()
- .getListing();
+ Listing listing = context.getProgram().getListing();
CodeUnit codeUnit = listing.getCodeUnitAt(address);
boolean isInstruction = false;
if (textSelection != null) {
@@ -582,8 +582,7 @@ public class SearchTextPlugin extends ProgramPlugin implements OptionsChangeList
// must have completed too fast for the provider to be set; try something cute
Component focusOwner =
- KeyboardFocusManager.getCurrentKeyboardFocusManager()
- .getFocusOwner();
+ KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
return focusOwner; // assume this IS the provider
}
@@ -628,8 +627,7 @@ public class SearchTextPlugin extends ProgramPlugin implements OptionsChangeList
@Override
public Highlight[] createHighlights(String text, ListingField field, int cursorTextOffset) {
- Class extends FieldFactory> fieldFactoryClass = field.getFieldFactory()
- .getClass();
+ Class extends FieldFactory> fieldFactoryClass = field.getFieldFactory().getClass();
if (!doHighlight) {
return NO_HIGHLIGHTS;
@@ -652,8 +650,7 @@ public class SearchTextPlugin extends ProgramPlugin implements OptionsChangeList
return getAllHighlights(text, cursorTextOffset);
}
- Address address = searchResult.programLocation()
- .getAddress();
+ Address address = searchResult.programLocation().getAddress();
ProxyObj> proxy = field.getProxy();
if (proxy.contains(address)) {
return getSingleSearchHighlight(text, field, cursorTextOffset);
@@ -745,8 +742,7 @@ public class SearchTextPlugin extends ProgramPlugin implements OptionsChangeList
return true;
}
- Class extends FieldFactory> factoryClass = field.getFieldFactory()
- .getClass();
+ Class extends FieldFactory> factoryClass = field.getFieldFactory().getClass();
if (searchOptions.searchComments()) {
if (factoryClass == PreCommentFieldFactory.class ||
factoryClass == PlateFieldFactory.class ||
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/table/TableComponentProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/table/TableComponentProvider.java
index 8b06b73aaa..ed1bb7bf19 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/table/TableComponentProvider.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/table/TableComponentProvider.java
@@ -4,9 +4,9 @@
* 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.
@@ -384,6 +384,10 @@ public class TableComponentProvider extends ComponentProviderAdapter
return model;
}
+ public GhidraTable getTable() {
+ return threadedPanel.getTable();
+ }
+
private void updateTitle() {
setSubTitle(generateSubTitle());
}
diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/PrettyPrinter.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/PrettyPrinter.java
index 79c5977f6d..e0c34c5f80 100644
--- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/PrettyPrinter.java
+++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/PrettyPrinter.java
@@ -4,9 +4,9 @@
* 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.
@@ -25,14 +25,12 @@ import ghidra.program.model.symbol.NameTransformer;
import ghidra.util.StringUtilities;
/**
- * This class is used to convert a C/C++ language
- * token group into readable C/C++ code.
+ * This class is used to convert a C/C++ language token group into readable C/C++ code.
*/
public class PrettyPrinter {
- /**
- * The indent string to use when printing.
- */
+ private final static NameTransformer IDENTITY = new IdentityNameTransformer();
+
public final static String INDENT_STRING = " ";
private Function function;
@@ -51,7 +49,7 @@ public class PrettyPrinter {
public PrettyPrinter(Function function, ClangTokenGroup tokgroup, NameTransformer transformer) {
this.function = function;
this.tokgroup = tokgroup;
- this.transformer = (transformer != null) ? transformer : new IdentityNameTransformer();
+ this.transformer = transformer != null ? transformer : IDENTITY;
flattenLines();
padEmptyLines();
}
@@ -72,8 +70,7 @@ public class PrettyPrinter {
}
/**
- * Returns a list of the C language lines contained in the
- * C language token group.
+ * Returns a list of the C language lines contained in the C language token group.
* @return a list of the C language lines
*/
public List getLines() {
@@ -81,37 +78,51 @@ public class PrettyPrinter {
}
/**
- * Prints the C language token group
- * into a string of C code.
+ * Prints the C language token group into a string of C code.
* @return a string of readable C code
*/
public DecompiledFunction print() {
StringBuilder buff = new StringBuilder();
for (ClangLine line : lines) {
- buff.append(line.getIndentString());
- List tokens = line.getAllTokens();
-
- for (ClangToken token : tokens) {
- boolean isToken2Clean = token instanceof ClangFuncNameToken ||
- token instanceof ClangVariableToken || token instanceof ClangTypeToken ||
- token instanceof ClangFieldToken || token instanceof ClangLabelToken;
-
- //do not clean constant variable tokens
- if (isToken2Clean && token.getSyntaxType() == ClangToken.CONST_COLOR) {
- isToken2Clean = false;
- }
-
- String tokenText = token.getText();
- if (isToken2Clean) {
- tokenText = transformer.simplify(tokenText);
- }
- buff.append(tokenText);
- }
+ getText(buff, line, transformer);
buff.append(StringUtilities.LINE_SEPARATOR);
}
return new DecompiledFunction(findSignature(), buff.toString());
}
+ private static void getText(StringBuilder buff, ClangLine line, NameTransformer transformer) {
+ buff.append(line.getIndentString());
+ List tokens = line.getAllTokens();
+
+ for (ClangToken token : tokens) {
+ boolean isToken2Clean = token instanceof ClangFuncNameToken ||
+ token instanceof ClangVariableToken || token instanceof ClangTypeToken ||
+ token instanceof ClangFieldToken || token instanceof ClangLabelToken;
+
+ //do not clean constant variable tokens
+ if (isToken2Clean && token.getSyntaxType() == ClangToken.CONST_COLOR) {
+ isToken2Clean = false;
+ }
+
+ String tokenText = token.getText();
+ if (isToken2Clean) {
+ tokenText = transformer.simplify(tokenText);
+ }
+ buff.append(tokenText);
+ }
+ }
+
+ /**
+ * Returns the text of the given line as seen in the UI.
+ * @param line the line
+ * @return the text
+ */
+ public static String getText(ClangLine line) {
+ StringBuilder buff = new StringBuilder();
+ getText(buff, line, IDENTITY);
+ return buff.toString();
+ }
+
private String findSignature() {
int nChildren = tokgroup.numChildren();
for (int i = 0; i < nChildren; ++i) {
diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/DecompilerActionContext.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/DecompilerActionContext.java
index ccde49eb95..ce6c51c881 100644
--- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/DecompilerActionContext.java
+++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/DecompilerActionContext.java
@@ -4,9 +4,9 @@
* 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.
@@ -23,6 +23,7 @@ import ghidra.app.context.NavigatableActionContext;
import ghidra.app.context.RestrictedAddressSetContext;
import ghidra.app.decompiler.*;
import ghidra.app.decompiler.component.DecompilerPanel;
+import ghidra.app.decompiler.component.DecompilerUtils;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Function;
@@ -123,8 +124,8 @@ public class DecompilerActionContext extends NavigatableActionContext
if (lineNumber != 0) {
return lineNumber;
}
- getTokenAtCursor();
- return tokenAtCursor == null ? 0 : tokenAtCursor.getLineParent().getLineNumber();
+ ClangToken token = getTokenAtCursor();
+ return token == null ? 0 : token.getLineParent().getLineNumber();
}
public DecompilerPanel getDecompilerPanel() {
@@ -152,6 +153,22 @@ public class DecompilerActionContext extends NavigatableActionContext
getComponentProvider().getController().setStatusMessage(msg);
}
+ // allows this Decompiler action context to signal the location is on a function
+ @Override
+ protected Function getFunctionForLocation() {
+ ClangToken token = getTokenAtCursor();
+ if (token == null) {
+ return null;
+ }
+
+ if (token instanceof ClangFuncNameToken functionToken) {
+ Function function = DecompilerUtils.getFunction(program, functionToken);
+ return function;
+ }
+
+ return null;
+ }
+
/**
* The companion method of {@link #checkActionEnablement(Supplier)}.
*
diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/DecompilerProvider.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/DecompilerProvider.java
index a43259d00a..68f33df871 100644
--- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/DecompilerProvider.java
+++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/plugin/core/decompile/DecompilerProvider.java
@@ -4,9 +4,9 @@
* 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.
@@ -1062,7 +1062,7 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
//
// Search
//
- String searchGroup = "comment2 - Search Group";
+ String searchGroup = "Comment2 - Search Group";
subGroupPosition = 0; // reset for the next group
FindAction findAction = new FindAction();
diff --git a/Ghidra/Features/DecompilerDependent/build.gradle b/Ghidra/Features/DecompilerDependent/build.gradle
index bf9c36055e..9fab3b88c9 100644
--- a/Ghidra/Features/DecompilerDependent/build.gradle
+++ b/Ghidra/Features/DecompilerDependent/build.gradle
@@ -4,9 +4,9 @@
* 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.
@@ -15,6 +15,7 @@
*/
apply from: "$rootProject.projectDir/gradle/distributableGhidraModule.gradle"
apply from: "$rootProject.projectDir/gradle/javaProject.gradle"
+apply from: "$rootProject.projectDir/gradle/helpProject.gradle"
apply from: "$rootProject.projectDir/gradle/jacocoProject.gradle"
apply from: "$rootProject.projectDir/gradle/javaTestProject.gradle"
apply plugin: 'eclipse'
diff --git a/Ghidra/Features/DecompilerDependent/certification.manifest b/Ghidra/Features/DecompilerDependent/certification.manifest
index b40809b58c..b428bddc97 100644
--- a/Ghidra/Features/DecompilerDependent/certification.manifest
+++ b/Ghidra/Features/DecompilerDependent/certification.manifest
@@ -1,3 +1,8 @@
##VERSION: 2.0
Module.manifest||GHIDRA||||END|
data/ExtensionPoint.manifest||GHIDRA||||END|
+data/decompiler.dependent.theme.properties||GHIDRA||||END|
+src/main/help/help/TOC_Source.xml||GHIDRA||||END|
+src/main/help/help/topics/DecompilerTextFinderPlugin/Decompiler_Text_Finder.html||GHIDRA||||END|
+src/main/help/help/topics/DecompilerTextFinderPlugin/images/DecompilerTextFinderDialog.png||GHIDRA||||END|
+src/main/help/help/topics/DecompilerTextFinderPlugin/images/DecompilerTextFinderResultsTable.png||GHIDRA||||END|
diff --git a/Ghidra/Features/DecompilerDependent/data/decompiler.dependent.theme.properties b/Ghidra/Features/DecompilerDependent/data/decompiler.dependent.theme.properties
new file mode 100644
index 0000000000..f4b6f297f1
--- /dev/null
+++ b/Ghidra/Features/DecompilerDependent/data/decompiler.dependent.theme.properties
@@ -0,0 +1,7 @@
+
+[Defaults]
+
+
+icon.plugin.decompiler.text.finder.select.functions = icon.make.selection {FunctionScope.gif[size(12,12)][move(6,6)]}
+
+[Dark Defaults]
\ No newline at end of file
diff --git a/Ghidra/Features/DecompilerDependent/src/main/help/help/TOC_Source.xml b/Ghidra/Features/DecompilerDependent/src/main/help/help/TOC_Source.xml
new file mode 100644
index 0000000000..3ee1228742
--- /dev/null
+++ b/Ghidra/Features/DecompilerDependent/src/main/help/help/TOC_Source.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
diff --git a/Ghidra/Features/DecompilerDependent/src/main/help/help/topics/DecompilerTextFinderPlugin/Decompiler_Text_Finder.html b/Ghidra/Features/DecompilerDependent/src/main/help/help/topics/DecompilerTextFinderPlugin/Decompiler_Text_Finder.html
new file mode 100644
index 0000000000..c6a52eb4f0
--- /dev/null
+++ b/Ghidra/Features/DecompilerDependent/src/main/help/help/topics/DecompilerTextFinderPlugin/Decompiler_Text_Finder.html
@@ -0,0 +1,197 @@
+
+
+
+
+ Search Decompiled Text
+
+
+
+
+
+
+ Search Decompiled Text
+
+
+
+ Available from Search Search
+ Decompiled Text , this action allows you to search the decompiled output
+ for each function in the current program.
+
+
+
+
+
+ The Decompiled Function Search dialog is shown when users execute the Search
+ Decompiled Text action. If String Search is selected, then a case insensitive text
+ search is performed using the specified text. If Regular Expression is selected, then
+ a Regular Expression
+ search is performed. Selecting Search Selection will only search function entry points
+ that are in the current program selection.
+
+
+
+
+
+
+
+
+
+
+
+
+ The Decompiled Function Search input dialog
+
+
+
+
+
+
+ When restricting the search to
+ the current program selection, only functions whose entry point is in the selection will
+ be searched. The selection will not search functions that have a program selection in
+ the body, but not at the entry point.
+
+
+
+
+ By default text searches apply
+ only to one line at a time. If you would like a multi-line search, then you will need
+ to use a Regular Expression search to do so. See the table below for an example.
+
+
+
+
+
+ Search Results
+
+
+ The search results will be presented as they are found, as seen in the table below. For single
+ line search matches, the matching part of the search will be highlighted in the Context
+ column.
+
+
+
+
+
+
+
+
+
+
+
+
+ The Decompiled Function Search results table
+
+
+
+
+ Select Functions Action
+
+
+
+
+ This action will create a program selection for each function entry point for each function
+ selected in the table.
+
+
+
+ Other Actions
+
+
+ Help for the other table actions can be found
+ here .
+
+
+
+
+
+
+ Example Searches
+
+
+ The table below show some example searches and lines that they will match. Note that the
+ reported matches will show the entire line that matched, not just the matching portion of the
+ line.
+
+
+
+
+
+
+
+
+ Search String
+ Description
+ Example Matching Lines
+
+
+
+
+ = '\0'
+
+
+
+ A non-regular expression to find the null character assignment.
+
+
+
+ ptr->data[1] = '\0';
+
+
+
+
+
+
+ set_string\(.*->.*\)
+
+
+
+ A regular expression to find set_string(
followed by any number of characters,
+ followed by ->
, followed by any number of characters and a closing parenthesis.
+
+
+
+ set_string(mytable->entry + mytable->numcodes,ptr);
+
+
+
+
+
+
+ (?s)ffff.*piVar2 =
+
+
+
+ A regular expression that searches across multiple lines by using (?S)
. This
+ will find ffff
followed by any number of characters, followed by
+ piVar2 =
.
+
+
+
+ if (__CTOR_LIST__ != (code *)0xffffffff) {
+ piVar2 = (int *)&__CTOR_LIST__;,
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Provided by: Decompiler Text Finder Plugin
+
+ Related Topics:
+
+
+
+
+
\ No newline at end of file
diff --git a/Ghidra/Features/DecompilerDependent/src/main/help/help/topics/DecompilerTextFinderPlugin/images/DecompilerTextFinderDialog.png b/Ghidra/Features/DecompilerDependent/src/main/help/help/topics/DecompilerTextFinderPlugin/images/DecompilerTextFinderDialog.png
new file mode 100644
index 0000000000..c9f279e131
Binary files /dev/null and b/Ghidra/Features/DecompilerDependent/src/main/help/help/topics/DecompilerTextFinderPlugin/images/DecompilerTextFinderDialog.png differ
diff --git a/Ghidra/Features/DecompilerDependent/src/main/help/help/topics/DecompilerTextFinderPlugin/images/DecompilerTextFinderResultsTable.png b/Ghidra/Features/DecompilerDependent/src/main/help/help/topics/DecompilerTextFinderPlugin/images/DecompilerTextFinderResultsTable.png
new file mode 100644
index 0000000000..ecb0f3f16c
Binary files /dev/null and b/Ghidra/Features/DecompilerDependent/src/main/help/help/topics/DecompilerTextFinderPlugin/images/DecompilerTextFinderResultsTable.png differ
diff --git a/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/plugin/core/search/DecompilerTextFinder.java b/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/plugin/core/search/DecompilerTextFinder.java
new file mode 100644
index 0000000000..1329048010
--- /dev/null
+++ b/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/plugin/core/search/DecompilerTextFinder.java
@@ -0,0 +1,389 @@
+/* ###
+ * 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.app.plugin.core.search;
+
+import java.util.*;
+import java.util.function.Consumer;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import generic.json.Json;
+import ghidra.app.decompiler.*;
+import ghidra.app.decompiler.component.DecompilerUtils;
+import ghidra.app.decompiler.parallel.*;
+import ghidra.app.plugin.core.navigation.locationreferences.LocationReferenceContext;
+import ghidra.app.plugin.core.navigation.locationreferences.LocationReferenceContextBuilder;
+import ghidra.program.model.address.AddressSet;
+import ghidra.program.model.address.AddressSpace;
+import ghidra.program.model.listing.*;
+import ghidra.util.Msg;
+import ghidra.util.task.TaskMonitor;
+import utility.function.Dummy;
+
+/**
+ * Searches for the given pattern in all functions in the given program.
+ */
+public class DecompilerTextFinder {
+
+ /**
+ * Finds text inside decompiled functions using the given pattern.
+ * @param program the program
+ * @param searchPattern the search pattern
+ * @param consumer the consumer that will get matches
+ * @param monitor the task monitor
+ * @see #findText(Program, Pattern, Collection, Consumer, TaskMonitor)
+ */
+ public void findText(Program program, Pattern searchPattern, Consumer consumer,
+ TaskMonitor monitor) {
+
+ monitor = TaskMonitor.dummyIfNull(monitor);
+ StringFinderCallback callback = new StringFinderCallback(program, searchPattern, consumer);
+
+ Listing listing = program.getListing();
+ FunctionIterator functions = listing.getFunctions(true);
+
+ doFindText(program, functions, callback, monitor);
+ }
+
+ /**
+ * Finds text inside the given decompiled functions using the given pattern.
+ * @param program the program
+ * @param searchPattern the search pattern
+ * @param functions the functions to search
+ * @param consumer the consumer that will get matches
+ * @param monitor the task monitor
+ * @see #findText(Program, Pattern, Consumer, TaskMonitor)
+ */
+ public void findText(Program program, Pattern searchPattern, Iterator functions,
+ Consumer consumer, TaskMonitor monitor) {
+
+ monitor = TaskMonitor.dummyIfNull(monitor);
+ StringFinderCallback callback = new StringFinderCallback(program, searchPattern, consumer);
+ doFindText(program, functions, callback, monitor);
+ }
+
+ /**
+ * Finds text inside the given decompiled functions using the given pattern.
+ * @param program the program
+ * @param searchPattern the search pattern
+ * @param functions the functions to search
+ * @param consumer the consumer that will get matches
+ * @param monitor the task monitor
+ * @see #findText(Program, Pattern, Consumer, TaskMonitor)
+ */
+ public void findText(Program program, Pattern searchPattern, Collection functions,
+ Consumer consumer, TaskMonitor monitor) {
+
+ monitor = TaskMonitor.dummyIfNull(monitor);
+ StringFinderCallback callback = new StringFinderCallback(program, searchPattern, consumer);
+ doFindText(functions, callback, monitor);
+ }
+
+ private void doFindText(Collection functions, StringFinderCallback callback,
+ TaskMonitor monitor) {
+
+ try {
+ ParallelDecompiler.decompileFunctions(callback, functions, monitor);
+
+ }
+ catch (InterruptedException e) {
+ Thread.currentThread().interrupt(); // reset the flag
+ if (!monitor.isCancelled()) {
+ Msg.debug(this, "Interrupted while decompiling functions");
+ }
+ }
+ catch (Exception e) {
+ Msg.error(this, "Encountered an exception decompiling functions", e);
+ }
+ finally {
+ callback.dispose();
+ }
+ }
+
+ private void doFindText(Program program, Iterator functions,
+ StringFinderCallback callback, TaskMonitor monitor) {
+
+ Consumer dummy = Dummy.consumer();
+
+ try {
+ ParallelDecompiler.decompileFunctions(callback, program, functions, dummy, monitor);
+
+ }
+ catch (InterruptedException e) {
+ Thread.currentThread().interrupt(); // reset the flag
+ if (!monitor.isCancelled()) {
+ Msg.debug(this, "Interrupted while decompiling functions");
+ }
+ }
+ catch (Exception e) {
+ Msg.error(this, "Encountered an exception decompiling functions", e);
+ }
+ finally {
+ callback.dispose();
+ }
+ }
+
+ private static class StringFinderCallback extends DecompilerCallback {
+
+ private Consumer callback;
+ private Pattern pattern;
+ private String searchText;
+
+ StringFinderCallback(Program program, Pattern pattern, Consumer callback) {
+ super(program, new DecompilerConfigurer());
+ this.pattern = pattern;
+ this.callback = callback;
+ this.searchText = pattern.pattern();
+ }
+
+ @Override
+ public Void process(DecompileResults results, TaskMonitor monitor) throws Exception {
+
+ Function function = results.getFunction();
+ if (function.isThunk()) {
+ return null;
+ }
+
+ ClangTokenGroup tokens = results.getCCodeMarkup();
+ List lines = DecompilerUtils.toLines(tokens);
+
+ // (?s) - enable dot all mode
+ // (?-s) - disable dot all mode
+ boolean multiLine = (pattern.flags() & Pattern.DOTALL) == Pattern.DOTALL;
+ if (multiLine) {
+ performMultiLineSearch(function, lines);
+ }
+ else {
+ // line-by-line search
+ for (ClangLine cLine : lines) {
+ findMatch(function, cLine);
+ }
+ }
+
+ return null;
+ }
+
+ private void performMultiLineSearch(Function function, List lines) {
+
+ // Map characters to lines so we can later translate a character position into the line
+ // that contains it. Also convert all lines into one big run of text to use with the
+ // regex. Also, turn the c line into a String for later searching.
+ StringBuilder buffy = new StringBuilder();
+ TreeMap linesRangeMap = new TreeMap<>();
+ int pos = 0;
+ for (ClangLine cLine : lines) {
+ String text = PrettyPrinter.getText(cLine);
+ buffy.append(text).append('\n');
+ TextLine textLine = new TextLine(pos, cLine, text);
+ linesRangeMap.put(pos, textLine);
+ pos += text.length() + 1; // +1 for newline
+ }
+
+ Matcher matcher = pattern.matcher(buffy);
+ findMatches(function, linesRangeMap, matcher);
+ }
+
+ /**
+ * Uses the given matcher to search for all matches, which may span multiple lines.
+ */
+ private void findMatches(Function function, TreeMap linesRangeMap,
+ Matcher matcher) {
+
+ while (matcher.find()) {
+ emitTextMatch(function, linesRangeMap, matcher);
+ }
+ }
+
+ private void emitTextMatch(Function function, TreeMap linesRangeMap,
+ Matcher matcher) {
+
+ List lineMatches = new ArrayList<>();
+
+ int pos = 0;
+ int start = matcher.start();
+ int end = matcher.end();
+ for (pos = start; pos < end; pos++) {
+
+ // grab the line that contains the current character position
+ TextLine line = linesRangeMap.floorEntry(pos).getValue();
+
+ // This will be positive if the current line contains the match start character.
+ // In this case, let the line know it has the start. If we don't set the start,
+ // then the line match will start at 0.
+ int lineStartOffset = start - line.getOffset(); // relative offset
+ if (lineStartOffset >= 0) {
+ line.setMatchStart(lineStartOffset);
+ }
+
+ // In this case, let the line know it has the end. If we don't set the end,
+ // then the line match will end at the end of the line.
+ if (end <= line.getEndOffset()) {
+ int relativeEnd = end - line.getOffset();
+ line.setMatchEnd(relativeEnd);
+ }
+
+ lineMatches.add(line);
+ pos = line.getEndOffset();
+ }
+
+ // Use the first line for attributes of the match, like line number and address
+ TextLine firstLine = lineMatches.get(0);
+ int lineNumber = firstLine.getLineNumber();
+ AddressSet addresses = getAddresses(function, firstLine.getCLine());
+ LocationReferenceContext context = createMatchContext(lineMatches);
+ TextMatch match =
+ new TextMatch(function, addresses, lineNumber, searchText, context, true);
+ callback.accept(match);
+ }
+
+ private LocationReferenceContext createMatchContext(List matches) {
+
+ LocationReferenceContextBuilder builder = new LocationReferenceContextBuilder();
+ for (TextLine line : matches) {
+ if (!builder.isEmpty()) {
+ builder.newline();
+ }
+
+ String text = line.getText();
+ int start = line.getMatchStart();
+ int end = line.getMatchEnd();
+ builder.append(text.substring(0, start));
+ builder.appendMatch(text.substring(start, end));
+ builder.append(text.substring(end, line.length()));
+ }
+
+ return builder.build();
+ }
+
+ private void findMatch(Function function, ClangLine line) {
+
+ String textLine = PrettyPrinter.getText(line);
+ Matcher matcher = pattern.matcher(textLine);
+ if (!matcher.find()) {
+ return;
+ }
+
+ LocationReferenceContextBuilder builder = new LocationReferenceContextBuilder();
+
+ int start = matcher.start();
+ int end = matcher.end();
+ builder.append(textLine.substring(0, start));
+ builder.appendMatch(textLine.substring(start, end));
+ if (end < textLine.length()) {
+ builder.append(textLine.substring(end));
+ }
+
+ int lineNumber = line.getLineNumber();
+ AddressSet addresses = getAddresses(function, line);
+ LocationReferenceContext context = builder.build();
+ TextMatch match =
+ new TextMatch(function, addresses, lineNumber, searchText, context, false);
+ callback.accept(match);
+ }
+
+ private AddressSet getAddresses(Function function, ClangLine line) {
+ Program program = function.getProgram();
+ AddressSpace space = function.getEntryPoint().getAddressSpace();
+ List tokens = line.getAllTokens();
+ return DecompilerUtils.findClosestAddressSet(program, space, tokens);
+ }
+
+ /**
+ * A text line represents a ClangLine, it's pretty text, its character position in the
+ * overall body of text and the character positions of the portion of text that has matched
+ * a search. A line may have a search match that is partial or the entire line may match
+ * the search, such as in a multi-line match.
+ */
+ private class TextLine {
+ private ClangLine cLine;
+ private int offset; // the character offset into the entire body of text
+ private String text;
+
+ // relative offsets
+ private int matchStart;
+ private int matchEnd;
+
+ TextLine(int offset, ClangLine cLine, String text) {
+ this.cLine = cLine;
+ this.offset = offset;
+ this.text = text;
+
+ matchStart = 0;
+ matchEnd = text.length();
+ }
+
+ ClangLine getCLine() {
+ return cLine;
+ }
+
+ int length() {
+ return text.length();
+ }
+
+ int getOffset() {
+ return offset;
+ }
+
+ int getEndOffset() {
+ return offset + length();
+ }
+
+ int getLineNumber() {
+ return cLine.getLineNumber();
+ }
+
+ String getText() {
+ return text;
+ }
+
+ int getMatchStart() {
+ return matchStart;
+ }
+
+ int getMatchEnd() {
+ return matchEnd;
+ }
+
+ void setMatchStart(int matchStart) {
+ this.matchStart = matchStart;
+ }
+
+ void setMatchEnd(int matchEnd) {
+ this.matchEnd = matchEnd;
+ }
+
+ @Override
+ public String toString() {
+ return Json.toString(this);
+ }
+ }
+ }
+
+ private static class DecompilerConfigurer implements DecompileConfigurer {
+
+ @Override
+ public void configure(DecompInterface decompiler) {
+ decompiler.toggleCCode(true);
+ decompiler.toggleSyntaxTree(true);
+ decompiler.setSimplificationStyle("decompile");
+
+ DecompileOptions xmlOptions = new DecompileOptions();
+ xmlOptions.setDefaultTimeout(60);
+ decompiler.setOptions(xmlOptions);
+ }
+ }
+
+}
diff --git a/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/plugin/core/search/DecompilerTextFinderDialog.java b/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/plugin/core/search/DecompilerTextFinderDialog.java
new file mode 100644
index 0000000000..2ac4c02df1
--- /dev/null
+++ b/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/plugin/core/search/DecompilerTextFinderDialog.java
@@ -0,0 +1,235 @@
+/* ###
+ * 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.app.plugin.core.search;
+
+import java.awt.BorderLayout;
+import java.awt.event.KeyEvent;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+import javax.swing.*;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+
+import org.apache.commons.lang3.StringUtils;
+
+import docking.ReusableDialogComponentProvider;
+import docking.widgets.checkbox.GCheckBox;
+import docking.widgets.combobox.GhidraComboBox;
+import docking.widgets.label.GLabel;
+import ghidra.util.HelpLocation;
+import ghidra.util.MessageType;
+
+/**
+ * A dialog to gather input for performing a search over decompiled text.
+ */
+public class DecompilerTextFinderDialog extends ReusableDialogComponentProvider {
+
+ private GhidraComboBox textCombo;
+
+ private JButton searchButton;
+ private JCheckBox regexCb;
+ private JCheckBox searchSelectionCb;
+
+ private String searchText;
+ private boolean isCancelled;
+
+ public DecompilerTextFinderDialog() {
+ super("Decompiled Function Search");
+
+ addWorkPanel(buildMainPanel());
+ buildButtons();
+
+ setHelpLocation(new HelpLocation("DecompilerTextFinderPlugin", "Search_Decompiled_Text"));
+ }
+
+ private void buildButtons() {
+ searchButton = new JButton("Search");
+ searchButton.addActionListener(ev -> doSearch());
+ addButton(searchButton);
+ setDefaultButton(searchButton);
+
+ addCancelButton();
+ }
+
+ private JPanel buildMainPanel() {
+
+ regexCb = new GCheckBox("Regular Expression", false);
+ regexCb.setName("Regular Expression Search");
+
+ regexCb.addItemListener(e -> clearStatusText());
+
+ searchSelectionCb = new JCheckBox("Search Selection");
+ searchSelectionCb.setName("Search Selection");
+
+ textCombo = new GhidraComboBox<>();
+ textCombo.setEditable(true);
+ textCombo.addActionListener(e -> doSearch());
+
+ textCombo.setColumns(20);
+ textCombo.addDocumentListener(new DocumentListener() {
+ @Override
+ public void changedUpdate(DocumentEvent e) {
+ handleDocumentUpdate();
+ }
+
+ @Override
+ public void insertUpdate(DocumentEvent e) {
+ handleDocumentUpdate();
+ }
+
+ @Override
+ public void removeUpdate(DocumentEvent e) {
+ handleDocumentUpdate();
+ }
+
+ private void handleDocumentUpdate() {
+ String text = textCombo.getText();
+ searchButton.setEnabled(!StringUtils.isBlank(text));
+ clearStatusText();
+ }
+ });
+
+ JLabel findLabel = new GLabel("Find: ");
+
+ // associate this label with a mnemonic key that activates the text field
+ findLabel.setDisplayedMnemonic(KeyEvent.VK_N);
+ textCombo.associateLabel(findLabel);
+
+ JPanel mainPanel = new JPanel(new BorderLayout());
+ JPanel textPanel = new JPanel();
+ textPanel.setLayout(new BoxLayout(textPanel, BoxLayout.LINE_AXIS));
+ textPanel.add(findLabel);
+ textPanel.add(textCombo);
+ mainPanel.add(textPanel, BorderLayout.NORTH);
+ mainPanel.add(buildOptionsPanel(), BorderLayout.SOUTH);
+ mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
+
+ return mainPanel;
+ }
+
+ private JPanel buildOptionsPanel() {
+ JPanel optionsPanel = new JPanel();
+ optionsPanel.setLayout(new BoxLayout(optionsPanel, BoxLayout.LINE_AXIS));
+ optionsPanel.setBorder(BorderFactory.createTitledBorder("Options"));
+
+ optionsPanel.add(regexCb);
+ optionsPanel.add(Box.createHorizontalGlue());
+ optionsPanel.add(searchSelectionCb);
+
+ return optionsPanel;
+ }
+
+ @Override
+ public void close() {
+ textCombo.setText("");
+ super.close();
+ }
+
+ private void doSearch() {
+
+ searchText = null;
+ clearStatusText();
+ if (!searchButton.isEnabled()) {
+ return; // don't search while disabled
+ }
+
+ String text = textCombo.getText();
+ if (!validateRegex(text)) {
+ return; // leave the dialog open so the user can see the error text
+ }
+
+ isCancelled = false;
+ searchText = text;
+ updateSearchHistory(searchText);
+ close();
+ }
+
+ private boolean validateRegex(String text) {
+
+ if (!isRegex()) {
+ return true;
+ }
+
+ try {
+ Pattern.compile(text);
+ return true;
+ }
+ catch (PatternSyntaxException e) {
+ setStatusText("Invalid regex: " + e.getMessage(), MessageType.ERROR);
+ return false;
+ }
+ }
+
+ @Override
+ protected void dialogShown() {
+ searchButton.setEnabled(false);
+ clearStatusText();
+ searchText = null;
+
+ // To track cancelled, assume that the dialog is always in a cancelled state unless the
+ // user actually performed a search.
+ isCancelled = true;
+ }
+
+ public void setSearchText(String text) {
+ textCombo.setText(text);
+ }
+
+ public String getSearchText() {
+ return searchText;
+ }
+
+ public boolean isSearchSelection() {
+ return searchSelectionCb.isSelected();
+ }
+
+ public void setSearchSelectionEnabled(boolean b) {
+ if (!b) {
+ searchSelectionCb.setEnabled(false);
+ searchSelectionCb.setSelected(false);
+ }
+ else {
+ searchSelectionCb.setEnabled(true);
+ }
+ }
+
+ public boolean isRegex() {
+ return regexCb.isSelected();
+ }
+
+ public boolean isCancelled() {
+ return isCancelled;
+ }
+
+ private void updateSearchHistory(String text) {
+
+ MutableComboBoxModel model = (MutableComboBoxModel) textCombo.getModel();
+ model.insertElementAt(text, 0);
+
+ int size = model.getSize();
+ for (int i = 1; i < size; i++) {
+ String element = model.getElementAt(i);
+ if (element.equals(text)) { // already in the list, remove it
+ model.removeElementAt(i);
+ break;
+ }
+ }
+
+ // do this last since removing items may change the selected item
+ model.setSelectedItem(text);
+ }
+}
diff --git a/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/plugin/core/search/DecompilerTextFinderPlugin.java b/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/plugin/core/search/DecompilerTextFinderPlugin.java
new file mode 100644
index 0000000000..9fffe608be
--- /dev/null
+++ b/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/plugin/core/search/DecompilerTextFinderPlugin.java
@@ -0,0 +1,167 @@
+/* ###
+ * 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.app.plugin.core.search;
+
+import java.awt.Color;
+
+import javax.swing.Icon;
+
+import docking.action.MenuData;
+import docking.action.builder.ActionBuilder;
+import generic.theme.GIcon;
+import ghidra.app.CorePluginPackage;
+import ghidra.app.context.NavigatableActionContext;
+import ghidra.app.context.NavigatableContextAction;
+import ghidra.app.events.ProgramSelectionPluginEvent;
+import ghidra.app.nav.Navigatable;
+import ghidra.app.plugin.PluginCategoryNames;
+import ghidra.app.plugin.ProgramPlugin;
+import ghidra.app.plugin.core.table.TableComponentProvider;
+import ghidra.app.util.SearchConstants;
+import ghidra.app.util.query.TableService;
+import ghidra.framework.options.ToolOptions;
+import ghidra.framework.plugintool.*;
+import ghidra.framework.plugintool.util.PluginStatus;
+import ghidra.program.model.address.AddressSet;
+import ghidra.program.model.listing.*;
+import ghidra.program.util.ProgramSelection;
+import ghidra.util.table.GhidraTable;
+
+//@formatter:off
+@PluginInfo(
+ status = PluginStatus.RELEASED,
+ packageName = CorePluginPackage.NAME,
+ category = PluginCategoryNames.SEARCH,
+ shortDescription = "Decompiler Text Finder Plugin",
+ description = "This plugin adds an action to allow users to search decompiled text.",
+ servicesRequired = { TableService.class }
+)
+//@formatter:on
+public class DecompilerTextFinderPlugin extends ProgramPlugin {
+
+ private static final Icon SELECT_FUNCTIONS_ICON =
+ new GIcon("icon.plugin.decompiler.text.finder.select.functions");
+
+ private DecompilerTextFinderDialog searchDialog;
+
+ public DecompilerTextFinderPlugin(PluginTool tool) {
+ super(tool);
+
+ createActions();
+ }
+
+ private void createActions() {
+
+ NavigatableContextAction searchAction =
+ new NavigatableContextAction("Search Decompiled Text", getName()) {
+ @Override
+ public void actionPerformed(NavigatableActionContext context) {
+ search(context.getNavigatable(), context.getProgram());
+ }
+ };
+
+ // Memory Search uses groups 'a', 'b', and 'c'; Search Text uses group 'd'
+ String subGroup = "e";
+ searchAction.setMenuBarData(new MenuData(new String[] { "Search", "Decompiled Text..." },
+ null, "search", -1, subGroup));
+
+ searchAction.addToWindowWhen(NavigatableActionContext.class);
+
+ tool.addAction(searchAction);
+ }
+
+ private void search(Navigatable navigatable, Program program) {
+
+ if (searchDialog == null) {
+ searchDialog = new DecompilerTextFinderDialog();
+ }
+
+ // update the Search Selection checkbox as needed
+ boolean enableSearchSelection = false;
+ if (currentSelection != null) {
+ FunctionManager functionManager = program.getFunctionManager();
+ FunctionIterator it = functionManager.getFunctions(currentSelection, true);
+ if (it.hasNext()) {
+ enableSearchSelection = true;
+ }
+ }
+ searchDialog.setSearchSelectionEnabled(enableSearchSelection);
+
+ tool.showDialog(searchDialog);
+ if (searchDialog.isCancelled()) {
+ return;
+ }
+
+ String searchText = searchDialog.getSearchText();
+ boolean isRegex = searchDialog.isRegex();
+ String title = "Decompiler Search Text - '" + searchText + "'";
+ String tableTypeName = "Decompiler Search";
+ DecompilerTextFinderTableModel model =
+ new DecompilerTextFinderTableModel(tool, program, searchText, isRegex);
+ if (searchDialog.isSearchSelection()) {
+ model.setSelection(currentSelection);
+ }
+
+ int searchLimit = getSearchLimit();
+ model.setSearchLimit(searchLimit);
+
+ Color markerColor = SearchConstants.SEARCH_HIGHLIGHT_COLOR;
+ Icon markerIcon = new GIcon("icon.base.search.marker");
+ String windowSubMenu = "Search";
+ TableService tableService = tool.getService(TableService.class);
+ TableComponentProvider provider = tableService.showTableWithMarkers(title,
+ tableTypeName, model, markerColor, markerIcon, windowSubMenu, navigatable);
+
+ provider.installRemoveItemsAction();
+
+ GhidraTable table = provider.getTable();
+ //@formatter:off
+ new ActionBuilder("Select Functions", getName())
+ .description("Make program selection of function starts from selected rows")
+ .toolBarIcon(SELECT_FUNCTIONS_ICON)
+ .popupMenuIcon(SELECT_FUNCTIONS_ICON)
+ .popupMenuPath("Select Functions")
+ .popupMenuGroup(null, "a") // before the others in the table, to match the toolbar
+ .enabledWhen(c -> table.getSelectedRowCount() > 0)
+ .onAction(c -> selectFunctions(table, model))
+ .buildAndInstallLocal(provider)
+ ;
+ //@formatter:on
+ }
+
+ private int getSearchLimit() {
+ ToolOptions options = tool.getOptions(SearchConstants.SEARCH_OPTION_NAME);
+ return options.getInt(SearchConstants.SEARCH_LIMIT_NAME,
+ SearchConstants.DEFAULT_SEARCH_LIMIT);
+ }
+
+ private void selectFunctions(GhidraTable table, DecompilerTextFinderTableModel model) {
+
+ AddressSet addresses = new AddressSet();
+ int[] rows = table.getSelectedRows();
+ for (int row : rows) {
+ TextMatch match = model.getRowObject(row);
+ Function f = match.getFunction();
+ addresses.add(f.getEntryPoint());
+ }
+
+ ProgramSelection selection = new ProgramSelection(addresses);
+ PluginEvent event =
+ new ProgramSelectionPluginEvent(getName(), selection, table.getProgram());
+ firePluginEvent(event);
+ }
+
+}
diff --git a/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/plugin/core/search/DecompilerTextFinderTableModel.java b/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/plugin/core/search/DecompilerTextFinderTableModel.java
new file mode 100644
index 0000000000..c8b068265d
--- /dev/null
+++ b/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/plugin/core/search/DecompilerTextFinderTableModel.java
@@ -0,0 +1,200 @@
+/* ###
+ * 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.app.plugin.core.search;
+
+import java.awt.Component;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
+import java.util.regex.Pattern;
+
+import docking.widgets.table.*;
+import ghidra.app.plugin.core.navigation.locationreferences.LocationReferenceContext;
+import ghidra.docking.settings.Settings;
+import ghidra.framework.plugintool.ServiceProvider;
+import ghidra.program.model.address.Address;
+import ghidra.program.model.address.AddressSetView;
+import ghidra.program.model.listing.*;
+import ghidra.util.datastruct.Accumulator;
+import ghidra.util.exception.CancelledException;
+import ghidra.util.table.GhidraProgramTableModel;
+import ghidra.util.table.column.AbstractGhidraColumnRenderer;
+import ghidra.util.table.column.GColumnRenderer;
+import ghidra.util.table.field.AbstractProgramBasedDynamicTableColumn;
+import ghidra.util.table.field.FunctionNameTableColumn;
+import ghidra.util.task.TaskMonitor;
+
+public class DecompilerTextFinderTableModel extends GhidraProgramTableModel {
+
+ private String searchText;
+ private boolean isRegex;
+ private AddressSetView selection;
+ private int searchLimit;
+
+ protected DecompilerTextFinderTableModel(ServiceProvider serviceProvider, Program program,
+ String searchText, boolean isRegex) {
+ super("Decompiler Search", serviceProvider, program, null, true);
+ this.searchText = searchText;
+ this.isRegex = isRegex;
+ }
+
+ void setSelection(AddressSetView selection) {
+ this.selection = selection;
+ }
+
+ void setSearchLimit(int limit) {
+ this.searchLimit = limit;
+ }
+
+ @Override
+ protected TableColumnDescriptor createTableColumnDescriptor() {
+
+ TableColumnDescriptor descriptor = new TableColumnDescriptor<>();
+
+ descriptor.addVisibleColumn(
+ DiscoverableTableUtils.adaptColumForModel(this, new FunctionNameTableColumn()), 1,
+ true);
+ descriptor.addVisibleColumn(new LineNumberTableColumn(), 2, true);
+ descriptor.addVisibleColumn(new ContextTableColumn());
+
+ return descriptor;
+ }
+
+ @Override
+ protected void doLoad(Accumulator accumulator, TaskMonitor monitor)
+ throws CancelledException {
+
+ // Add a consumer that will monitor the count and stop the process on too many results
+ AtomicInteger counter = new AtomicInteger();
+ Consumer limitedConsumer = tm -> {
+ int count = counter.incrementAndGet();
+ if (count >= searchLimit) {
+ monitor.cancel();
+ }
+
+ accumulator.add(tm);
+ };
+
+ Pattern pattern;
+ if (isRegex) {
+ // note: we expect this to be a valid regex
+ pattern = Pattern.compile(searchText);
+ }
+ else {
+ String quoted = Pattern.quote(searchText);
+ pattern = Pattern.compile(quoted, Pattern.CASE_INSENSITIVE);
+ }
+
+ DecompilerTextFinder finder = new DecompilerTextFinder();
+ if (selection != null) {
+ FunctionManager functionManager = program.getFunctionManager();
+ FunctionIterator functions = functionManager.getFunctions(selection, true);
+ finder.findText(program, pattern, functions, limitedConsumer, monitor);
+ }
+ else {
+ finder.findText(program, pattern, limitedConsumer, monitor);
+ }
+ }
+
+ @Override
+ public Address getAddress(int row) {
+ TextMatch match = getRowObject(row);
+ if (match != null) {
+ return match.getAddress();
+ }
+ return null;
+ }
+
+//=================================================================================================
+//Inner Classes
+//=================================================================================================
+
+ private class LineNumberTableColumn
+ extends AbstractProgramBasedDynamicTableColumn {
+
+ @Override
+ public Integer getValue(TextMatch rowObject, Settings settings, Program p,
+ ServiceProvider sp) throws IllegalArgumentException {
+ return rowObject.getLineNumber();
+ }
+
+ @Override
+ public String getColumnName() {
+ return "Line Number";
+ }
+
+ @Override
+ public int getColumnPreferredWidth() {
+ return 75;
+ }
+ }
+
+ private class ContextTableColumn
+ extends AbstractProgramBasedDynamicTableColumn {
+
+ private ContextCellRenderer renderer = new ContextCellRenderer();
+
+ @Override
+ public LocationReferenceContext getValue(TextMatch rowObject, Settings settings, Program p,
+ ServiceProvider sp) throws IllegalArgumentException {
+ return rowObject.getContext();
+ }
+
+ @Override
+ public String getColumnName() {
+ return "Context";
+ }
+
+ @Override
+ public GColumnRenderer getColumnRenderer() {
+ return renderer;
+ }
+ }
+
+ private class ContextCellRenderer
+ extends AbstractGhidraColumnRenderer {
+
+ {
+ // the context uses html
+ setHTMLRenderingEnabled(true);
+ }
+
+ @Override
+ public Component getTableCellRendererComponent(GTableCellRenderingData data) {
+
+ // initialize
+ super.getTableCellRendererComponent(data);
+
+ TextMatch match = (TextMatch) data.getRowObject();
+ LocationReferenceContext context = match.getContext();
+ String text;
+ if (match.isMultiLine()) {
+ // multi-line matches create visual noise when showing colors, as of much of the
+ // entire line matches
+ text = context.getPlainText();
+ }
+ else {
+ text = context.getBoldMatchingText();
+ }
+ setText(text);
+ return this;
+ }
+
+ @Override
+ public String getFilterString(LocationReferenceContext context, Settings settings) {
+ return context.getPlainText();
+ }
+ }
+}
diff --git a/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/plugin/core/search/TextMatch.java b/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/plugin/core/search/TextMatch.java
new file mode 100644
index 0000000000..094e04a928
--- /dev/null
+++ b/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/plugin/core/search/TextMatch.java
@@ -0,0 +1,79 @@
+/* ###
+ * 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.app.plugin.core.search;
+
+import generic.json.Json;
+import ghidra.app.plugin.core.navigation.locationreferences.LocationReferenceContext;
+import ghidra.program.model.address.Address;
+import ghidra.program.model.address.AddressSet;
+import ghidra.program.model.listing.Function;
+
+/**
+ * A simple class that represents text found in Decompiler output.
+ */
+public class TextMatch {
+
+ private Function function;
+ private AddressSet addresses;
+ private LocationReferenceContext context;
+ private int lineNumber;
+
+ private String searchText;
+ private boolean isMultiLine;
+
+ TextMatch(Function function, AddressSet addresses, int lineNumber, String searchText,
+ LocationReferenceContext context, boolean isMultiLine) {
+ this.function = function;
+ this.addresses = addresses;
+ this.lineNumber = lineNumber;
+ this.searchText = searchText;
+ this.context = context;
+ this.isMultiLine = isMultiLine;
+ }
+
+ public Function getFunction() {
+ return function;
+ }
+
+ public LocationReferenceContext getContext() {
+ return context;
+ }
+
+ public int getLineNumber() {
+ return lineNumber;
+ }
+
+ public Address getAddress() {
+ if (addresses.isEmpty()) {
+ return function.getEntryPoint();
+ }
+
+ return addresses.getFirstRange().getMinAddress();
+ }
+
+ public boolean isMultiLine() {
+ return isMultiLine;
+ }
+
+ public String getSearchText() {
+ return searchText;
+ }
+
+ @Override
+ public String toString() {
+ return Json.toString(this, "function", "context", "searchText");
+ }
+}
diff --git a/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/plugin/core/search/TextMatchToAddressTableRowMapper.java b/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/plugin/core/search/TextMatchToAddressTableRowMapper.java
new file mode 100644
index 0000000000..f025ca0bea
--- /dev/null
+++ b/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/plugin/core/search/TextMatchToAddressTableRowMapper.java
@@ -0,0 +1,30 @@
+/* ###
+ * 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.app.plugin.core.search;
+
+import ghidra.framework.plugintool.ServiceProvider;
+import ghidra.program.model.address.Address;
+import ghidra.program.model.listing.Program;
+import ghidra.util.table.ProgramLocationTableRowMapper;
+
+public class TextMatchToAddressTableRowMapper
+ extends ProgramLocationTableRowMapper {
+
+ @Override
+ public Address map(TextMatch rowObject, Program data, ServiceProvider serviceProvider) {
+ return rowObject.getAddress();
+ }
+}
diff --git a/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/plugin/core/search/TextMatchToFunctionTableRowMapper.java b/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/plugin/core/search/TextMatchToFunctionTableRowMapper.java
new file mode 100644
index 0000000000..ba5023d7ae
--- /dev/null
+++ b/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/plugin/core/search/TextMatchToFunctionTableRowMapper.java
@@ -0,0 +1,30 @@
+/* ###
+ * 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.app.plugin.core.search;
+
+import ghidra.framework.plugintool.ServiceProvider;
+import ghidra.program.model.listing.Function;
+import ghidra.program.model.listing.Program;
+import ghidra.util.table.ProgramLocationTableRowMapper;
+
+public class TextMatchToFunctionTableRowMapper
+ extends ProgramLocationTableRowMapper {
+
+ @Override
+ public Function map(TextMatch rowObject, Program data, ServiceProvider serviceProvider) {
+ return rowObject.getFunction();
+ }
+}
diff --git a/Ghidra/Features/DecompilerDependent/src/test/java/ghidra/app/plugin/core/string/variadic/FormatStringParserTest.java b/Ghidra/Features/DecompilerDependent/src/test/java/ghidra/app/plugin/core/string/variadic/FormatStringParserTest.java
index aff7b2564c..68a5664f35 100644
--- a/Ghidra/Features/DecompilerDependent/src/test/java/ghidra/app/plugin/core/string/variadic/FormatStringParserTest.java
+++ b/Ghidra/Features/DecompilerDependent/src/test/java/ghidra/app/plugin/core/string/variadic/FormatStringParserTest.java
@@ -4,9 +4,9 @@
* 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.
@@ -23,7 +23,8 @@ import org.junit.Before;
import org.junit.Test;
import generic.test.AbstractGenericTest;
-import ghidra.program.database.*;
+import ghidra.program.database.ProgramBuilder;
+import ghidra.program.database.ProgramDB;
import ghidra.program.database.data.ProgramDataTypeManager;
import ghidra.program.model.data.*;
@@ -81,14 +82,14 @@ public class FormatStringParserTest extends AbstractGenericTest {
runFormatTest("%d%hi", expectedTypes2, false);
DataType[] expectedTypes3 =
- { program.getDataTypeManager().getPointer(new PointerDataType(DataType.VOID)),
+ { program.getDataTypeManager().getPointer(new PointerDataType(VoidDataType.dataType)),
program.getDataTypeManager().getPointer(new CharDataType()) };
runFormatTest("%p%*d%s", expectedTypes3, false);
- DataType[] expectedTypes4 =
- { program.getDataTypeManager().getPointer(new LongDoubleDataType()),
- program.getDataTypeManager().getPointer(new CharDataType()),
- program.getDataTypeManager().getPointer(new PointerDataType(DataType.VOID)) };
+ DataType[] expectedTypes4 = {
+ program.getDataTypeManager().getPointer(new LongDoubleDataType()),
+ program.getDataTypeManager().getPointer(new CharDataType()),
+ program.getDataTypeManager().getPointer(new PointerDataType(VoidDataType.dataType)) };
runFormatTest("!:%12La%*d+=%2s%3p%*20d", expectedTypes4, false);
@@ -106,8 +107,8 @@ public class FormatStringParserTest extends AbstractGenericTest {
{ program.getDataTypeManager().getPointer(new CharDataType()), new LongDataType() };
runFormatTest("#thisisatest%+-4.12s%#.1lin\nd2", expectedTypes2, true);
- DataType[] expectedTypes3 = { new PointerDataType(DataType.VOID), new LongDoubleDataType(),
- new UnsignedCharDataType() };
+ DataType[] expectedTypes3 = { new PointerDataType(VoidDataType.dataType),
+ new LongDoubleDataType(), new UnsignedCharDataType() };
runFormatTest("%01.3pp%%%#1.2Lg%%%%%hhXxn2", expectedTypes3, true);
DataType[] expectedTypes4 = { new IntegerDataType(), new IntegerDataType(),
diff --git a/Ghidra/Framework/Docking/src/main/java/docking/action/DockingAction.java b/Ghidra/Framework/Docking/src/main/java/docking/action/DockingAction.java
index 8bd435c985..191a2ffc4e 100644
--- a/Ghidra/Framework/Docking/src/main/java/docking/action/DockingAction.java
+++ b/Ghidra/Framework/Docking/src/main/java/docking/action/DockingAction.java
@@ -4,9 +4,9 @@
* 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.
@@ -501,12 +501,18 @@ public abstract class DockingAction implements DockingActionIf {
// menu path
if (menuBarData != null) {
- buffer.append(" MENU PATH: ").append(
- menuBarData.getMenuPathAsString());
+ buffer.append(" MENU PATH: ")
+ .append(menuBarData.getMenuPathAsString());
buffer.append('\n');
buffer.append(" MENU GROUP: ").append(menuBarData.getMenuGroup());
buffer.append('\n');
+ String menuSubGroup = menuBarData.getMenuSubGroup();
+ if (menuSubGroup != null) {
+ buffer.append(" MENU SUB-GROUP: ").append(menuSubGroup);
+ buffer.append('\n');
+ }
+
String parentGroup = menuBarData.getParentMenuGroup();
if (parentGroup != null) {
buffer.append(" PARENT GROUP: ").append(parentGroup);
@@ -528,8 +534,8 @@ public abstract class DockingAction implements DockingActionIf {
// popup menu path
if (popupMenuData != null) {
- buffer.append(" POPUP PATH: ").append(
- popupMenuData.getMenuPathAsString());
+ buffer.append(" POPUP PATH: ")
+ .append(popupMenuData.getMenuPathAsString());
buffer.append('\n');
buffer.append(" POPUP GROUP: ").append(popupMenuData.getMenuGroup());
buffer.append('\n');
diff --git a/Ghidra/Framework/Generic/src/main/java/generic/json/Json.java b/Ghidra/Framework/Generic/src/main/java/generic/json/Json.java
index eadfecf2c9..263e1916fc 100644
--- a/Ghidra/Framework/Generic/src/main/java/generic/json/Json.java
+++ b/Ghidra/Framework/Generic/src/main/java/generic/json/Json.java
@@ -4,9 +4,9 @@
* 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.
@@ -15,8 +15,11 @@
*/
package generic.json;
+import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.util.Arrays;
+import java.util.Map;
+import java.util.stream.Collectors;
import org.apache.commons.lang3.builder.*;
@@ -135,16 +138,14 @@ public class Json extends ToStringStyle {
* @return the string
*/
public static String toStringExclude(Object o, String... excludedFields) {
- ReflectionToStringBuilder builder = new ReflectionToStringBuilder(o,
- Json.WITH_NEWLINES);
+ ReflectionToStringBuilder builder = new ReflectionToStringBuilder(o, Json.WITH_NEWLINES);
builder.setExcludeFieldNames(excludedFields);
return builder.toString();
}
- // Future: update this class to use the order of the included fields to be the printed ordered
private static class InclusiveReflectionToStringBuilder extends ReflectionToStringBuilder {
- private String[] includedNames;
+ private String[] includedNames = new String[0];
public InclusiveReflectionToStringBuilder(Object object) {
super(object, WITH_NEWLINES);
@@ -156,27 +157,73 @@ public class Json extends ToStringStyle {
return false;
}
- if (this.includedNames != null &&
- Arrays.binarySearch(this.includedNames, field.getName()) >= 0) {
- return true;
+ if (includedNames.length == 0) {
+ return true; // this implies a programming error
+ }
+
+ String fieldName = field.getName();
+ for (String name : includedNames) {
+ if (fieldName.equals(name)) {
+ return true;
+ }
}
return false;
}
+ // Overridden to control the order the field are listed. The parent class sorts by name; we
+ // want output in the order specified by the user.
+ @Override
+ protected void appendFieldsIn(final Class> clazz) {
+ if (clazz.isArray()) {
+ super.appendFieldsIn(clazz);
+ return;
+ }
+
+ if (includedNames.length == 0) {
+ super.appendFieldsIn(clazz);
+ return;
+ }
+
+ Field[] fields = clazz.getDeclaredFields();
+ AccessibleObject.setAccessible(fields, true);
+ Map fieldsByName =
+ Arrays.stream(fields).collect(Collectors.toMap(f -> f.getName(), f -> f));
+ for (String name : includedNames) {
+
+ Field field = fieldsByName.get(name);
+ if (field == null) {
+ continue;
+ }
+
+ if (accept(field)) {
+ try {
+ // Field.get(Object) creates wrappers objects for primitive types.
+ Object fieldValue = this.getValue(field);
+ if (!isExcludeNullValues() || fieldValue != null) {
+ this.append(name, fieldValue,
+ !field.isAnnotationPresent(ToStringSummary.class));
+ }
+ }
+ catch (IllegalAccessException ex) {
+ throw new InternalError(
+ "Unexpected IllegalAccessException: " + ex.getMessage());
+ }
+ }
+ }
+ }
+
/**
* Sets the names to be included
* @param includeFieldNamesParam the names
* @return this builder
*/
- public ReflectionToStringBuilder setIncludeFieldNames(
- final String... includeFieldNamesParam) {
+ public ReflectionToStringBuilder setIncludeFieldNames(String... includeFieldNamesParam) {
if (includeFieldNamesParam == null) {
- this.includedNames = null;
+ this.includedNames = new String[0];
}
else {
this.includedNames = includeFieldNamesParam;
- Arrays.sort(this.includedNames);
}
return this;
}
diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/Accumulator.java b/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/Accumulator.java
index 4f1058d614..0915871d53 100644
--- a/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/Accumulator.java
+++ b/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/Accumulator.java
@@ -4,9 +4,9 @@
* 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.
@@ -16,6 +16,7 @@
package ghidra.util.datastruct;
import java.util.Collection;
+import java.util.function.Consumer;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
@@ -31,7 +32,7 @@ import java.util.stream.StreamSupport;
*
* @param the type
*/
-public interface Accumulator extends Iterable {
+public interface Accumulator extends Iterable, Consumer {
public void add(T t);
@@ -50,4 +51,9 @@ public interface Accumulator extends Iterable {
default Stream stream() {
return StreamSupport.stream(spliterator(), false);
}
+
+ @Override
+ default void accept(T t) {
+ add(t);
+ }
}
diff --git a/Ghidra/Framework/Utility/src/main/java/ghidra/util/UserSearchUtils.java b/Ghidra/Framework/Utility/src/main/java/ghidra/util/UserSearchUtils.java
index 1913274ddc..fe7bc7cbb8 100644
--- a/Ghidra/Framework/Utility/src/main/java/ghidra/util/UserSearchUtils.java
+++ b/Ghidra/Framework/Utility/src/main/java/ghidra/util/UserSearchUtils.java
@@ -305,10 +305,11 @@ public class UserSearchUtils {
*/
private static String convertUserInputToRegex(String input, boolean allowGlobbing) {
- // Note: Order is important! (due to how escape characters added and checked)
- String escaped = escapeEscapeCharacters(input);
-
+ String escaped = input;
if (allowGlobbing) {
+
+ // Note: Order is important! (due to how escape characters added and checked)
+ escaped = escapeEscapeCharacters(input);
escaped = escapeNonGlobbingRegexCharacters(input);
escaped = convertGlobbingCharactersToRegex(escaped);
}
diff --git a/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/DecompilerTextFinderPluginScreenShots.java b/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/DecompilerTextFinderPluginScreenShots.java
new file mode 100644
index 0000000000..8421afc59e
--- /dev/null
+++ b/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/DecompilerTextFinderPluginScreenShots.java
@@ -0,0 +1,59 @@
+/* ###
+ * 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 help.screenshot;
+
+import org.junit.Test;
+
+import docking.action.DockingActionIf;
+import ghidra.app.plugin.core.search.DecompilerTextFinderDialog;
+import ghidra.app.plugin.core.search.TextMatch;
+import ghidra.app.plugin.core.table.TableComponentProvider;
+import ghidra.util.table.GhidraProgramTableModel;
+
+public class DecompilerTextFinderPluginScreenShots extends GhidraScreenShotGenerator {
+
+ @Test
+ public void testDecompilerTextFinderDialog() {
+
+ DockingActionIf action = getAction(tool, "Search Decompiled Text");
+ performAction(action, false);
+ captureDialog();
+ closeAllWindows();
+ }
+
+ @Test
+ public void testDecompilerTextFinderResultsTable() {
+
+ DockingActionIf action = getAction(tool, "Search Decompiled Text");
+ performAction(action, false);
+ DecompilerTextFinderDialog searchDialog =
+ waitForDialogComponent(DecompilerTextFinderDialog.class);
+
+ String searchText = " = '\\0'";
+ runSwing(() -> searchDialog.setSearchText(searchText));
+ pressButtonByText(searchDialog, "Search", false);
+
+ @SuppressWarnings("unchecked")
+ TableComponentProvider tableProvider =
+ waitForComponentProvider(TableComponentProvider.class);
+ GhidraProgramTableModel model = tableProvider.getModel();
+ waitForTableModel(model);
+
+ // TOD capture entire window?
+ captureProvider(tableProvider);
+ close(searchDialog);
+ }
+}