diff --git a/Ghidra/Debug/Debugger-agent-dbgmodel-traceloader/ghidra_scripts/BangAddressToMemory.java b/Ghidra/Debug/Debugger-agent-dbgmodel-traceloader/ghidra_scripts/BangAddressToMemory.java index f9ab0962db..54466e115d 100644 --- a/Ghidra/Debug/Debugger-agent-dbgmodel-traceloader/ghidra_scripts/BangAddressToMemory.java +++ b/Ghidra/Debug/Debugger-agent-dbgmodel-traceloader/ghidra_scripts/BangAddressToMemory.java @@ -34,7 +34,7 @@ import ghidra.util.database.UndoableTransaction; import ghidra.util.exception.DuplicateNameException; /** - * This script populates a trace database with memory derived from "!address". This is particularly + * This script populates a trace database with memory derived from "!address". This is particularly * useful for dump files and other cases where QueryVirtual fails. * *

@@ -64,7 +64,6 @@ public class BangAddressToMemory extends GhidraScript { private AddressSpace defaultSpace; - private DebuggerModelService modelService; private DebuggerTraceManagerService managerService; @@ -96,7 +95,7 @@ public class BangAddressToMemory extends GhidraScript { if (modelService == null) { throw new RuntimeException("Unable to find DebuggerMemviewPlugin"); } - + DebuggerObjectModel model = modelService.getCurrentModel(); if (!(model instanceof AbstractDbgModel)) { throw new RuntimeException("Current model must be an AbstractDbgModel"); @@ -111,7 +110,7 @@ public class BangAddressToMemory extends GhidraScript { throw new RuntimeException("Script requires an active trace"); } memory = trace.getMemoryManager(); - + lang = currentProgram.getLanguage(); defaultSpace = lang.getAddressFactory().getDefaultAddressSpace(); @@ -121,7 +120,7 @@ public class BangAddressToMemory extends GhidraScript { } private void parse(String result) { - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Populate memory", true); + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Populate memory"); LockHold hold = trace.lockWrite();) { //Pattern pattern = Pattern.compile("\\s+(*)\\s+(*)\\s+"); //Matcher matcher = pattern.matcher(fullclassname); @@ -149,7 +148,7 @@ public class BangAddressToMemory extends GhidraScript { try { TraceMemoryRegion region = memory.addRegion(startStr, Range.atLeast(0L), rng, TraceMemoryFlag.READ, - TraceMemoryFlag.WRITE, TraceMemoryFlag.EXECUTE); + TraceMemoryFlag.WRITE, TraceMemoryFlag.EXECUTE); region.setName(name); } catch (TraceOverlappedRegionException | DuplicateNameException e) { diff --git a/Ghidra/Debug/Debugger-agent-dbgmodel-traceloader/ghidra_scripts/PopulateTraceLocal.java b/Ghidra/Debug/Debugger-agent-dbgmodel-traceloader/ghidra_scripts/PopulateTraceLocal.java index e4fc8ab489..2789664944 100644 --- a/Ghidra/Debug/Debugger-agent-dbgmodel-traceloader/ghidra_scripts/PopulateTraceLocal.java +++ b/Ghidra/Debug/Debugger-agent-dbgmodel-traceloader/ghidra_scripts/PopulateTraceLocal.java @@ -191,7 +191,7 @@ public class PopulateTraceLocal extends GhidraScript { control.waitForEvent(); try (UndoableTransaction tid = - UndoableTransaction.start(trace, "Populate Events", true)) { + UndoableTransaction.start(trace, "Populate Events")) { List children = util.getElements(List.of("Debugger", "State", "DebuggerVariables", "curprocess", @@ -284,7 +284,7 @@ public class PopulateTraceLocal extends GhidraScript { } try (UndoableTransaction tid = - UndoableTransaction.start(trace, "Populate Registers", true)) { + UndoableTransaction.start(trace, "Populate Registers")) { //for (Long tick : tickManager.getAllTicks()) { for (Long snap : eventSnaps) { control.execute("!tt " + Long.toHexString(snap) + ":0"); diff --git a/Ghidra/Debug/Debugger-agent-dbgmodel-traceloader/ghidra_scripts/PopulateTraceRemote.java b/Ghidra/Debug/Debugger-agent-dbgmodel-traceloader/ghidra_scripts/PopulateTraceRemote.java index 9290cf3029..3d60abb685 100644 --- a/Ghidra/Debug/Debugger-agent-dbgmodel-traceloader/ghidra_scripts/PopulateTraceRemote.java +++ b/Ghidra/Debug/Debugger-agent-dbgmodel-traceloader/ghidra_scripts/PopulateTraceRemote.java @@ -151,7 +151,7 @@ public class PopulateTraceRemote extends GhidraScript { manager = tool.getService(DebuggerTraceManagerService.class); targets = tool.getService(DebuggerModelService.class); - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Populate Events", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Populate Events")) { timeManager = trace.getTimeManager(); timeManager.createSnapshot("init"); } diff --git a/Ghidra/Debug/Debugger/ghidra_scripts/DebuggerEmuExampleScript.java b/Ghidra/Debug/Debugger/ghidra_scripts/DebuggerEmuExampleScript.java index 8ff1d657f2..e8b432f71e 100644 --- a/Ghidra/Debug/Debugger/ghidra_scripts/DebuggerEmuExampleScript.java +++ b/Ghidra/Debug/Debugger/ghidra_scripts/DebuggerEmuExampleScript.java @@ -81,7 +81,7 @@ public class DebuggerEmuExampleScript extends GhidraScript { .getProjectData() .getRootFolder() .createFile("emu_example", program, monitor); - try (UndoableTransaction tid = UndoableTransaction.start(program, "Init", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Init")) { AddressSpace space = program.getAddressFactory().getDefaultAddressSpace(); entry = space.getAddress(0x00400000); Address dataEntry = space.getAddress(0x00600000); @@ -163,7 +163,7 @@ public class DebuggerEmuExampleScript extends GhidraScript { */ TraceTimeManager time = trace.getTimeManager(); TraceSnapshot snapshot = time.getSnapshot(0, true); - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Emulate", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Emulate")) { for (int i = 0; i < 10; i++) { println("Executing: " + thread.getCounter()); thread.stepInstruction(); diff --git a/Ghidra/Debug/Debugger/ghidra_scripts/PopulateDemoTrace.java b/Ghidra/Debug/Debugger/ghidra_scripts/PopulateDemoTrace.java index 475f58764e..abf0658307 100644 --- a/Ghidra/Debug/Debugger/ghidra_scripts/PopulateDemoTrace.java +++ b/Ghidra/Debug/Debugger/ghidra_scripts/PopulateDemoTrace.java @@ -295,7 +295,7 @@ public class PopulateDemoTrace extends GhidraScript { * object. */ try (UndoableTransaction tid = - UndoableTransaction.start(trace, "Populate First Snapshot", true)) { + UndoableTransaction.start(trace, "Populate First Snapshot")) { /** * While not strictly required, each tick should be explicitly added to the database and * given a description. Some things may mis-behave if there does not exist at least one @@ -439,7 +439,7 @@ public class PopulateDemoTrace extends GhidraScript { /** * Just hand emulate the stepping */ - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step")) { long snap = trace.getTimeManager().createSnapshot("Stepped: PUSH RBP").getKey(); stack1offset -= 8; @@ -466,7 +466,7 @@ public class PopulateDemoTrace extends GhidraScript { /** * More hand emulation */ - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step")) { long snap = trace.getTimeManager().createSnapshot("Stepped: MOV RBP,RSP").getKey(); putRIP(snap, regs1, mainInstructions.get(++pc1)); @@ -482,7 +482,7 @@ public class PopulateDemoTrace extends GhidraScript { * While this is a complicated call, there is nothing new to demonstrate in its * implementation. As an exercise, see if you can follow what is happening within. */ - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step")) { long snap = trace.getTimeManager() .createSnapshot("Stepped Thread 1: CALL clone -> Thread 2") .getKey(); @@ -520,7 +520,7 @@ public class PopulateDemoTrace extends GhidraScript { /** * Hand emulate thread1 a few steps */ - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step")) { long snap = trace.getTimeManager().createSnapshot("Stepped Thread 1: RET from clone").getKey(); @@ -535,7 +535,7 @@ public class PopulateDemoTrace extends GhidraScript { /** * ... */ - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step")) { long snap = trace.getTimeManager().createSnapshot("Stepped Thread 1: TEST EAX,EAX").getKey(); @@ -545,7 +545,7 @@ public class PopulateDemoTrace extends GhidraScript { placeRegUnits(snap, thread1); } - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step")) { long snap = trace.getTimeManager().createSnapshot("Stepped Thread 1: JNZ child").getKey(); @@ -557,7 +557,7 @@ public class PopulateDemoTrace extends GhidraScript { /** * Switch to thread2 */ - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step")) { long snap = trace.getTimeManager().createSnapshot("Stepped Thread 2: RET from clone").getKey(); @@ -569,7 +569,7 @@ public class PopulateDemoTrace extends GhidraScript { placeRegUnits(snap, thread2); } - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step")) { long snap = trace.getTimeManager().createSnapshot("Stepped Thread 2: TEST EAX,EAX").getKey(); @@ -579,7 +579,7 @@ public class PopulateDemoTrace extends GhidraScript { placeRegUnits(snap, thread2); } - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step")) { long snap = trace.getTimeManager().createSnapshot("Stepped Thread 2: JNZ child").getKey(); @@ -591,7 +591,7 @@ public class PopulateDemoTrace extends GhidraScript { /** * Switch to thread1 */ - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step")) { long snap = trace.getTimeManager().createSnapshot("Stepped Thread 1: SUB RSP,0x10").getKey(); @@ -603,7 +603,7 @@ public class PopulateDemoTrace extends GhidraScript { placeRegUnits(snap, thread1); } - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step")) { long snap = trace.getTimeManager().createSnapshot("Stepped Thread 1: MOV...(1)").getKey(); @@ -614,7 +614,7 @@ public class PopulateDemoTrace extends GhidraScript { placeRegUnits(snap, thread1); } - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step")) { long snap = trace.getTimeManager().createSnapshot("Stepped Thread 1: MOV...(2)").getKey(); @@ -625,7 +625,7 @@ public class PopulateDemoTrace extends GhidraScript { placeRegUnits(snap, thread1); } - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step")) { long snap = trace.getTimeManager().createSnapshot("Stepped Thread 1: MOV...(3)").getKey(); @@ -636,7 +636,7 @@ public class PopulateDemoTrace extends GhidraScript { placeRegUnits(snap, thread1); } - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step")) { long snap = trace.getTimeManager().createSnapshot("Stepped Thread 1: MOV...(4)").getKey(); @@ -650,7 +650,7 @@ public class PopulateDemoTrace extends GhidraScript { /** * Switch to thread2 */ - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step")) { long snap = trace.getTimeManager().createSnapshot("Stepped Thread 2: SUB RSP,0x10").getKey(); @@ -662,7 +662,7 @@ public class PopulateDemoTrace extends GhidraScript { placeRegUnits(snap, thread2); } - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step")) { long snap = trace.getTimeManager().createSnapshot("Stepped Thread 2: MOV...(1)").getKey(); @@ -673,7 +673,7 @@ public class PopulateDemoTrace extends GhidraScript { placeRegUnits(snap, thread2); } - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step")) { long snap = trace.getTimeManager().createSnapshot("Stepped Thread 2: MOV...(2)").getKey(); @@ -684,7 +684,7 @@ public class PopulateDemoTrace extends GhidraScript { placeRegUnits(snap, thread2); } - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step")) { long snap = trace.getTimeManager().createSnapshot("Stepped Thread 2: MOV...(3)").getKey(); @@ -698,7 +698,7 @@ public class PopulateDemoTrace extends GhidraScript { /** * Let thread2 exit first */ - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step")) { long snap = trace.getTimeManager().createSnapshot("Stepped Thread 2: CALL exit").getKey(); @@ -708,7 +708,7 @@ public class PopulateDemoTrace extends GhidraScript { /** * Terminate */ - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Step")) { long snap = trace.getTimeManager().createSnapshot("Stepped Thread 1: CALL exit").getKey(); diff --git a/Ghidra/Debug/Debugger/ghidra_scripts/StandAloneSyscallEmuExampleScript.java b/Ghidra/Debug/Debugger/ghidra_scripts/StandAloneSyscallEmuExampleScript.java index 0236347e74..3c5fa8e464 100644 --- a/Ghidra/Debug/Debugger/ghidra_scripts/StandAloneSyscallEmuExampleScript.java +++ b/Ghidra/Debug/Debugger/ghidra_scripts/StandAloneSyscallEmuExampleScript.java @@ -70,7 +70,7 @@ public class StandAloneSyscallEmuExampleScript extends GhidraScript { program = new ProgramDB("syscall_example", language, language.getCompilerSpecByID(new CompilerSpecID("gcc")), this); - try (UndoableTransaction tid = UndoableTransaction.start(program, "Init", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Init")) { AddressSpace space = program.getAddressFactory().getDefaultAddressSpace(); entry = space.getAddress(0x00400000); Address dataEntry = space.getAddress(0x00600000); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/BreakpointLocationRow.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/BreakpointLocationRow.java index 796c32a484..d9e7758e17 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/BreakpointLocationRow.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/BreakpointLocationRow.java @@ -74,7 +74,7 @@ public class BreakpointLocationRow { public void setName(String name) { try (UndoableTransaction tid = - UndoableTransaction.start(loc.getTrace(), "Set breakpoint name", true)) { + UndoableTransaction.start(loc.getTrace(), "Set breakpoint name")) { loc.setName(name); } } @@ -101,7 +101,7 @@ public class BreakpointLocationRow { public void setComment(String comment) { try (UndoableTransaction tid = - UndoableTransaction.start(loc.getTrace(), "Set breakpoint comment", true)) { + UndoableTransaction.start(loc.getTrace(), "Set breakpoint comment")) { loc.setComment(comment); } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyIntoProgramDialog.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyIntoProgramDialog.java index dc86cd230a..27b82790d1 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyIntoProgramDialog.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyIntoProgramDialog.java @@ -830,7 +830,7 @@ public class DebuggerCopyIntoProgramDialog extends DialogComponentProvider { Program dest = getDestination().getOrCreateProgram(source, this); boolean doRelease = !Arrays.asList(programManager.getAllOpenPrograms()).contains(dest); TraceRecorder recorder = getRecorderIfEnabledAndReadsPresent(); - try (UndoableTransaction tid = UndoableTransaction.start(dest, "Copy From Trace", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(dest, "Copy From Trace")) { monitor.initialize(tableModel.getRowCount()); for (RangeEntry entry : tableModel.getModelData()) { monitor.setMessage("Copying into " + entry.getDstRange()); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/RegionRow.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/RegionRow.java index 409668d7cf..165b1da59a 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/RegionRow.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/memory/RegionRow.java @@ -35,9 +35,8 @@ public class RegionRow { public void setName(String name) { try (UndoableTransaction tid = - UndoableTransaction.start(region.getTrace(), "Renamed region", true)) { + UndoableTransaction.start(region.getTrace(), "Rename region")) { region.setName(name); - tid.commit(); } } @@ -76,7 +75,7 @@ public class RegionRow { public void setRead(boolean read) { try (UndoableTransaction tid = - UndoableTransaction.start(region.getTrace(), "Toggle region read flag", true)) { + UndoableTransaction.start(region.getTrace(), "Toggle region read flag")) { region.setRead(read); } } @@ -87,7 +86,7 @@ public class RegionRow { public void setWrite(boolean write) { try (UndoableTransaction tid = - UndoableTransaction.start(region.getTrace(), "Toggle region write flag", true)) { + UndoableTransaction.start(region.getTrace(), "Toggle region write flag")) { region.setWrite(write); } } @@ -98,7 +97,7 @@ public class RegionRow { public void setExecute(boolean execute) { try (UndoableTransaction tid = - UndoableTransaction.start(region.getTrace(), "Toggle region execute flag", true)) { + UndoableTransaction.start(region.getTrace(), "Toggle region execute flag")) { region.setExecute(execute); } } @@ -109,7 +108,7 @@ public class RegionRow { public void setVolatile(boolean vol) { try (UndoableTransaction tid = - UndoableTransaction.start(region.getTrace(), "Toggle region volatile flag", true)) { + UndoableTransaction.start(region.getTrace(), "Toggle region volatile flag")) { region.setVolatile(vol); } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerStaticMappingProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerStaticMappingProvider.java index b6b604c5e5..ce3ab2cc88 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerStaticMappingProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerStaticMappingProvider.java @@ -303,12 +303,10 @@ public class DebuggerStaticMappingProvider extends ComponentProviderAdapter // TODO: Action to adjust life span? // Note: provider displays mappings for all time, so delete means delete, not truncate try (UndoableTransaction tid = - UndoableTransaction.start(currentTrace, "Remove Static Mappings", false)) { + UndoableTransaction.start(currentTrace, "Remove Static Mappings")) { for (StaticMappingRow mapping : ctx.getSelectedMappings()) { mapping.getMapping().delete(); } - // TODO: Do I want all-or-nothing among all transactions? - tid.commit(); } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/ModuleRow.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/ModuleRow.java index 8ac71b20f3..0e572c63b5 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/ModuleRow.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/ModuleRow.java @@ -34,7 +34,7 @@ public class ModuleRow { public void setName(String name) { try (UndoableTransaction tid = - UndoableTransaction.start(module.getTrace(), "Renamed module", true)) { + UndoableTransaction.start(module.getTrace(), "Renamed module")) { module.setName(name); } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/SectionRow.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/SectionRow.java index 68bb173749..e627a02890 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/SectionRow.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/modules/SectionRow.java @@ -42,7 +42,7 @@ public class SectionRow { public void setName(String name) { try (UndoableTransaction tid = - UndoableTransaction.start(section.getTrace(), "Renamed section", true)) { + UndoableTransaction.start(section.getTrace(), "Rename section")) { section.setName(name); } catch (DuplicateNameException e) { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/pcode/DebuggerPcodeStepperProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/pcode/DebuggerPcodeStepperProvider.java index 53ee769550..ac863b1348 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/pcode/DebuggerPcodeStepperProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/pcode/DebuggerPcodeStepperProvider.java @@ -229,7 +229,7 @@ public class DebuggerPcodeStepperProvider extends ComponentProviderAdapter { return null; } try (UndoableTransaction tid = - UndoableTransaction.start(current.getTrace(), "Resolve DataType", true)) { + UndoableTransaction.start(current.getTrace(), "Resolve DataType")) { return current.getTrace().getDataTypeManager().resolve(dataType, null); } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/register/DebuggerRegistersProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/register/DebuggerRegistersProvider.java index 5ba13f399b..d5cc6640f7 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/register/DebuggerRegistersProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/register/DebuggerRegistersProvider.java @@ -367,7 +367,7 @@ public class DebuggerRegistersProvider extends ComponentProviderAdapter return null; } try (UndoableTransaction tid = - UndoableTransaction.start(currentTrace, "Resolve DataType", true)) { + UndoableTransaction.start(currentTrace, "Resolve DataType")) { return currentTrace.getDataTypeManager().resolve(dataType, null); } } @@ -832,14 +832,13 @@ public class DebuggerRegistersProvider extends ComponentProviderAdapter */ void writeRegisterDataType(Register register, DataType dataType) { try (UndoableTransaction tid = - UndoableTransaction.start(current.getTrace(), "Edit Register Type", false)) { + UndoableTransaction.start(current.getTrace(), "Edit Register Type")) { TraceCodeRegisterSpace space = getRegisterMemorySpace(true).getCodeSpace(true); long snap = current.getViewSnap(); space.definedUnits().clear(Range.closed(snap, snap), register, TaskMonitor.DUMMY); if (dataType != null) { space.definedData().create(Range.atLeast(snap), register, dataType); } - tid.commit(); } catch (CodeUnitInsertionException | CancelledException e) { throw new AssertionError(e); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/stack/StackFrameRow.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/stack/StackFrameRow.java index 24794c177f..e45472f7f2 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/stack/StackFrameRow.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/stack/StackFrameRow.java @@ -79,8 +79,8 @@ public class StackFrameRow { } public void setComment(String comment) { - try (UndoableTransaction tid = UndoableTransaction - .start(frame.getStack().getThread().getTrace(), "Frame comment", true)) { + try (UndoableTransaction tid = + UndoableTransaction.start(frame.getStack().getThread().getTrace(), "Frame comment")) { frame.setComment(getSnap(), comment); } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/thread/ThreadRow.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/thread/ThreadRow.java index e52fc64df9..64ba50122b 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/thread/ThreadRow.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/thread/ThreadRow.java @@ -44,7 +44,7 @@ public class ThreadRow { public void setName(String name) { try (UndoableTransaction tid = - UndoableTransaction.start(thread.getTrace(), "Renamed thread", true)) { + UndoableTransaction.start(thread.getTrace(), "Rename thread")) { thread.setName(name); } } @@ -69,7 +69,7 @@ public class ThreadRow { public void setComment(String comment) { try (UndoableTransaction tid = - UndoableTransaction.start(thread.getTrace(), "Renamed thread", true)) { + UndoableTransaction.start(thread.getTrace(), "Rename thread")) { thread.setComment(comment); } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/time/DebuggerTimePlugin.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/time/DebuggerTimePlugin.java index 8d42bcf254..7d6d09dc7c 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/time/DebuggerTimePlugin.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/time/DebuggerTimePlugin.java @@ -112,7 +112,7 @@ public class DebuggerTimePlugin extends AbstractDebuggerPlugin { if (dialog.isCanceled()) { return; } - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Rename Snapshot", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Rename Snapshot")) { if (snapshot == null) { snapshot = manager.getSnapshot(snap, true); } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/time/SnapshotRow.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/time/SnapshotRow.java index 3c6d8d3d66..24d28bf6be 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/time/SnapshotRow.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/time/SnapshotRow.java @@ -61,9 +61,8 @@ public class SnapshotRow { public void setDescription(String description) { try (UndoableTransaction tid = - UndoableTransaction.start(trace, "Modify snapshot description", false)) { + UndoableTransaction.start(trace, "Modify snapshot description")) { snapshot.setDescription(description); - tid.commit(); } } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/watch/DebuggerWatchesProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/watch/DebuggerWatchesProvider.java index 27186b9a49..17024a9b69 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/watch/DebuggerWatchesProvider.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/watch/DebuggerWatchesProvider.java @@ -208,7 +208,7 @@ public class DebuggerWatchesProvider extends ComponentProviderAdapter { return null; } try (UndoableTransaction tid = - UndoableTransaction.start(currentTrace, "Resolve DataType", true)) { + UndoableTransaction.start(currentTrace, "Resolve DataType")) { return currentTrace.getDataTypeManager().resolve(dataType, null); } } @@ -523,7 +523,7 @@ public class DebuggerWatchesProvider extends ComponentProviderAdapter { } } try (UndoableTransaction tid = - UndoableTransaction.start(current.getTrace(), "Apply Watch Data Type", true)) { + UndoableTransaction.start(current.getTrace(), "Apply Watch Data Type")) { try { listing.clearCodeUnits(row.getAddress(), row.getRange().getMaxAddress(), false); listing.createData(address, dataType, size); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/DefaultDebuggerPlatformMapper.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/DefaultDebuggerPlatformMapper.java index c78382eac4..3296e282bb 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/DefaultDebuggerPlatformMapper.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/DefaultDebuggerPlatformMapper.java @@ -54,9 +54,9 @@ public class DefaultDebuggerPlatformMapper extends AbstractDebuggerPlatformMappe @Override public void addToTrace(long snap) { - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Add guest " + - cSpec.getLanguage().getLanguageDescription() + "/" + cSpec.getCompilerSpecDescription(), - true)) { + String description = "Add guest " + cSpec.getLanguage().getLanguageDescription() + "/" + + cSpec.getCompilerSpecDescription(); + try (UndoableTransaction tid = UndoableTransaction.start(trace, description)) { TracePlatformManager platformManager = trace.getPlatformManager(); TracePlatform platform = platformManager.getOrAddPlatform(cSpec); if (platform.isHost()) { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/ObjectBasedDebuggerMemoryMapper.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/ObjectBasedDebuggerMemoryMapper.java index 23f96de056..6cefd90d21 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/ObjectBasedDebuggerMemoryMapper.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/mapping/ObjectBasedDebuggerMemoryMapper.java @@ -72,7 +72,7 @@ public class ObjectBasedDebuggerMemoryMapper implements DebuggerMemoryMapper { protected AddressSpace createSpace(String name) { try (UndoableTransaction tid = - UndoableTransaction.start(trace, "Create space for mapping", true)) { + UndoableTransaction.start(trace, "Create space for mapping")) { AddressFactory factory = trace.getBaseAddressFactory(); AddressSpace space = factory.getAddressSpace(name); if (space == null) { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/LogicalBreakpointInternal.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/LogicalBreakpointInternal.java index e8ad84b19d..64900ff352 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/LogicalBreakpointInternal.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/breakpoint/LogicalBreakpointInternal.java @@ -128,9 +128,8 @@ public interface LogicalBreakpointInternal extends LogicalBreakpoint { throw new IllegalStateException("Must save breakpoint to program before naming it"); } try (UndoableTransaction tid = - UndoableTransaction.start(program, "Rename breakpoint", false)) { + UndoableTransaction.start(program, "Rename breakpoint")) { bookmark.set(bookmark.getCategory(), name); - tid.commit(); } } @@ -154,8 +153,7 @@ public interface LogicalBreakpointInternal extends LogicalBreakpoint { // volatile reads Bookmark eBookmark = this.eBookmark; Bookmark dBookmark = this.dBookmark; - try (UndoableTransaction tid = - UndoableTransaction.start(program, "Clear breakpoint", false)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Clear breakpoint")) { BookmarkManager bookmarkManager = program.getBookmarkManager(); if (eBookmark != null) { bookmarkManager.removeBookmark(eBookmark); @@ -165,7 +163,6 @@ public interface LogicalBreakpointInternal extends LogicalBreakpoint { } // (e,d)Bookmark Gets nulled on program change callback // If null here, logical breakpoint manager will get confused - tid.commit(); } } @@ -250,7 +247,7 @@ public interface LogicalBreakpointInternal extends LogicalBreakpoint { String delType = enabled ? BREAKPOINT_DISABLED_BOOKMARK_TYPE : BREAKPOINT_ENABLED_BOOKMARK_TYPE; try (UndoableTransaction tid = - UndoableTransaction.start(program, "Enable breakpoint", true)) { + UndoableTransaction.start(program, "Enable breakpoint")) { BookmarkManager manager = program.getBookmarkManager(); String catStr = computeCategory(); manager.setBookmark(address, addType, catStr, comment); diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/editing/DebuggerStateEditingServicePlugin.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/editing/DebuggerStateEditingServicePlugin.java index aad9720ad1..a547cb4e4a 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/editing/DebuggerStateEditingServicePlugin.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/editing/DebuggerStateEditingServicePlugin.java @@ -156,7 +156,7 @@ public class DebuggerStateEditingServicePlugin extends AbstractDebuggerPlugin long snap = coordinates.getViewSnap(); TraceMemoryOperations memOrRegs; try (UndoableTransaction txid = - UndoableTransaction.start(trace, "Edit Variable", true)) { + UndoableTransaction.start(trace, "Edit Variable")) { if (address.isRegisterAddress()) { TraceThread thread = coordinates.getThread(); if (thread == null) { diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/AbstractReadsTargetPcodeExecutorState.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/AbstractReadsTargetPcodeExecutorState.java index a533a9fd41..b0749d842c 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/AbstractReadsTargetPcodeExecutorState.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/AbstractReadsTargetPcodeExecutorState.java @@ -105,7 +105,7 @@ public abstract class AbstractReadsTargetPcodeExecutorState } else { try (UndoableTransaction tid = - UndoableTransaction.start(trace, "Create space", true)) { + UndoableTransaction.start(trace, "Create space")) { tms = TraceSleighUtils.getSpaceForExecution(s, trace, thread, frame, true); } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/DebuggerEmulationServicePlugin.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/DebuggerEmulationServicePlugin.java index 0befa08c22..f30e00fa48 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/DebuggerEmulationServicePlugin.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/DebuggerEmulationServicePlugin.java @@ -403,7 +403,7 @@ public class DebuggerEmulationServicePlugin extends Plugin implements DebuggerEm time.execute(trace, emu, monitor); } TraceSnapshot destSnap; - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Emulate", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Emulate")) { destSnap = findScratch(trace, time); emu.writeDown(trace, destSnap.getKey(), time.getSnap(), false); } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/ProgramEmulationUtils.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/ProgramEmulationUtils.java index 60f1f67c54..a4d469372a 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/ProgramEmulationUtils.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/ProgramEmulationUtils.java @@ -293,13 +293,12 @@ public enum ProgramEmulationUtils { boolean success = false; try { trace = new DBTrace(getTraceName(program), program.getCompilerSpec(), consumer); - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Emulate", false)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Emulate")) { TraceSnapshot initial = trace.getTimeManager().createSnapshot(EMULATION_STARTED_AT + pc); long snap = initial.getKey(); loadExecutable(initial, program); doLaunchEmulationThread(trace, snap, program, pc, pc); - tid.commit(); } success = true; return trace; @@ -339,9 +338,8 @@ public enum ProgramEmulationUtils { public static TraceThread launchEmulationThread(Trace trace, long snap, Program program, Address tracePc, Address programPc) { try (UndoableTransaction tid = - UndoableTransaction.start(trace, "Emulate new Thread", false)) { + UndoableTransaction.start(trace, "Emulate new Thread")) { TraceThread thread = doLaunchEmulationThread(trace, snap, program, tracePc, programPc); - tid.commit(); return thread; } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/RecorderPermanentTransaction.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/RecorderPermanentTransaction.java index 30cd7a5b23..1404f27400 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/RecorderPermanentTransaction.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/RecorderPermanentTransaction.java @@ -21,7 +21,7 @@ import ghidra.util.database.UndoableTransaction; public class RecorderPermanentTransaction implements AutoCloseable { public static RecorderPermanentTransaction start(UndoableDomainObject obj, String description) { - UndoableTransaction tid = UndoableTransaction.start(obj, description, true); + UndoableTransaction tid = UndoableTransaction.start(obj, description); return new RecorderPermanentTransaction(obj, tid); } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/TraceObjectManager.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/TraceObjectManager.java index f4b6cfca96..2218f01f6f 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/TraceObjectManager.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/TraceObjectManager.java @@ -255,7 +255,7 @@ public class TraceObjectManager { TraceThread traceThread = threadRecorder.getTraceThread(); recorder.createSnapshot(traceThread + " started", traceThread, null); try (UndoableTransaction tid = - UndoableTransaction.start(recorder.getTrace(), "Adjust thread creation", true)) { + UndoableTransaction.start(recorder.getTrace(), "Adjust thread creation")) { long existing = traceThread.getCreationSnap(); if (existing == Long.MIN_VALUE) { traceThread.setCreationSnap(recorder.getSnap()); @@ -545,7 +545,7 @@ public class TraceObjectManager { if (rec != null) { String name = (String) added.get(TargetObject.DISPLAY_ATTRIBUTE_NAME); try (UndoableTransaction tid = - UndoableTransaction.start(rec.getTrace(), "Renamed thread", true)) { + UndoableTransaction.start(rec.getTrace(), "Rename thread")) { rec.getTraceThread().setName(name); } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/record/ObjectBasedTraceRecorder.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/record/ObjectBasedTraceRecorder.java index d307a50da0..f21ce99aee 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/record/ObjectBasedTraceRecorder.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/record/ObjectBasedTraceRecorder.java @@ -189,7 +189,7 @@ public class ObjectBasedTraceRecorder implements TraceRecorder { String path = object.getJoinedPath("."); // Don't offload, because we need a consistent map try (UndoableTransaction tid = - UndoableTransaction.start(trace, "Object created: " + path, true)) { + UndoableTransaction.start(trace, "Object created: " + path)) { objectRecorder.recordCreated(snap, object); } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/record/ObjectRecorder.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/record/ObjectRecorder.java index f93e634099..b9fc94d191 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/record/ObjectRecorder.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/model/record/ObjectRecorder.java @@ -61,7 +61,7 @@ class ObjectRecorder { this.isSupportsFocus = !schema.searchFor(TargetFocusScope.class, false).isEmpty(); try (UndoableTransaction tid = - UndoableTransaction.start(recorder.trace, "Create root", true)) { + UndoableTransaction.start(recorder.trace, "Create root")) { objectManager.createRootObject(schema); } } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingServicePlugin.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingServicePlugin.java index 64f8979933..df87d472c7 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingServicePlugin.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingServicePlugin.java @@ -730,7 +730,7 @@ public class DebuggerStaticMappingServicePlugin extends Plugin public void addMapping(TraceLocation from, ProgramLocation to, long length, boolean truncateExisting) throws TraceConflictedMappingException { try (UndoableTransaction tid = - UndoableTransaction.start(from.getTrace(), "Add mapping", true)) { + UndoableTransaction.start(from.getTrace(), "Add mapping")) { DebuggerStaticMappingUtils.addMapping(from, to, length, truncateExisting); } } @@ -739,7 +739,7 @@ public class DebuggerStaticMappingServicePlugin extends Plugin public void addMapping(MapEntry entry, boolean truncateExisting) throws TraceConflictedMappingException { try (UndoableTransaction tid = - UndoableTransaction.start(entry.getFromTrace(), "Add mapping", true)) { + UndoableTransaction.start(entry.getFromTrace(), "Add mapping")) { DebuggerStaticMappingUtils.addMapping(entry, truncateExisting); } } @@ -751,8 +751,7 @@ public class DebuggerStaticMappingServicePlugin extends Plugin entries.stream().collect(Collectors.groupingBy(ent -> ent.getFromTrace())); for (Map.Entry>> ent : byTrace.entrySet()) { Trace trace = ent.getKey(); - try (UndoableTransaction tid = - UndoableTransaction.start(trace, description, true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, description)) { doAddMappings(trace, ent.getValue(), monitor, truncateExisting); } } @@ -776,7 +775,7 @@ public class DebuggerStaticMappingServicePlugin extends Plugin public void addIdentityMapping(Trace from, Program toProgram, Range lifespan, boolean truncateExisting) { try (UndoableTransaction tid = - UndoableTransaction.start(from, "Add identity mappings", true)) { + UndoableTransaction.start(from, "Add identity mappings")) { DebuggerStaticMappingUtils.addIdentityMapping(from, toProgram, lifespan, truncateExisting); } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/workflow/DisassembleAtPcDebuggerBot.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/workflow/DisassembleAtPcDebuggerBot.java index 8130f49b1e..5b806d63fd 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/workflow/DisassembleAtPcDebuggerBot.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/workflow/DisassembleAtPcDebuggerBot.java @@ -226,7 +226,7 @@ public class DisassembleAtPcDebuggerBot implements DebuggerBot { } TraceData pcUnit = null; try (UndoableTransaction tid = - UndoableTransaction.start(trace, "Disassemble: PC is code pointer", true)) { + UndoableTransaction.start(trace, "Disassemble: PC is code pointer")) { TraceCodeRegisterSpace regCode = codeManager.getCodeRegisterSpace(thread, frameLevel, true); try { diff --git a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointMarkerPluginScreenShots.java b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointMarkerPluginScreenShots.java index 790667fded..5e02f231e0 100644 --- a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointMarkerPluginScreenShots.java +++ b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointMarkerPluginScreenShots.java @@ -98,7 +98,7 @@ public class DebuggerBreakpointMarkerPluginScreenShots extends GhidraScreenShotG .getRootFolder() .createFile("WinHelloCPP", program, TaskMonitor.DUMMY); - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Add Mapping", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Add Mapping")) { mappingService.addIdentityMapping(trace, program, Range.atLeast(0L), true); } waitForValue(() -> mappingService.getOpenMappedLocation( diff --git a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsPluginScreenShots.java b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsPluginScreenShots.java index 145dd242ef..8d47583e96 100644 --- a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsPluginScreenShots.java +++ b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsPluginScreenShots.java @@ -130,12 +130,12 @@ public class DebuggerBreakpointsPluginScreenShots extends GhidraScreenShotGenera mb.testProcess1.addRegion("echo:.data", mb.rng(0x00600000, 0x00600fff), "rw"); mb.testProcess3.addRegion("echo:.text", mb.rng(0x7fac0000, 0x7fac0fff), "rx"); - try (UndoableTransaction tid = UndoableTransaction.start(trace1, "Add mapping", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace1, "Add mapping")) { DebuggerStaticMappingUtils.addMapping( new DefaultTraceLocation(trace1, null, Range.atLeast(0L), addr(trace1, 0x00400000)), new ProgramLocation(program, addr(program, 0x00400000)), 0x00210000, false); } - try (UndoableTransaction tid = UndoableTransaction.start(trace3, "Add mapping", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace3, "Add mapping")) { DebuggerStaticMappingUtils.addMapping( new DefaultTraceLocation(trace3, null, Range.atLeast(0L), addr(trace3, 0x7fac0000)), new ProgramLocation(program, addr(program, 0x00400000)), 0x00010000, false); @@ -159,7 +159,7 @@ public class DebuggerBreakpointsPluginScreenShots extends GhidraScreenShotGenera trace3.getBreakpointManager() .getBreakpointsAt(recorder3.getSnap(), addr(trace3, 0x7fac1234)))); - try (UndoableTransaction tid = UndoableTransaction.start(program, "Add breakpoint", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Add breakpoint")) { program.getBookmarkManager() .setBookmark(addr(program, 0x00401234), LogicalBreakpoint.BREAKPOINT_ENABLED_BOOKMARK_TYPE, "SW_EXECUTE;1", diff --git a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyActionsPluginScreenShots.java b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyActionsPluginScreenShots.java index d255c35c91..1fbd8509cf 100644 --- a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyActionsPluginScreenShots.java +++ b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyActionsPluginScreenShots.java @@ -111,7 +111,7 @@ public class DebuggerCopyActionsPluginScreenShots extends GhidraScreenShotGenera program = createDefaultProgram("echo", "Toy:BE:64:default", this); AddressSpace stSpace = program.getAddressFactory().getDefaultAddressSpace(); - try (UndoableTransaction tid = UndoableTransaction.start(program, "Add memory", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Add memory")) { program.setImageBase(tb.addr(stSpace, 0x00400000), true); Memory memory = program.getMemory(); memory.createInitializedBlock(".text", tb.addr(stSpace, 0x00400000), 0x10000, (byte) 0, diff --git a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsPluginScreenShots.java b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsPluginScreenShots.java index 94643005b0..69b3f5706b 100644 --- a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsPluginScreenShots.java +++ b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsPluginScreenShots.java @@ -103,7 +103,7 @@ public class DebuggerRegionsPluginScreenShots extends GhidraScreenShotGenerator progBash = createDefaultProgram("bash", ProgramBuilder._X64, this); progLibC = createDefaultProgram("libc.so.6", ProgramBuilder._X64, this); - try (UndoableTransaction tid = UndoableTransaction.start(progBash, "Add memory", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(progBash, "Add memory")) { progBash.setImageBase(addr(progBash, 0x00400000), true); progBash.getMemory() .createInitializedBlock(".text", addr(progBash, 0x00400000), 0x10000, (byte) 0, @@ -113,7 +113,7 @@ public class DebuggerRegionsPluginScreenShots extends GhidraScreenShotGenerator TaskMonitor.DUMMY, false); } - try (UndoableTransaction tid = UndoableTransaction.start(progLibC, "Add memory", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(progLibC, "Add memory")) { progLibC.setImageBase(addr(progLibC, 0x00400000), true); progLibC.getMemory() .createInitializedBlock(".text", addr(progLibC, 0x00400000), 0x10000, (byte) 0, diff --git a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesPluginScreenShots.java b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesPluginScreenShots.java index 43a0c25635..98b229618a 100644 --- a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesPluginScreenShots.java +++ b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesPluginScreenShots.java @@ -114,7 +114,7 @@ public class DebuggerModulesPluginScreenShots extends GhidraScreenShotGenerator progBash = createDefaultProgram("bash", ProgramBuilder._X64, this); progLibC = createDefaultProgram("libc.so.6", ProgramBuilder._X64, this); - try (UndoableTransaction tid = UndoableTransaction.start(progBash, "Add memory", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(progBash, "Add memory")) { progBash.setImageBase(addr(progBash, 0x00400000), true); progBash.getMemory() .createInitializedBlock(".text", addr(progBash, 0x00400000), 0x10000, (byte) 0, @@ -124,7 +124,7 @@ public class DebuggerModulesPluginScreenShots extends GhidraScreenShotGenerator TaskMonitor.DUMMY, false); } - try (UndoableTransaction tid = UndoableTransaction.start(progLibC, "Add memory", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(progLibC, "Add memory")) { progLibC.setImageBase(addr(progLibC, 0x00400000), true); progLibC.getMemory() .createInitializedBlock(".text", addr(progLibC, 0x00400000), 0x10000, (byte) 0, diff --git a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerStaticMappingPluginScreenShots.java b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerStaticMappingPluginScreenShots.java index ce706763c0..beded9da7c 100644 --- a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerStaticMappingPluginScreenShots.java +++ b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerStaticMappingPluginScreenShots.java @@ -94,7 +94,7 @@ public class DebuggerStaticMappingPluginScreenShots extends GhidraScreenShotGene progEcho = createDefaultProgram("bash", ProgramBuilder._X64, this); progLibC = createDefaultProgram("libc.so.6", ProgramBuilder._X64, this); - try (UndoableTransaction tid = UndoableTransaction.start(progEcho, "Add memory", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(progEcho, "Add memory")) { progEcho.setImageBase(addr(progEcho, 0x00400000), true); progEcho.getMemory() .createInitializedBlock(".text", addr(progEcho, 0x00400000), 0x10000, (byte) 0, @@ -104,7 +104,7 @@ public class DebuggerStaticMappingPluginScreenShots extends GhidraScreenShotGene TaskMonitor.DUMMY, false); } - try (UndoableTransaction tid = UndoableTransaction.start(progLibC, "Add memory", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(progLibC, "Add memory")) { progLibC.setImageBase(addr(progLibC, 0x00400000), true); progLibC.getMemory() .createInitializedBlock(".text", addr(progLibC, 0x00400000), 0x10000, (byte) 0, diff --git a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/stack/DebuggerStackPluginScreenShots.java b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/stack/DebuggerStackPluginScreenShots.java index cf8d62bc72..d3e8fd4316 100644 --- a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/stack/DebuggerStackPluginScreenShots.java +++ b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/stack/DebuggerStackPluginScreenShots.java @@ -83,7 +83,7 @@ public class DebuggerStackPluginScreenShots extends GhidraScreenShotGenerator { public void testCaptureDebuggerStackPlugin() throws Throwable { DomainFolder root = tool.getProject().getProjectData().getRootFolder(); program = createDefaultProgram("echo", ToyProgramBuilder._X64, this); - try (UndoableTransaction tid = UndoableTransaction.start(program, "Populate", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Populate")) { program.setImageBase(addr(program, 0x00400000), true); program.getMemory() .createInitializedBlock(".text", addr(program, 0x00400000), 0x10000, (byte) 0, diff --git a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/thread/DebuggerThreadsPluginScreenShots.java b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/thread/DebuggerThreadsPluginScreenShots.java index 93de071e67..6c8a0604a2 100644 --- a/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/thread/DebuggerThreadsPluginScreenShots.java +++ b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/thread/DebuggerThreadsPluginScreenShots.java @@ -72,7 +72,7 @@ public class DebuggerThreadsPluginScreenShots extends GhidraScreenShotGenerator waitForValue(() -> recorder.getTraceThread(handler2Thread)); AbstractGhidraHeadedDebuggerGUITest.waitForDomainObject(trace); - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Comments", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Comments")) { recorder.getTraceThread(mainThread).setComment("GUI main loop"); recorder.getTraceThread(serverThread).setComment("Server"); recorder.getTraceThread(handler1Thread).setComment("Handler 1"); diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/AbstractGhidraHeadedDebuggerGUITest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/AbstractGhidraHeadedDebuggerGUITest.java index 2766f6b158..8efff5afda 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/AbstractGhidraHeadedDebuggerGUITest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/AbstractGhidraHeadedDebuggerGUITest.java @@ -736,7 +736,7 @@ public abstract class AbstractGhidraHeadedDebuggerGUITest program = new ProgramDB("static-" + name.getMethodName(), lang, lang.getDefaultCompilerSpec(), this); try (UndoableTransaction tid = - UndoableTransaction.start(program, "Set Executable Path", true)) { + UndoableTransaction.start(program, "Set Executable Path")) { program.setExecutablePath(path); } programManager.openProgram(program); diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointMarkerPluginTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointMarkerPluginTest.java index 4c96b701d9..6b9105e5aa 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointMarkerPluginTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointMarkerPluginTest.java @@ -107,7 +107,7 @@ public class DebuggerBreakpointMarkerPluginTest extends AbstractGhidraHeadedDebu protected void addStaticMemoryAndBreakpoint() throws LockException, DuplicateNameException, MemoryConflictException, AddressOverflowException, CancelledException { try (UndoableTransaction tid = - UndoableTransaction.start(program, "Add bookmark break", true)) { + UndoableTransaction.start(program, "Add bookmark break")) { program.getMemory() .createInitializedBlock(".text", addr(program, 0x00400000), 0x1000, (byte) 0, TaskMonitor.DUMMY, false); @@ -118,7 +118,7 @@ public class DebuggerBreakpointMarkerPluginTest extends AbstractGhidraHeadedDebu } protected void addMapping(Trace trace) throws Exception { - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Add mapping", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Add mapping")) { DebuggerStaticMappingUtils.addMapping( new DefaultTraceLocation(trace, null, Range.atLeast(0L), addr(trace, 0x55550123)), new ProgramLocation(program, addr(program, 0x00400123)), 0x1000, false); @@ -421,7 +421,7 @@ public class DebuggerBreakpointMarkerPluginTest extends AbstractGhidraHeadedDebu } waitForPass(() -> assertEquals(0, breakpointService.getAllBreakpoints().size())); - try (UndoableTransaction tid = UndoableTransaction.start(program, "Disassemble", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Disassemble")) { Disassembler.getDisassembler(program, TaskMonitor.DUMMY, msg -> { }).disassemble(addr(program, 0x00400123), set(rng(program, 0x00400123, 0x00400123))); } @@ -449,7 +449,7 @@ public class DebuggerBreakpointMarkerPluginTest extends AbstractGhidraHeadedDebu } waitForPass(() -> assertEquals(0, breakpointService.getAllBreakpoints().size())); - try (UndoableTransaction tid = UndoableTransaction.start(program, "Disassemble", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Disassemble")) { program.getListing().createData(addr(program, 0x00400123), ByteDataType.dataType); } waitForDomainObject(program); diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsProviderTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsProviderTest.java index 0a658fdc48..568f46f4fa 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsProviderTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsProviderTest.java @@ -81,7 +81,7 @@ public class DebuggerBreakpointsProviderTest extends AbstractGhidraHeadedDebugge } protected void addMapping(Trace trace, Program prog) throws Exception { - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Add mapping", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Add mapping")) { DebuggerStaticMappingUtils.addMapping( new DefaultTraceLocation(trace, null, Range.atLeast(0L), addr(trace, 0x55550000)), new ProgramLocation(prog, addr(prog, 0x00400000)), 0x1000, false); @@ -103,7 +103,7 @@ public class DebuggerBreakpointsProviderTest extends AbstractGhidraHeadedDebugge protected void addStaticMemoryAndBreakpoint() throws LockException, DuplicateNameException, MemoryConflictException, AddressOverflowException, CancelledException { try (UndoableTransaction tid = - UndoableTransaction.start(program, "Add bookmark break", true)) { + UndoableTransaction.start(program, "Add bookmark break")) { program.getMemory() .createInitializedBlock(".text", addr(program, 0x00400000), 0x1000, (byte) 0, TaskMonitor.DUMMY, false); diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyActionsPluginTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyActionsPluginTest.java index c6b0727cef..d2230bc839 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyActionsPluginTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyActionsPluginTest.java @@ -136,7 +136,7 @@ public class DebuggerCopyActionsPluginTest extends AbstractGhidraHeadedDebuggerG AddressSpace stSpace = program.getAddressFactory().getDefaultAddressSpace(); - try (UndoableTransaction tid = UndoableTransaction.start(program, "Add blocks", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Add blocks")) { program.getMemory() .createInitializedBlock(".text", tb.addr(stSpace, 0x00400000), 0x8000, (byte) 0, monitor, false); @@ -230,7 +230,7 @@ public class DebuggerCopyActionsPluginTest extends AbstractGhidraHeadedDebuggerG AddressSpace stSpace = program.getAddressFactory().getDefaultAddressSpace(); MemoryBlock block; - try (UndoableTransaction tid = UndoableTransaction.start(program, "Create block", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Create block")) { block = program.getMemory() .createUninitializedBlock(".text", tb.addr(stSpace, 0x00400000), 0x10000, false); @@ -292,7 +292,7 @@ public class DebuggerCopyActionsPluginTest extends AbstractGhidraHeadedDebuggerG AddressSpace stSpace = program.getAddressFactory().getDefaultAddressSpace(); MemoryBlock block; - try (UndoableTransaction tid = UndoableTransaction.start(program, "Create block", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Create block")) { block = program.getMemory() .createUninitializedBlock(".text", tb.addr(stSpace, 0x00400000), 0x10000, false); diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyPlanTests.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyPlanTests.java index c2b21ee2ce..7695f40376 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyPlanTests.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyPlanTests.java @@ -84,7 +84,7 @@ public class DebuggerCopyPlanTests extends AbstractGhidraHeadedDebuggerGUITest { Address paddr = tb.addr(stSpace, 0x00400000); assertTrue(AllCopiers.BYTES.isRequiresInitializedMemory()); - try (UndoableTransaction tid = UndoableTransaction.start(program, "Copy", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Copy")) { program.getMemory() .createInitializedBlock(".text", paddr, 0x10000, (byte) 0, TaskMonitor.DUMMY, false); @@ -117,7 +117,7 @@ public class DebuggerCopyPlanTests extends AbstractGhidraHeadedDebuggerGUITest { Address paddr = tb.addr(stSpace, 0x00400000); assertFalse(AllCopiers.STATE.isRequiresInitializedMemory()); - try (UndoableTransaction tid = UndoableTransaction.start(program, "Copy", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Copy")) { program.getMemory() .createInitializedBlock(".text", paddr, 0x10000, (byte) 0, TaskMonitor.DUMMY, false); @@ -194,7 +194,7 @@ public class DebuggerCopyPlanTests extends AbstractGhidraHeadedDebuggerGUITest { assertTrue(iit.hasNext()); } - try (UndoableTransaction tid = UndoableTransaction.start(program, "Copy", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Copy")) { Address paddr = tb.addr(stSpace, 0x00400000); program.getMemory() .createInitializedBlock(".text", paddr, 0x10000, (byte) 0, TaskMonitor.DUMMY, @@ -242,7 +242,7 @@ public class DebuggerCopyPlanTests extends AbstractGhidraHeadedDebuggerGUITest { assertTrue(iit.hasNext()); } - try (UndoableTransaction tid = UndoableTransaction.start(program, "Copy", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Copy")) { Address paddr = tb.addr(stSpace, 0x00400000); program.getMemory() .createInitializedBlock(".text", paddr, 0x10000, (byte) 0, TaskMonitor.DUMMY, @@ -315,7 +315,7 @@ public class DebuggerCopyPlanTests extends AbstractGhidraHeadedDebuggerGUITest { assertFalse(insCtx.equals(tb.trace.getRegisterContextManager() .getDefaultValue(tb.language, contextReg, checkCtx.getAddress()))); - try (UndoableTransaction tid = UndoableTransaction.start(program, "Copy", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Copy")) { Address paddr = tb.addr(stSpace, 0x00400000); program.getMemory() .createInitializedBlock(".text", paddr, 0x10000, (byte) 0, TaskMonitor.DUMMY, @@ -372,7 +372,7 @@ public class DebuggerCopyPlanTests extends AbstractGhidraHeadedDebuggerGUITest { tb.buf(0x00, 0x03, 0x00, 0x01, 0x02)); } - try (UndoableTransaction tid = UndoableTransaction.start(program, "Copy", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Copy")) { Address paddr = tb.addr(stSpace, 0x00600000); program.getMemory() .createInitializedBlock(".data", paddr, 0x10000, (byte) 0, TaskMonitor.DUMMY, @@ -432,7 +432,7 @@ public class DebuggerCopyPlanTests extends AbstractGhidraHeadedDebuggerGUITest { tb.buf(0x00, 0x03, 0x00, 0x01, 0x02)); } - try (UndoableTransaction tid = UndoableTransaction.start(program, "Copy", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Copy")) { Address paddr = tb.addr(stSpace, 0x00600000); program.getMemory() .createInitializedBlock(".data", paddr, 0x10000, (byte) 0, TaskMonitor.DUMMY, @@ -505,7 +505,7 @@ public class DebuggerCopyPlanTests extends AbstractGhidraHeadedDebuggerGUITest { } Address paddr = tb.addr(stSpace, 0x00400000); - try (UndoableTransaction tid = UndoableTransaction.start(program, "Copy", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Copy")) { program.getMemory() .createInitializedBlock(".text", paddr, 0x10000, (byte) 0, TaskMonitor.DUMMY, false); @@ -570,7 +570,7 @@ public class DebuggerCopyPlanTests extends AbstractGhidraHeadedDebuggerGUITest { } Address paddr = tb.addr(stSpace, 0x55550000); - try (UndoableTransaction tid = UndoableTransaction.start(program, "Init", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Init")) { program.getMemory() .createInitializedBlock(".text", paddr, 0x10000, (byte) 0, TaskMonitor.DUMMY, false); @@ -621,7 +621,7 @@ public class DebuggerCopyPlanTests extends AbstractGhidraHeadedDebuggerGUITest { } Address paddr = tb.addr(stSpace, 0x55550000); - try (UndoableTransaction tid = UndoableTransaction.start(program, "Init", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Init")) { program.getMemory() .createInitializedBlock(".text", paddr, 0x10000, (byte) 0, TaskMonitor.DUMMY, false); @@ -677,7 +677,7 @@ public class DebuggerCopyPlanTests extends AbstractGhidraHeadedDebuggerGUITest { } Address paddr = tb.addr(stSpace, 0x55550000); - try (UndoableTransaction tid = UndoableTransaction.start(program, "Init", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Init")) { program.getMemory() .createInitializedBlock(".text", paddr, 0x10000, (byte) 0, TaskMonitor.DUMMY, false); @@ -720,7 +720,7 @@ public class DebuggerCopyPlanTests extends AbstractGhidraHeadedDebuggerGUITest { } Address paddr = tb.addr(stSpace, 0x55550000); - try (UndoableTransaction tid = UndoableTransaction.start(program, "Init", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Init")) { program.getMemory() .createInitializedBlock(".text", paddr, 0x10000, (byte) 0, TaskMonitor.DUMMY, false); diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProviderTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProviderTest.java index 812ede8486..45330e0c65 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProviderTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProviderTest.java @@ -115,7 +115,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI intoProject(program); AddressSpace ss = program.getAddressFactory().getDefaultAddressSpace(); - try (UndoableTransaction tid = UndoableTransaction.start(program, "Add block", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Add block")) { program.getMemory() .createInitializedBlock(".text", ss.getAddress(0x00600000), 0x10000, (byte) 0, monitor, false); @@ -488,7 +488,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI intoProject(program); AddressSpace ss = program.getAddressFactory().getDefaultAddressSpace(); - try (UndoableTransaction tid = UndoableTransaction.start(program, "Add block", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Add block")) { program.getMemory() .createInitializedBlock(".text", ss.getAddress(0x00600000), 0x10000, (byte) 0, monitor, false); @@ -601,7 +601,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI intoProject(program); AddressSpace ss = program.getAddressFactory().getDefaultAddressSpace(); - try (UndoableTransaction tid = UndoableTransaction.start(program, "Add block", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Add block")) { program.getMemory() .createInitializedBlock(".text", ss.getAddress(0x00600000), 0x10000, (byte) 0, monitor, false); @@ -1486,7 +1486,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI intoProject(program); AddressSpace ss = program.getAddressFactory().getDefaultAddressSpace(); - try (UndoableTransaction tid = UndoableTransaction.start(program, "Add block", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Add block")) { program.getMemory() .createInitializedBlock(".text", ss.getAddress(0x00600000), 0x10000, (byte) 0, monitor, false); diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsProviderTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsProviderTest.java index c72088ccf6..d629b870b2 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsProviderTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerRegionsProviderTest.java @@ -77,7 +77,7 @@ public class DebuggerRegionsProviderTest extends AbstractGhidraHeadedDebuggerGUI } protected void addBlocks() throws Exception { - try (UndoableTransaction tid = UndoableTransaction.start(program, "Add block", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Add block")) { Memory mem = program.getMemory(); blockExeText = mem.createInitializedBlock(".text", tb.addr(0x00400000), 0x100, (byte) 0, monitor, false); @@ -257,7 +257,7 @@ public class DebuggerRegionsProviderTest extends AbstractGhidraHeadedDebuggerGUI assertFalse(provider.actionMapRegions.isEnabled()); addBlocks(); - try (UndoableTransaction tid = UndoableTransaction.start(program, "Change name", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Change name")) { program.setName("echo"); } waitForDomainObject(program); diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/model/ModelQueryTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/model/ModelQueryTest.java index 8b349c8f48..9ebd2ebffa 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/model/ModelQueryTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/model/ModelQueryTest.java @@ -39,7 +39,7 @@ public class ModelQueryTest extends AbstractGhidraHeadedDebuggerGUITest { ModelQuery rootQuery = ModelQuery.parse(""); ModelQuery threadQuery = ModelQuery.parse("Processes[].Threads[]"); - try (UndoableTransaction tid = UndoableTransaction.start(tb.trace, "Init", true)) { + try (UndoableTransaction tid = tb.startTransaction()) { DBTraceObjectManager objects = tb.trace.getObjectManager(); TraceObjectValue rootVal = diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesProviderTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesProviderTest.java index d89753aa5a..a18696c3d5 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesProviderTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerModulesProviderTest.java @@ -129,7 +129,7 @@ public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerGUI protected MemoryBlock addBlock() throws Exception, MemoryConflictException, AddressOverflowException, CancelledException { - try (UndoableTransaction tid = UndoableTransaction.start(program, "Add block", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Add block")) { return program.getMemory() .createInitializedBlock(".text", tb.addr(0x00400000), 0x1000, (byte) 0, monitor, false); @@ -226,7 +226,7 @@ public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerGUI waitForSwing(); MemoryBlock block = addBlock(); - try (UndoableTransaction tid = UndoableTransaction.start(program, "Change name", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Change name")) { program.setName(modExe.getName()); } waitForDomainObject(program); @@ -355,7 +355,7 @@ public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerGUI assertTrue(modulesProvider.actionMapIdentically.isEnabled()); // Need some substance in the program - try (UndoableTransaction tid = UndoableTransaction.start(program, "Populate", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Populate")) { addBlock(); } waitForDomainObject(program); @@ -390,7 +390,7 @@ public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerGUI // Still assertFalse(modulesProvider.actionMapModules.isEnabled()); - try (UndoableTransaction tid = UndoableTransaction.start(program, "Change name", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Change name")) { program.setImageBase(addr(program, 0x00400000), true); program.setName(modExe.getName()); @@ -458,7 +458,7 @@ public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerGUI assertFalse(modulesProvider.actionMapSections.isEnabled()); MemoryBlock block = addBlock(); - try (UndoableTransaction tid = UndoableTransaction.start(program, "Change name", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Change name")) { program.setName(modExe.getName()); } waitForDomainObject(program); diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerStaticMappingProviderTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerStaticMappingProviderTest.java index 1869631e4a..b9bf7ea828 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerStaticMappingProviderTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/modules/DebuggerStaticMappingProviderTest.java @@ -123,7 +123,7 @@ public class DebuggerStaticMappingProviderTest extends AbstractGhidraHeadedDebug } waitForDomainObject(tb.trace); - try (UndoableTransaction tid = UndoableTransaction.start(program, "Add block", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Add block")) { program.getMemory() .createInitializedBlock(".text", addr(program, 0xc0de1234L), 0x100, (byte) 0, TaskMonitor.DUMMY, false); diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/stack/DebuggerStackProviderTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/stack/DebuggerStackProviderTest.java index 1736ddb96c..b2b405a73c 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/stack/DebuggerStackProviderTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/stack/DebuggerStackProviderTest.java @@ -478,7 +478,7 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerGUITe assertProviderPopulated(); Function func; - try (UndoableTransaction tid = UndoableTransaction.start(program, "Add Function", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Add Function")) { program.getMemory() .createInitializedBlock(".text", addr(program, 0x00600000), 0x1000, (byte) 0, TaskMonitor.DUMMY, false); diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/watch/DebuggerWatchesProviderTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/watch/DebuggerWatchesProviderTest.java index afaa2067ed..3f88c8d3dc 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/watch/DebuggerWatchesProviderTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/watch/DebuggerWatchesProviderTest.java @@ -536,7 +536,7 @@ public class DebuggerWatchesProviderTest extends AbstractGhidraHeadedDebuggerGUI programManager.openProgram(program); AddressSpace stSpace = program.getAddressFactory().getDefaultAddressSpace(); - try (UndoableTransaction tid = UndoableTransaction.start(program, "Add block", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Add block")) { Memory mem = program.getMemory(); mem.createInitializedBlock(".data", tb.addr(stSpace, 0x00600000), 0x10000, (byte) 0, TaskMonitor.DUMMY, false); @@ -617,7 +617,7 @@ public class DebuggerWatchesProviderTest extends AbstractGhidraHeadedDebuggerGUI structDt.add(DWordDataType.dataType, "field0", ""); structDt.add(DWordDataType.dataType, "field4", ""); - try (UndoableTransaction tid = UndoableTransaction.start(program, "Add data", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Add data")) { program.getListing().createData(tb.addr(stSpace, 0x00600000), structDt); } @@ -658,7 +658,7 @@ public class DebuggerWatchesProviderTest extends AbstractGhidraHeadedDebuggerGUI setupMappedDataSection(); Symbol symbol; - try (UndoableTransaction tid = UndoableTransaction.start(program, "Add symbol", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Add symbol")) { symbol = program.getSymbolTable() .createLabel(tb.addr(0x00601234), "my_symbol", SourceType.USER_DEFINED); } diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/breakpoint/DebuggerLogicalBreakpointServiceTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/breakpoint/DebuggerLogicalBreakpointServiceTest.java index 1a66363e7b..d94396334b 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/breakpoint/DebuggerLogicalBreakpointServiceTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/breakpoint/DebuggerLogicalBreakpointServiceTest.java @@ -256,7 +256,7 @@ public class DebuggerLogicalBreakpointServiceTest extends AbstractGhidraHeadedDe protected void addProgramTextBlock(Program p) throws Throwable { try (UndoableTransaction tid = - UndoableTransaction.start(program, "Add .text block", true)) { + UndoableTransaction.start(program, "Add .text block")) { p.getMemory() .createInitializedBlock(".text", addr(p, 0x00400000), 0x1000, (byte) 0, monitor, false); @@ -281,7 +281,7 @@ public class DebuggerLogicalBreakpointServiceTest extends AbstractGhidraHeadedDe TraceMemoryRegion textRegion = waitFor(() -> r.getTraceMemoryRegion(region), "Recorder missed region: " + region); try (UndoableTransaction tid = - UndoableTransaction.start(t, "Add .text mapping", true)) { + UndoableTransaction.start(t, "Add .text mapping")) { DebuggerStaticMappingUtils.addMapping( new DefaultTraceLocation(t, null, textRegion.getLifespan(), textRegion.getMinAddress()), @@ -292,7 +292,7 @@ public class DebuggerLogicalBreakpointServiceTest extends AbstractGhidraHeadedDe protected void removeTextMapping(TraceRecorder r, Program p) throws Throwable { Trace t = r.getTrace(); - try (UndoableTransaction tid = UndoableTransaction.start(t, "Remove .text mapping", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(t, "Remove .text mapping")) { TraceStaticMapping mapping = t.getStaticMappingManager().findContaining(addr(t, 0x55550000), r.getSnap()); mapping.delete(); @@ -341,7 +341,7 @@ public class DebuggerLogicalBreakpointServiceTest extends AbstractGhidraHeadedDe } protected void addProgramBreakpoints(Program p) throws Throwable { - try (UndoableTransaction tid = UndoableTransaction.start(p, "Create bookmarks", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(p, "Create bookmarks")) { enBm = p.getBookmarkManager() .setBookmark(addr(p, 0x00400123), LogicalBreakpoint.BREAKPOINT_ENABLED_BOOKMARK_TYPE, "SW_EXECUTE;1", ""); @@ -362,7 +362,7 @@ public class DebuggerLogicalBreakpointServiceTest extends AbstractGhidraHeadedDe } protected void removeProgramBreakpoints(Program p) throws Throwable { - try (UndoableTransaction tid = UndoableTransaction.start(p, "Remove breakpoints", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(p, "Remove breakpoints")) { p.getBookmarkManager().removeBookmark(enBm); p.getBookmarkManager().removeBookmark(disBm); } @@ -1160,12 +1160,13 @@ public class DebuggerLogicalBreakpointServiceTest extends AbstractGhidraHeadedDe expectMappingChange(() -> addTextMapping(recorder1, text, program)); waitForSwing(); - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Will abort", false)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Will abort")) { addTargetSoftwareBreakpoint(recorder1, text); waitForDomainObject(trace); // Sanity assertLogicalBreakpointForMappedSoftwareBreakpoint(trace); + tid.abort(); } waitForDomainObject(trace); @@ -1197,7 +1198,7 @@ public class DebuggerLogicalBreakpointServiceTest extends AbstractGhidraHeadedDe waitForDomainObject(trace); changeListener.assertAgreesWithService(); - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Will abort", false)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Will abort")) { expectMappingChange(() -> addTextMapping(recorder1, text, program)); waitForSwing(); @@ -1226,7 +1227,7 @@ public class DebuggerLogicalBreakpointServiceTest extends AbstractGhidraHeadedDe addProgramTextBlock(program); TestTargetMemoryRegion text = addTargetTextRegion(mb.testProcess1); - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Will abort", false)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Will abort")) { addTargetSoftwareBreakpoint(recorder1, text); expectMappingChange(() -> addTextMapping(recorder1, text, program)); @@ -1260,12 +1261,13 @@ public class DebuggerLogicalBreakpointServiceTest extends AbstractGhidraHeadedDe expectMappingChange(() -> addTextMapping(recorder1, text, program)); waitForSwing(); - try (UndoableTransaction tid = UndoableTransaction.start(program, "Will abort", false)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Will abort")) { addProgramBreakpoints(program); waitForDomainObject(program); // Sanity assertLogicalBreakpointsForMappedBookmarks(trace); + tid.abort(); } waitForDomainObject(program); @@ -1285,7 +1287,7 @@ public class DebuggerLogicalBreakpointServiceTest extends AbstractGhidraHeadedDe addProgramTextBlock(program); TestTargetMemoryRegion text = addTargetTextRegion(mb.testProcess1); - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Will undo", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Will undo")) { addTargetSoftwareBreakpoint(recorder1, text); expectMappingChange(() -> addTextMapping(recorder1, text, program)); } @@ -1321,7 +1323,7 @@ public class DebuggerLogicalBreakpointServiceTest extends AbstractGhidraHeadedDe expectMappingChange(() -> addTextMapping(recorder1, text, program)); waitForSwing(); - try (UndoableTransaction tid = UndoableTransaction.start(program, "Will undo", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Will undo")) { addProgramBreakpoints(program); } waitForDomainObject(program); diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/emulation/DebuggerEmulationServiceTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/emulation/DebuggerEmulationServiceTest.java index b0a1aa5d90..50fa7eebae 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/emulation/DebuggerEmulationServiceTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/emulation/DebuggerEmulationServiceTest.java @@ -66,7 +66,7 @@ public class DebuggerEmulationServiceTest extends AbstractGhidraHeadedDebuggerGU Register regPC = program.getRegister("pc"); Register regR0 = program.getRegister("r0"); Register regR1 = program.getRegister("r1"); - try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize")) { MemoryBlock blockText = memory.createInitializedBlock(".text", addrText, 0x1000, (byte) 0, TaskMonitor.DUMMY, false); blockText.setExecute(true); @@ -122,7 +122,7 @@ public class DebuggerEmulationServiceTest extends AbstractGhidraHeadedDebuggerGU Register regPC = program.getRegister("pc"); Register regR0 = program.getRegister("r0"); Register regR1 = program.getRegister("r1"); - try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize")) { MemoryBlock blockText = memory.createInitializedBlock(".text", addrText, 0x1000, (byte) 0, TaskMonitor.DUMMY, false); blockText.setExecute(true); @@ -181,7 +181,7 @@ public class DebuggerEmulationServiceTest extends AbstractGhidraHeadedDebuggerGU Register regPC = program.getRegister("PC"); Register regW0 = program.getRegister("W0"); Register regW1 = program.getRegister("W1"); - try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize")) { MemoryBlock blockText = memory.createInitializedBlock(".text", addrText, 0x1000, (byte) 0, TaskMonitor.DUMMY, false); blockText.setExecute(true); diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/model/DefaultTraceRecorderTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/model/DefaultTraceRecorderTest.java index 51256a8407..84f3acab42 100644 --- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/model/DefaultTraceRecorderTest.java +++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/model/DefaultTraceRecorderTest.java @@ -77,7 +77,7 @@ public class DefaultTraceRecorderTest extends AbstractGhidraHeadedDebuggerGUITes protected TraceMemoryRegisterSpace createRegSpace(TraceThread thread) { try (UndoableTransaction tid = - UndoableTransaction.start(thread.getTrace(), "Create register space", true)) { + UndoableTransaction.start(thread.getTrace(), "Create register space")) { return thread.getTrace().getMemoryManager().getMemoryRegisterSpace(thread, true); } } @@ -143,7 +143,7 @@ public class DefaultTraceRecorderTest extends AbstractGhidraHeadedDebuggerGUITes mb.testProcess1.regs.addRegistersFromLanguage(getToyBE64Language(), r -> r.isBaseRegister() && r != pc && r != sp); TestTargetRegisterBankInThread regs = mb.testThread1.addRegisterBank(); - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Add PC type", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Add PC type")) { TraceCodeRegisterSpace code = trace.getCodeManager().getCodeRegisterSpace(thread, true); code.definedData().create(Range.atLeast(0L), pc, PointerDataType.dataType); } @@ -192,7 +192,7 @@ public class DefaultTraceRecorderTest extends AbstractGhidraHeadedDebuggerGUITes mb.testProcess1.regs.addRegistersFromLanguage(getToyBE64Language(), r -> r.isBaseRegister() && r != pc && r != sp); TestTargetRegisterBankInThread regs = mb.testThread1.addRegisterBank(); - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Add SP type", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Add SP type")) { TraceCodeRegisterSpace code = trace.getCodeManager().getCodeRegisterSpace(thread, true); code.definedData().create(Range.atLeast(0L), sp, PointerDataType.dataType); } @@ -241,7 +241,7 @@ public class DefaultTraceRecorderTest extends AbstractGhidraHeadedDebuggerGUITes //waitForCondition(() -> registerMapped(recorder, thread, pc)); TraceThread thread = waitForValue(() -> recorder.getTraceThread(mb.testThread1)); - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Add PC type", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Add PC type")) { TraceCodeRegisterSpace code = trace.getCodeManager().getCodeRegisterSpace(thread, true); code.definedData().create(Range.atLeast(0L), pc, PointerDataType.dataType); } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/DBTrace.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/DBTrace.java index d16a14af42..fa4110452d 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/DBTrace.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/DBTrace.java @@ -155,10 +155,9 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace this.baseAddressFactory = new TraceAddressFactory(this.baseLanguage, this.baseCompilerSpec); - try (UndoableTransaction tid = UndoableTransaction.start(this, "Create", false)) { + try (UndoableTransaction tid = UndoableTransaction.start(this, "Create")) { initOptions(DBOpenMode.CREATE); init(); - tid.commit(); } catch (VersionException | CancelledException e) { throw new AssertionError(e); diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/address/DBTraceOverlaySpaceAdapter.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/address/DBTraceOverlaySpaceAdapter.java index f1576c1070..bdc7b7801c 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/address/DBTraceOverlaySpaceAdapter.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/address/DBTraceOverlaySpaceAdapter.java @@ -60,7 +60,7 @@ public class DBTraceOverlaySpaceAdapter implements DBTraceManager { * @param the type of object containing the field */ public static class AddressDBFieldCodec - extends AbstractDBFieldCodec { + extends AbstractDBFieldCodec { static final Charset UTF8 = Charset.forName("UTF-8"); public static byte[] encode(Address address) { @@ -68,16 +68,8 @@ public class DBTraceOverlaySpaceAdapter implements DBTraceManager { return null; } AddressSpace as = address.getAddressSpace(); - ByteBuffer buf = ByteBuffer.allocate(Byte.BYTES + Short.BYTES + Long.BYTES); - if (as instanceof OverlayAddressSpace) { - buf.put((byte) 1); - OverlayAddressSpace os = (OverlayAddressSpace) as; - buf.putShort((short) os.getDatabaseKey()); - } - else { - buf.put((byte) 0); - buf.putShort((short) as.getSpaceID()); - } + ByteBuffer buf = ByteBuffer.allocate(Short.BYTES + Long.BYTES); + buf.putShort((short) as.getSpaceID()); buf.putLong(address.getOffset()); return buf.array(); } @@ -86,29 +78,19 @@ public class DBTraceOverlaySpaceAdapter implements DBTraceManager { if (enc == null) { return null; } - else { - ByteBuffer buf = ByteBuffer.wrap(enc); - byte overlay = buf.get(); - final AddressSpace as; - if (overlay == 1) { - short key = buf.getShort(); - as = osa.spacesByKey.get(key & 0xffffL); - } - else { - short id = buf.getShort(); - as = osa.trace.getInternalAddressFactory().getAddressSpace(id); - } - long offset = buf.getLong(); - return as.getAddress(offset); - } + ByteBuffer buf = ByteBuffer.wrap(enc); + short id = buf.getShort(); + final AddressSpace as = osa.trace.getInternalAddressFactory().getAddressSpace(id); + long offset = buf.getLong(); + return as.getAddress(offset); } public AddressDBFieldCodec(Class objectType, Field field, int column) { - super(Address.class, objectType, BinaryField.class, field, column); + super(Address.class, objectType, FixedField10.class, field, column); } @Override - public void store(Address value, BinaryField f) { + public void store(Address value, FixedField10 f) { f.setBinaryData(encode(value)); } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceCodeManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceCodeManager.java index 4789e9777d..09d1cff553 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceCodeManager.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceCodeManager.java @@ -43,8 +43,8 @@ import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter.AddressDBFieldCo import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter.DecodesAddresses; import ghidra.trace.database.data.DBTraceDataTypeManager; import ghidra.trace.database.guest.DBTraceGuestPlatform; -import ghidra.trace.database.guest.DBTracePlatformManager; import ghidra.trace.database.guest.DBTraceGuestPlatform.DBTraceGuestLanguage; +import ghidra.trace.database.guest.DBTracePlatformManager; import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery; import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager; import ghidra.trace.database.space.DBTraceDelegatingManager; @@ -69,7 +69,17 @@ public class DBTraceCodeManager implements TraceCodeManager, DBTraceDelegatingManager { public static final String NAME = "Code"; - @DBAnnotatedObjectInfo(version = 0) + /** + * A prototype entry + * + *

+ * Version history: + *

+ */ + @DBAnnotatedObjectInfo(version = 1) public static class DBTraceCodePrototypeEntry extends DBAnnotatedObject implements DecodesAddresses { public static final String TABLE_NAME = "Prototypes"; @@ -99,7 +109,7 @@ public class DBTraceCodeManager @DBAnnotatedField(column = CONTEXT_COLUMN_NAME) private byte[] context; @DBAnnotatedField(column = ADDRESS_COLUMN_NAME, codec = AddressDBFieldCodec.class) - private Address address; + private Address address = Address.NO_ADDRESS; @DBAnnotatedField(column = DELAY_COLUMN_NAME) private boolean delaySlot; diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceStaticMapping.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceStaticMapping.java index e4b334f757..9ffc99998d 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceStaticMapping.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/module/DBTraceStaticMapping.java @@ -34,7 +34,17 @@ import ghidra.util.LockHold; import ghidra.util.database.*; import ghidra.util.database.annot.*; -@DBAnnotatedObjectInfo(version = 0) +/** + * The implementation of a stack mapping, directly via a database object + * + *

+ * Version history: + *

+ */ +@DBAnnotatedObjectInfo(version = 1) public class DBTraceStaticMapping extends DBAnnotatedObject implements TraceStaticMapping, DecodesAddresses { public static final String TABLE_NAME = "StaticMappings"; @@ -80,7 +90,7 @@ public class DBTraceStaticMapping extends DBAnnotatedObject column = TRACE_ADDRESS_COLUMN_NAME, indexed = true, codec = AddressDBFieldCodec.class) - private Address traceAddress; + private Address traceAddress = Address.NO_ADDRESS; @DBAnnotatedField(column = LENGTH_COLUMN_NAME) private long length; @DBAnnotatedField(column = START_SNAP_COLUMN_NAME) diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/stack/DBTraceStackFrame.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/stack/DBTraceStackFrame.java index d178f29208..cc7c914b58 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/stack/DBTraceStackFrame.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/stack/DBTraceStackFrame.java @@ -33,7 +33,17 @@ import ghidra.util.LockHold; import ghidra.util.database.*; import ghidra.util.database.annot.*; -@DBAnnotatedObjectInfo(version = 0) +/** + * The implementation of a stack frame, directly via a database object + * + *

+ * Version history: + *

+ */ +@DBAnnotatedObjectInfo(version = 1) public class DBTraceStackFrame extends DBAnnotatedObject implements TraceStackFrame, DecodesAddresses { public static final String TABLE_NAME = "StackFrames"; @@ -56,7 +66,11 @@ public class DBTraceStackFrame extends DBAnnotatedObject private long stackKey; @DBAnnotatedField(column = LEVEL_COLUMN_NAME) private int level; - @DBAnnotatedField(column = PC_COLUMN_NAME, indexed = true, codec = AddressDBFieldCodec.class) + @DBAnnotatedField( + column = PC_COLUMN_NAME, + indexed = true, + codec = AddressDBFieldCodec.class, + sparse = true) private Address pc; @DBAnnotatedField(column = COMMENT_COLUMN_NAME) private String comment; diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceFunctionSymbol.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceFunctionSymbol.java index 78d90c8d16..a6f1c18b1d 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceFunctionSymbol.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceFunctionSymbol.java @@ -55,7 +55,17 @@ import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.InvalidInputException; import ghidra.util.task.TaskMonitor; -@DBAnnotatedObjectInfo(version = 0) +/** + * The implementation of a function symbol, directly via a database object + * + *

+ * Version history: + *

+ */ +@DBAnnotatedObjectInfo(version = 1) public class DBTraceFunctionSymbol extends DBTraceNamespaceSymbol implements TraceFunctionSymbol, DecodesAddresses { @SuppressWarnings("hiding") @@ -103,8 +113,9 @@ public class DBTraceFunctionSymbol extends DBTraceNamespaceSymbol @DBAnnotatedColumn(STACK_RETURN_OFFSET_COLUMN_NAME) static DBObjectColumn STACK_RETURN_OFFSET_COLUMN; + // Do I need to index entry, too? Not just body? @DBAnnotatedField(column = ENTRY_COLUMN_NAME, codec = AddressDBFieldCodec.class) - protected Address entryPoint; // Do I need to index entry, too? Not just body? + protected Address entryPoint = Address.NO_ADDRESS; @DBAnnotatedField(column = START_SNAP_COLUMN_NAME) protected long startSnap; @DBAnnotatedField(column = END_SNAP_COLUMN_NAME) diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceLabelSymbol.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceLabelSymbol.java index 917d0fbf4d..f9305c2863 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceLabelSymbol.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceLabelSymbol.java @@ -39,7 +39,17 @@ import ghidra.util.database.DBObjectColumn; import ghidra.util.database.annot.*; import ghidra.util.exception.DuplicateNameException; -@DBAnnotatedObjectInfo(version = 0) +/** + * The implementation of a label symbol, directly via a database object + * + *

+ * Version history: + *

+ */ +@DBAnnotatedObjectInfo(version = 1) public class DBTraceLabelSymbol extends AbstractDBTraceSymbol implements TraceLabelSymbol, DBTraceSpaceKey, DecodesAddresses { static final String TABLE_NAME = "Labels"; @@ -61,8 +71,9 @@ public class DBTraceLabelSymbol extends AbstractDBTraceSymbol @DBAnnotatedColumn(END_SNAP_COLUMN_NAME) static DBObjectColumn END_SNAP_COLUMN; + // NOTE: Indexed in manager's range map @DBAnnotatedField(column = ADDRESS_COLUMN_NAME, codec = AddressDBFieldCodec.class) - protected Address address; // NOTE: Indexed in manager's range map + protected Address address = Address.NO_ADDRESS; @DBAnnotatedField(column = THREAD_COLUMN_NAME) protected long threadKey; @DBAnnotatedField(column = START_SNAP_COLUMN_NAME) diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceSpace.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceSpace.java index 9ab33c14e3..028751b140 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceSpace.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceSpace.java @@ -91,7 +91,17 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS protected abstract DBTraceReference construct(DBTraceReferenceEntry ent); } - @DBAnnotatedObjectInfo(version = 0) + /** + * A reference entry + * + *

+ * Version history: + *

+ */ + @DBAnnotatedObjectInfo(version = 1) protected static class DBTraceReferenceEntry extends AbstractDBTraceAddressSnapRangePropertyMapData implements DecodesAddresses { @@ -137,7 +147,7 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS column = TO_ADDR_COLUMN_NAME, indexed = true, codec = AddressDBFieldCodec.class) - protected Address toAddress; + protected Address toAddress = Address.NO_ADDRESS; @DBAnnotatedField(column = SYMBOL_ID_COLUMN_NAME, indexed = true) protected long symbolId; // TODO: Is this at the from or to address? I think TO... @DBAnnotatedField(column = REF_TYPE_COLUMN_NAME, codec = RefTypeDBFieldCodec.class) @@ -514,12 +524,12 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS badOffsetReference = true; } } - + if (badOffsetReference) { Msg.warn(this, "Offset Reference from " + fromAddress + " produces bad Xref into EXTERNAL block"); } - + makeWay(lifespan, fromAddress, toAddress, operandIndex); DBTraceReferenceEntry entry = referenceMapSpace.put(fromAddress, lifespan, null); diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/ToyDBTraceBuilder.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/ToyDBTraceBuilder.java index c63c7b26c5..a26bb2e78c 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/ToyDBTraceBuilder.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/ToyDBTraceBuilder.java @@ -193,7 +193,7 @@ public class ToyDBTraceBuilder implements AutoCloseable { } public UndoableTransaction startTransaction() { - return UndoableTransaction.start(trace, "Testing", true); + return UndoableTransaction.start(trace, "Testing"); } public DBTraceBookmarkType getOrAddBookmarkType(String name) { diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/data/DBTraceDataTypeManagerTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/data/DBTraceDataTypeManagerTest.java index e7716f7f0f..c659240af1 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/data/DBTraceDataTypeManagerTest.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/data/DBTraceDataTypeManagerTest.java @@ -80,7 +80,7 @@ public class DBTraceDataTypeManagerTest extends AbstractGhidraHeadlessIntegratio @Test public void testSetName() throws InvalidNameException { - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Testing", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Testing")) { dtm.setName("Another name"); } assertEquals("Another name", trace.getName()); @@ -93,12 +93,12 @@ public class DBTraceDataTypeManagerTest extends AbstractGhidraHeadlessIntegratio Path tmpDir = Files.createTempDirectory("test"); File archiveFile = tmpDir.resolve("test.gdt").toFile(); FileDataTypeManager dtm2 = FileDataTypeManager.createFileArchive(archiveFile); - try (UndoableTransaction tid = UndoableTransaction.start(dtm2, "Testing", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(dtm2, "Testing")) { dtm2.addDataType(mine, DataTypeConflictHandler.DEFAULT_HANDLER); } DataType got = dtm2.getDataType(minePath); - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Testing", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Testing")) { dtm.addDataType(got, DataTypeConflictHandler.DEFAULT_HANDLER); } dtm2.delete(); @@ -112,7 +112,7 @@ public class DBTraceDataTypeManagerTest extends AbstractGhidraHeadlessIntegratio public void testAddAndGet() { StructureDataType mine = getTestDataType(); DataTypePath minePath = mine.getDataTypePath(); - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Testing", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Testing")) { dtm.addDataType(mine, DataTypeConflictHandler.REPLACE_HANDLER); } @@ -125,14 +125,14 @@ public class DBTraceDataTypeManagerTest extends AbstractGhidraHeadlessIntegratio public void testAddRemoveUndoThenGet() throws IOException { StructureDataType mine = getTestDataType(); DataTypePath minePath = mine.getDataTypePath(); - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Testing", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Testing")) { dtm.addDataType(mine, DataTypeConflictHandler.REPLACE_HANDLER); } DataType got = dtm.getDataType(minePath); assertEquals(mine.toString(), got.toString()); // TODO: Eww - try (UndoableTransaction tid = UndoableTransaction.start(trace, "To Undo", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "To Undo")) { dtm.remove(got, new ConsoleTaskMonitor()); } @@ -148,7 +148,7 @@ public class DBTraceDataTypeManagerTest extends AbstractGhidraHeadlessIntegratio public void testChangeDataType() { StructureDataType mine = getTestDataType(); DataTypePath minePath = mine.getDataTypePath(); - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Testing", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Testing")) { dtm.addDataType(mine, DataTypeConflictHandler.REPLACE_HANDLER); Structure got = (Structure) dtm.getDataType(minePath); @@ -165,7 +165,7 @@ public class DBTraceDataTypeManagerTest extends AbstractGhidraHeadlessIntegratio DataTypePath mineAPath = mineA.getDataTypePath(); StructureDataType mineB = getTestDataTypeB(); DataTypePath mineBPath = mineB.getDataTypePath(); - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Testing", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Testing")) { dtm.addDataType(mineA, DataTypeConflictHandler.REPLACE_HANDLER); DataType got = dtm.getDataType(mineAPath); @@ -181,7 +181,7 @@ public class DBTraceDataTypeManagerTest extends AbstractGhidraHeadlessIntegratio StructureDataType mine = getTestDataType(); DataTypePath minePath = mine.getDataTypePath(); DataType got; - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Testing", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Testing")) { dtm.addDataType(mine, DataTypeConflictHandler.REPLACE_HANDLER); got = dtm.getDataType(minePath); @@ -197,7 +197,7 @@ public class DBTraceDataTypeManagerTest extends AbstractGhidraHeadlessIntegratio StructureDataType mine = getTestDataType(); DataTypePath minePath = mine.getDataTypePath(); DataType got; - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Testing", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Testing")) { dtm.addDataType(mine, DataTypeConflictHandler.REPLACE_HANDLER); got = dtm.getDataType(minePath); @@ -211,7 +211,7 @@ public class DBTraceDataTypeManagerTest extends AbstractGhidraHeadlessIntegratio @Test public void testCreateCategory() { Category category; - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Testing", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Testing")) { category = dtm.createCategory(new CategoryPath("/Another/Path")); } assertEquals(category, dtm.getCategory(new CategoryPath("/Another/Path"))); @@ -220,7 +220,7 @@ public class DBTraceDataTypeManagerTest extends AbstractGhidraHeadlessIntegratio @Test public void testMoveCategory() throws DuplicateNameException { Category toMove; - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Testing", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Testing")) { Category category = dtm.createCategory(new CategoryPath("/Another/Path")); toMove = dtm.createCategory(new CategoryPath("/MoveMe")); category.moveCategory(toMove, new ConsoleTaskMonitor()); @@ -231,7 +231,7 @@ public class DBTraceDataTypeManagerTest extends AbstractGhidraHeadlessIntegratio @Test public void testRenameCategory() throws DuplicateNameException, InvalidNameException { Category category; - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Testing", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Testing")) { category = dtm.createCategory(new CategoryPath("/Another/Path")); category.setName("Renamed"); } @@ -241,12 +241,12 @@ public class DBTraceDataTypeManagerTest extends AbstractGhidraHeadlessIntegratio @Test public void testRemoveCategory() { Category category; - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Testing", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Testing")) { category = dtm.createCategory(new CategoryPath("/Another/Path")); } assertEquals(category, dtm.getCategory(new CategoryPath("/Another/Path"))); - try (UndoableTransaction tid = UndoableTransaction.start(trace, "Testing", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(trace, "Testing")) { dtm.getCategory(new CategoryPath("/Another")) .removeEmptyCategory("Path", new ConsoleTaskMonitor()); diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/map/DBTraceAddressSnapRangePropertyMapAddressSetViewTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/map/DBTraceAddressSnapRangePropertyMapAddressSetViewTest.java index 91e05ca66e..6c6b298ca3 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/map/DBTraceAddressSnapRangePropertyMapAddressSetViewTest.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/map/DBTraceAddressSnapRangePropertyMapAddressSetViewTest.java @@ -145,7 +145,7 @@ public class DBTraceAddressSnapRangePropertyMapAddressSetViewTest .getLanguage(new LanguageID("Toy:BE:64:default")); obj = new MyObject(this); factory = new DBCachedObjectStoreFactory(obj); - try (UndoableTransaction tid = UndoableTransaction.start(obj, "CreateTable", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(obj, "CreateTable")) { space = new DBTraceAddressSnapRangePropertyMapSpace<>("Entries", factory, obj.getReadWriteLock(), toy.getDefaultSpace(), MyEntry.class, MyEntry::new); } @@ -163,7 +163,7 @@ public class DBTraceAddressSnapRangePropertyMapAddressSetViewTest view = makeIntersectingView(tasr(0x0100, 0x2fff, 0, 0), s -> true); assertFalse(view.contains(addr(0x1800))); - try (UndoableTransaction trans = UndoableTransaction.start(obj, "Create Entries", true)) { + try (UndoableTransaction trans = UndoableTransaction.start(obj, "Create Entries")) { space.put(tasr(0x1000, 0x1fff, 0, 9), "A"); } @@ -195,7 +195,7 @@ public class DBTraceAddressSnapRangePropertyMapAddressSetViewTest view = makeIntersectingView(tasr(0x0100, 0x2fff, 0, 0), s -> true); assertFalse(view.contains(addr(0x1000), addr(0x1fff))); - try (UndoableTransaction trans = UndoableTransaction.start(obj, "Create Entries", true)) { + try (UndoableTransaction trans = UndoableTransaction.start(obj, "Create Entries")) { space.put(tasr(0x1000, 0x2fff, 0, 0), "A"); space.put(tasr(0x2000, 0x3fff, 1, 1), "B"); } @@ -232,7 +232,7 @@ public class DBTraceAddressSnapRangePropertyMapAddressSetViewTest view = makeIntersectingView(tasr(0x0100, 0x2fff, 0, 0), s -> true); assertFalse(view.contains(set(rng(0x1000, 0x1fff)))); - try (UndoableTransaction trans = UndoableTransaction.start(obj, "Create Entries", true)) { + try (UndoableTransaction trans = UndoableTransaction.start(obj, "Create Entries")) { space.put(tasr(0x1000, 0x2fff, 0, 0), "A"); space.put(tasr(0x2000, 0x3fff, 1, 1), "B"); } @@ -271,7 +271,7 @@ public class DBTraceAddressSnapRangePropertyMapAddressSetViewTest assertEquals(0, view.getNumAddressRanges()); assertEquals(0, view.getNumAddresses()); - try (UndoableTransaction trans = UndoableTransaction.start(obj, "Create Entries", true)) { + try (UndoableTransaction trans = UndoableTransaction.start(obj, "Create Entries")) { space.put(tasr(0x1000, 0x1fff, 0, 0), "A"); space.put(tasr(0x2000, 0x2fff, 0, 0), "A"); space.put(tasr(0x2000, 0x2fff, 1, 1), "B"); @@ -307,7 +307,7 @@ public class DBTraceAddressSnapRangePropertyMapAddressSetViewTest assertNull(view.getMinAddress()); assertNull(view.getMaxAddress()); - try (UndoableTransaction trans = UndoableTransaction.start(obj, "Create Entries", true)) { + try (UndoableTransaction trans = UndoableTransaction.start(obj, "Create Entries")) { space.put(tasr(0x1000, 0x2fff, 0, 0), "A"); space.put(tasr(0x2000, 0x3fff, 1, 1), "B"); } @@ -337,7 +337,7 @@ public class DBTraceAddressSnapRangePropertyMapAddressSetViewTest view = makeIntersectingView(tasr(0x0100, 0x2fff, 0, 0), s -> true); assertEquals(List.of(), list(view.iterator())); - try (UndoableTransaction trans = UndoableTransaction.start(obj, "Create Entries", true)) { + try (UndoableTransaction trans = UndoableTransaction.start(obj, "Create Entries")) { space.put(tasr(0x1000, 0x1fff, 0, 0), "A"); space.put(tasr(0x2000, 0x2fff, 0, 0), "A"); space.put(tasr(0x2000, 0x2fff, 1, 1), "B"); @@ -376,7 +376,7 @@ public class DBTraceAddressSnapRangePropertyMapAddressSetViewTest view = makeIntersectingView(tasr(0x0100, 0x2fff, 0, 0), s -> true); assertEquals(List.of(), list(view.getAddresses(true))); - try (UndoableTransaction trans = UndoableTransaction.start(obj, "Create Entries", true)) { + try (UndoableTransaction trans = UndoableTransaction.start(obj, "Create Entries")) { space.put(tasr(1, 5, 0, 0), "A"); } @@ -396,7 +396,7 @@ public class DBTraceAddressSnapRangePropertyMapAddressSetViewTest @Test public void testIntersects() { - try (UndoableTransaction trans = UndoableTransaction.start(obj, "Create Entries", true)) { + try (UndoableTransaction trans = UndoableTransaction.start(obj, "Create Entries")) { space.put(tasr(0x1000, 0x1fff, 0, 0), "A"); space.put(tasr(0x2000, 0x2fff, 0, 0), "A"); space.put(tasr(0x2000, 0x2fff, 1, 1), "B"); @@ -418,7 +418,7 @@ public class DBTraceAddressSnapRangePropertyMapAddressSetViewTest @Test public void testUnion() { - try (UndoableTransaction trans = UndoableTransaction.start(obj, "Create Entries", true)) { + try (UndoableTransaction trans = UndoableTransaction.start(obj, "Create Entries")) { space.put(tasr(0x1000, 0x1fff, 0, 0), "A"); space.put(tasr(0x2000, 0x2fff, 0, 0), "A"); space.put(tasr(0x2000, 0x2fff, 1, 1), "B"); @@ -431,7 +431,7 @@ public class DBTraceAddressSnapRangePropertyMapAddressSetViewTest @Test public void testSubtract() { - try (UndoableTransaction trans = UndoableTransaction.start(obj, "Create Entries", true)) { + try (UndoableTransaction trans = UndoableTransaction.start(obj, "Create Entries")) { space.put(tasr(0x1000, 0x1fff, 0, 0), "A"); space.put(tasr(0x2000, 0x2fff, 0, 0), "A"); space.put(tasr(0x2000, 0x2fff, 1, 1), "B"); @@ -445,7 +445,7 @@ public class DBTraceAddressSnapRangePropertyMapAddressSetViewTest @Test public void testXor() { - try (UndoableTransaction trans = UndoableTransaction.start(obj, "Create Entries", true)) { + try (UndoableTransaction trans = UndoableTransaction.start(obj, "Create Entries")) { space.put(tasr(0x1000, 0x1fff, 0, 0), "A"); space.put(tasr(0x2000, 0x2fff, 0, 0), "A"); space.put(tasr(0x2000, 0x2fff, 1, 1), "B"); @@ -459,7 +459,7 @@ public class DBTraceAddressSnapRangePropertyMapAddressSetViewTest @Test public void testHasSameAddresses() { - try (UndoableTransaction trans = UndoableTransaction.start(obj, "Create Entries", true)) { + try (UndoableTransaction trans = UndoableTransaction.start(obj, "Create Entries")) { space.put(tasr(0x1000, 0x1fff, 0, 0), "A"); space.put(tasr(0x2000, 0x2fff, 0, 0), "A"); space.put(tasr(0x2000, 0x2fff, 1, 1), "B"); @@ -475,7 +475,7 @@ public class DBTraceAddressSnapRangePropertyMapAddressSetViewTest @Test public void testGetFirstLastRanges() { - try (UndoableTransaction trans = UndoableTransaction.start(obj, "Create Entries", true)) { + try (UndoableTransaction trans = UndoableTransaction.start(obj, "Create Entries")) { space.put(tasr(0x1000, 0x1fff, 0, 0), "A"); space.put(tasr(0x2000, 0x27ff, 0, 0), "A"); space.put(tasr(0x2000, 0x2fff, 1, 1), "B"); @@ -489,7 +489,7 @@ public class DBTraceAddressSnapRangePropertyMapAddressSetViewTest @Test public void testGetRangeContaining() { - try (UndoableTransaction trans = UndoableTransaction.start(obj, "Create Entries", true)) { + try (UndoableTransaction trans = UndoableTransaction.start(obj, "Create Entries")) { space.put(tasr(0x1000, 0x1fff, 0, 0), "A"); space.put(tasr(0x2000, 0x2fff, 0, 0), "A"); space.put(tasr(0x2000, 0x2fff, 1, 1), "B"); @@ -509,7 +509,7 @@ public class DBTraceAddressSnapRangePropertyMapAddressSetViewTest @Test public void testFindFirstAddressInCommon() { - try (UndoableTransaction trans = UndoableTransaction.start(obj, "Create Entries", true)) { + try (UndoableTransaction trans = UndoableTransaction.start(obj, "Create Entries")) { space.put(tasr(0x1000, 0x1fff, 0, 0), "A"); space.put(tasr(0x2000, 0x2fff, 0, 0), "A"); space.put(tasr(0x2000, 0x2fff, 1, 1), "B"); diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/map/DBTraceAddressSnapRangePropertyMapOcclusionIntoFutureIterableTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/map/DBTraceAddressSnapRangePropertyMapOcclusionIntoFutureIterableTest.java index f9175953cf..f4d9a9dee5 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/map/DBTraceAddressSnapRangePropertyMapOcclusionIntoFutureIterableTest.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/map/DBTraceAddressSnapRangePropertyMapOcclusionIntoFutureIterableTest.java @@ -157,7 +157,7 @@ public class DBTraceAddressSnapRangePropertyMapOcclusionIntoFutureIterableTest new LanguageID("Toy:BE:64:default")); obj = new MyObject(this); factory = new DBCachedObjectStoreFactory(obj); - try (UndoableTransaction tid = UndoableTransaction.start(obj, "CreateTable", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(obj, "CreateTable")) { space = new DBTraceAddressSnapRangePropertyMapSpace<>("Entries", factory, obj.getReadWriteLock(), toy.getDefaultSpace(), MyEntry.class, MyEntry::new); } @@ -188,7 +188,7 @@ public class DBTraceAddressSnapRangePropertyMapOcclusionIntoFutureIterableTest @Test public void testOutOfWindow() { DBTraceAddressSnapRangePropertyMapOcclusionIntoFutureIterable it; - try (UndoableTransaction tid = UndoableTransaction.start(obj, "Create Entries", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(obj, "Create Entries")) { space.put(tasr(0x1000, 0x1fff, 5, 10), "A"); } @@ -208,7 +208,7 @@ public class DBTraceAddressSnapRangePropertyMapOcclusionIntoFutureIterableTest @Test public void testSingleEntry() { DBTraceAddressSnapRangePropertyMapOcclusionIntoFutureIterable it; - try (UndoableTransaction tid = UndoableTransaction.start(obj, "Create Entries", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(obj, "Create Entries")) { space.put(tasr(0x1000, 0x1fff, 90, 95), "A"); } @@ -232,7 +232,7 @@ public class DBTraceAddressSnapRangePropertyMapOcclusionIntoFutureIterableTest @Test public void testEntriesAtExtremes() { DBTraceAddressSnapRangePropertyMapOcclusionIntoFutureIterable it; - try (UndoableTransaction tid = UndoableTransaction.start(obj, "Create Entries", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(obj, "Create Entries")) { space.put(tasr(0x0000, 0x0fff, 5, 10), "W"); space.put(tasr(-0x1000, -0x0001, 5, 10), "E"); space.put(tasr(0x1000, 0x1fff, Long.MIN_VALUE, Long.MIN_VALUE + 10), "S"); @@ -240,18 +240,18 @@ public class DBTraceAddressSnapRangePropertyMapOcclusionIntoFutureIterableTest } it = makeOcclusionIterable(tasr(0x0000, -0x0001, Long.MIN_VALUE, Long.MAX_VALUE)); - assertEquals(list( // - ent(0x0000, 0x0fff, 5, 10, "W"), // - ent(0x1000, 0x1fff, Long.MIN_VALUE, Long.MIN_VALUE + 10, "S"), // - ent(0x2000, 0x2fff, Long.MAX_VALUE - 10, Long.MAX_VALUE, "N"), // - ent(-0x1000, -0x0001, 5, 10, "E") // - ), list(it)); + assertEquals(list( + ent(0x0000, 0x0fff, 5, 10, "W"), + ent(0x1000, 0x1fff, Long.MIN_VALUE, Long.MIN_VALUE + 10, "S"), + ent(0x2000, 0x2fff, Long.MAX_VALUE - 10, Long.MAX_VALUE, "N"), + ent(-0x1000, -0x0001, 5, 10, "E")), + list(it)); } @Test public void testOcclusion() { DBTraceAddressSnapRangePropertyMapOcclusionIntoFutureIterable it; - try (UndoableTransaction tid = UndoableTransaction.start(obj, "Create Entries", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(obj, "Create Entries")) { space.put(tasr(0x1000, 0x1fff, 90, 95), "A"); space.put(tasr(0x1800, 0x27ff, 89, 95), "B"); diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/map/DBTraceAddressSnapRangePropertyMapOcclusionIntoPastIterableTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/map/DBTraceAddressSnapRangePropertyMapOcclusionIntoPastIterableTest.java index 054aee6be4..58bbcd89c3 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/map/DBTraceAddressSnapRangePropertyMapOcclusionIntoPastIterableTest.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/map/DBTraceAddressSnapRangePropertyMapOcclusionIntoPastIterableTest.java @@ -157,7 +157,7 @@ public class DBTraceAddressSnapRangePropertyMapOcclusionIntoPastIterableTest new LanguageID("Toy:BE:64:default")); obj = new MyObject(this); factory = new DBCachedObjectStoreFactory(obj); - try (UndoableTransaction tid = UndoableTransaction.start(obj, "CreateTable", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(obj, "CreateTable")) { space = new DBTraceAddressSnapRangePropertyMapSpace<>("Entries", factory, obj.getReadWriteLock(), toy.getDefaultSpace(), MyEntry.class, MyEntry::new); } @@ -188,7 +188,7 @@ public class DBTraceAddressSnapRangePropertyMapOcclusionIntoPastIterableTest @Test public void testOutOfWindow() { DBTraceAddressSnapRangePropertyMapOcclusionIntoPastIterable it; - try (UndoableTransaction tid = UndoableTransaction.start(obj, "Create Entries", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(obj, "Create Entries")) { space.put(tasr(0x1000, 0x1fff, 5, 10), "A"); } @@ -208,7 +208,7 @@ public class DBTraceAddressSnapRangePropertyMapOcclusionIntoPastIterableTest @Test public void testSingleEntry() { DBTraceAddressSnapRangePropertyMapOcclusionIntoPastIterable it; - try (UndoableTransaction tid = UndoableTransaction.start(obj, "Create Entries", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(obj, "Create Entries")) { space.put(tasr(0x1000, 0x1fff, 5, 10), "A"); } @@ -232,7 +232,7 @@ public class DBTraceAddressSnapRangePropertyMapOcclusionIntoPastIterableTest @Test public void testEntriesAtExtremes() { DBTraceAddressSnapRangePropertyMapOcclusionIntoPastIterable it; - try (UndoableTransaction tid = UndoableTransaction.start(obj, "Create Entries", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(obj, "Create Entries")) { space.put(tasr(0x0000, 0x0fff, 5, 10), "W"); space.put(tasr(-0x1000, -0x0001, 5, 10), "E"); space.put(tasr(0x1000, 0x1fff, Long.MIN_VALUE, Long.MIN_VALUE + 10), "S"); @@ -251,7 +251,7 @@ public class DBTraceAddressSnapRangePropertyMapOcclusionIntoPastIterableTest @Test public void testOcclusion() { DBTraceAddressSnapRangePropertyMapOcclusionIntoPastIterable it; - try (UndoableTransaction tid = UndoableTransaction.start(obj, "Create Entries", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(obj, "Create Entries")) { space.put(tasr(0x1000, 0x1fff, 5, 10), "A"); space.put(tasr(0x1800, 0x27ff, 5, 11), "B"); diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/map/DBTraceAddressSnapRangePropertyMapSpaceTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/map/DBTraceAddressSnapRangePropertyMapSpaceTest.java index a84a4628d9..0c41b3851a 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/map/DBTraceAddressSnapRangePropertyMapSpaceTest.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/map/DBTraceAddressSnapRangePropertyMapSpaceTest.java @@ -80,7 +80,7 @@ public class DBTraceAddressSnapRangePropertyMapSpaceTest } protected void loadSpaces() throws VersionException, IOException { - try (UndoableTransaction tid = UndoableTransaction.start(this, "Create Tables", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(this, "Create Tables")) { this.space1 = new DBTraceAddressSnapRangePropertyMapSpace<>("Entries1", factory, getReadWriteLock(), toy.getDefaultSpace(), MyEntry.class, MyEntry::new); this.space2 = new DBTraceAddressSnapRangePropertyMapSpace<>("Entries2", factory, @@ -236,7 +236,7 @@ public class DBTraceAddressSnapRangePropertyMapSpaceTest @Test public void testDeleteValue() { - try (UndoableTransaction tid = UndoableTransaction.start(obj, "Create entries", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(obj, "Create entries")) { MyEntry entry1 = obj.space1.put(at(0x1000, 5), null); MyEntry entry2 = obj.space2.put(at(0x1001, 5), null); String value3 = obj.space3.put(at(0x1002, 5), "Test"); @@ -268,7 +268,7 @@ public class DBTraceAddressSnapRangePropertyMapSpaceTest @Test @Ignore("TODO") public void testRemove() { - try (UndoableTransaction tid = UndoableTransaction.start(obj, "Create entries", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(obj, "Create entries")) { obj.space1.put(at(0x1000, 5), null); obj.space2.put(at(0x1000, 5), null); assertEquals(1, obj.space1.size()); @@ -308,7 +308,7 @@ public class DBTraceAddressSnapRangePropertyMapSpaceTest public void testCollections() { MyEntry entry1; MyEntry entry2; - try (UndoableTransaction tid = UndoableTransaction.start(obj, "Create entries", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(obj, "Create entries")) { entry1 = obj.space1.put(new ImmutableTraceAddressSnapRange(addr(0x1000), 5), null); entry2 = obj.space1.put(new ImmutableTraceAddressSnapRange(addr(0x1001), 6), null); } @@ -329,7 +329,7 @@ public class DBTraceAddressSnapRangePropertyMapSpaceTest @Test public void testReduce() { MyEntry ent1; - try (UndoableTransaction tid = UndoableTransaction.start(obj, "Create entries", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(obj, "Create entries")) { ent1 = obj.space1.put(at(0x1000, 5), null); } @@ -342,7 +342,7 @@ public class DBTraceAddressSnapRangePropertyMapSpaceTest @Test public void testFirsts() { MyEntry entry1; - try (UndoableTransaction tid = UndoableTransaction.start(obj, "Create entries", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(obj, "Create entries")) { entry1 = obj.space1.put(new ImmutableTraceAddressSnapRange(addr(0x1000), 5), null); } @@ -353,7 +353,7 @@ public class DBTraceAddressSnapRangePropertyMapSpaceTest @Test public void testClear() { - try (UndoableTransaction tid = UndoableTransaction.start(obj, "Create entries", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(obj, "Create entries")) { MyEntry entry1 = obj.space1.put(new ImmutableTraceAddressSnapRange(addr(0x1000), 5), null); assertEquals(1, obj.space1.size()); @@ -369,7 +369,7 @@ public class DBTraceAddressSnapRangePropertyMapSpaceTest public void testGetDataByKey() { assertNull(obj.space1.getDataByKey(0)); MyEntry entry1; - try (UndoableTransaction tid = UndoableTransaction.start(obj, "Create entries", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(obj, "Create entries")) { entry1 = obj.space1.put(new ImmutableTraceAddressSnapRange(addr(0x1000), 5), null); } @@ -381,7 +381,7 @@ public class DBTraceAddressSnapRangePropertyMapSpaceTest @Ignore("TODO") public void testSaveAndLoad() throws IOException, CancelledException, VersionException { MyEntry entry1; - try (UndoableTransaction tid = UndoableTransaction.start(obj, "Create entries", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(obj, "Create entries")) { entry1 = obj.space1.put(new ImmutableTraceAddressSnapRange(addr(0x1000), 5), null); } assertEquals(ent(0x1000, 5, entry1), obj.space1.firstEntry()); @@ -400,12 +400,12 @@ public class DBTraceAddressSnapRangePropertyMapSpaceTest @Ignore("Related to GP-479") public void testUndoThenRedo() throws IOException { MyEntry entry1; - try (UndoableTransaction tid = UndoableTransaction.start(obj, "Create entries", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(obj, "Create entries")) { entry1 = obj.space1.put(new ImmutableTraceAddressSnapRange(addr(0x1000), 5), null); } assertEquals(ent(0x1000, 5, entry1), obj.space1.firstEntry()); - try (UndoableTransaction tid = UndoableTransaction.start(obj, "Clear", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(obj, "Clear")) { obj.space1.clear(); } assertNull(obj.space1.firstEntry()); diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/module/DBTraceStaticMappingManagerTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/module/DBTraceStaticMappingManagerTest.java index 040eab0917..262e01e96c 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/module/DBTraceStaticMappingManagerTest.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/module/DBTraceStaticMappingManagerTest.java @@ -34,49 +34,50 @@ import ghidra.util.database.UndoableTransaction; public class DBTraceStaticMappingManagerTest extends AbstractGhidraHeadlessIntegrationTest { - ToyDBTraceBuilder b; + ToyDBTraceBuilder tb; DBTraceStaticMappingManager staticMappingManager; @Before public void setUpStaticMappingManagerTest() throws IOException { - b = new ToyDBTraceBuilder("Testing", "Toy:BE:64:default"); - staticMappingManager = b.trace.getStaticMappingManager(); + tb = new ToyDBTraceBuilder("Testing", "Toy:BE:64:default"); + staticMappingManager = tb.trace.getStaticMappingManager(); } @After public void tearDownStaticMappingManagerTest() { - b.close(); + tb.close(); } @Test public void testAddAndGet() throws Exception { - try (UndoableTransaction tid = b.startTransaction()) { - staticMappingManager.add(b.range(0xdeadbeef, 0xdeadbeef + 99), Range.closed(2L, 5L), + try (UndoableTransaction tid = tb.startTransaction()) { + staticMappingManager.add(tb.range(0xdeadbeef, 0xdeadbeef + 99), Range.closed(2L, 5L), new URL("ghidra://static"), "DEADBEEF"); } - DBTraceStaticMapping found = staticMappingManager.findContaining(b.addr(0xdeadbeef), 2); - assertEquals(b.addr(0xdeadbeef), found.getMinTraceAddress()); + DBTraceStaticMapping found = staticMappingManager.findContaining(tb.addr(0xdeadbeef), 2); + assertEquals(tb.addr(0xdeadbeef), found.getMinTraceAddress()); assertEquals(100, found.getLength()); assertEquals(2, found.getStartSnap()); assertEquals(5, found.getEndSnap()); assertEquals(new URL("ghidra://static"), found.getStaticProgramURL()); assertEquals("DEADBEEF", found.getStaticAddress()); - assertEquals(found, staticMappingManager.findContaining(b.addr(0xdeadbeef + 99), 2)); - assertEquals(found, staticMappingManager.findContaining(b.addr(0xdeadbeef + 99), 5)); - assertEquals(found, staticMappingManager.findContaining(b.addr(0xdeadbeef), 5)); + assertEquals(found, staticMappingManager.findContaining(tb.addr(0xdeadbeef + 99), 2)); + assertEquals(found, staticMappingManager.findContaining(tb.addr(0xdeadbeef + 99), 5)); + assertEquals(found, staticMappingManager.findContaining(tb.addr(0xdeadbeef), 5)); - assertNull(staticMappingManager.findContaining(b.addr(0xdeadbeef - 1), 2)); - assertNull(staticMappingManager.findContaining(b.addr(0xdeadbeef + 100), 2)); - assertNull(staticMappingManager.findContaining(b.addr(0xdeadbeef), 1)); - assertNull(staticMappingManager.findContaining(b.addr(0xdeadbeef), 6)); + assertNull(staticMappingManager.findContaining(tb.addr(0xdeadbeef - 1), 2)); + assertNull(staticMappingManager.findContaining(tb.addr(0xdeadbeef + 100), 2)); + assertNull(staticMappingManager.findContaining(tb.addr(0xdeadbeef), 1)); + assertNull(staticMappingManager.findContaining(tb.addr(0xdeadbeef), 6)); } @Test public void testAddAndEnumerate() throws Exception { - try (UndoableTransaction tid = UndoableTransaction.start(b.trace, "Testing", true)) { - staticMappingManager.add(b.range(0xdeadbeef, 0xdeadbeef + 99), Range.closedOpen(2L, 5L), + try (UndoableTransaction tid = tb.startTransaction()) { + staticMappingManager.add(tb.range(0xdeadbeef, 0xdeadbeef + 99), + Range.closedOpen(2L, 5L), new URL("ghidra://static"), "DEADBEEF"); } @@ -86,10 +87,11 @@ public class DBTraceStaticMappingManagerTest extends AbstractGhidraHeadlessInteg @Test public void testAddRemoveAndEnumerate() throws Exception { - try (UndoableTransaction tid = UndoableTransaction.start(b.trace, "Testing", true)) { - staticMappingManager.add(b.range(0xdeadbeef, 0xdeadbeef + 99), Range.closedOpen(2L, 5L), + try (UndoableTransaction tid = tb.startTransaction()) { + staticMappingManager.add(tb.range(0xdeadbeef, 0xdeadbeef + 99), + Range.closedOpen(2L, 5L), new URL("ghidra://static"), "DEADBEEF"); - staticMappingManager.add(b.range(0xdeadbeef, 0xdeadbeef + 99), + staticMappingManager.add(tb.range(0xdeadbeef, 0xdeadbeef + 99), Range.closedOpen(7L, 10L), new URL("ghidra://static"), "DEADBEEF"); @@ -105,10 +107,11 @@ public class DBTraceStaticMappingManagerTest extends AbstractGhidraHeadlessInteg @Test public void testOverlapCausesException() throws Exception { - try (UndoableTransaction tid = UndoableTransaction.start(b.trace, "Testing", true)) { - staticMappingManager.add(b.range(0xdeadbeef, 0xdeadbeef + 99), Range.closedOpen(2L, 5L), + try (UndoableTransaction tid = tb.startTransaction()) { + staticMappingManager.add(tb.range(0xdeadbeef, 0xdeadbeef + 99), + Range.closedOpen(2L, 5L), new URL("ghidra://static"), "DEADBEEF"); - staticMappingManager.add(b.range(0xdeadbeef + 80, 0xdeadbeef + 179), + staticMappingManager.add(tb.range(0xdeadbeef + 80, 0xdeadbeef + 179), Range.closedOpen(2L, 5L), new URL("ghidra://static"), "DEADBEEF"); fail(); } @@ -119,20 +122,22 @@ public class DBTraceStaticMappingManagerTest extends AbstractGhidraHeadlessInteg @Test public void testOverlapAgreeingAccepted() throws Exception { - try (UndoableTransaction tid = UndoableTransaction.start(b.trace, "Testing", true)) { - staticMappingManager.add(b.range(0xdeadbeef, 0xdeadbeef + 99), Range.closedOpen(2L, 5L), + try (UndoableTransaction tid = tb.startTransaction()) { + staticMappingManager.add(tb.range(0xdeadbeef, 0xdeadbeef + 99), + Range.closedOpen(2L, 5L), new URL("ghidra://static"), "DEADBEEF"); - staticMappingManager.add(b.range(0xdeadbeef + 80, 0xdeadbeef + 179), + staticMappingManager.add(tb.range(0xdeadbeef + 80, 0xdeadbeef + 179), Range.closedOpen(2L, 5L), new URL("ghidra://static"), "DEADBF3F"); } } @Test public void testTouchingProceedingIsNotOverlapping() throws Exception { - try (UndoableTransaction tid = UndoableTransaction.start(b.trace, "Testing", true)) { - staticMappingManager.add(b.range(0xdeadbeef, 0xdeadbeef + 99), Range.closedOpen(2L, 5L), + try (UndoableTransaction tid = tb.startTransaction()) { + staticMappingManager.add(tb.range(0xdeadbeef, 0xdeadbeef + 99), + Range.closedOpen(2L, 5L), new URL("ghidra://static"), "DEADBEEF"); - staticMappingManager.add(b.range(0xdeadbeef + 100, 0xdeadbeef + 199), + staticMappingManager.add(tb.range(0xdeadbeef + 100, 0xdeadbeef + 199), Range.closedOpen(2L, 5L), new URL("ghidra://static"), "DEADBEEF"); } } @@ -140,12 +145,12 @@ public class DBTraceStaticMappingManagerTest extends AbstractGhidraHeadlessInteg @SuppressWarnings("hiding") @Test public void testSaveAndLoad() throws Exception { - try (UndoableTransaction tid = UndoableTransaction.start(b.trace, "Testing", true)) { - staticMappingManager.add(b.range(0xdeadbeef, 0xdeadbeef + 99), Range.closed(2L, 5L), + try (UndoableTransaction tid = tb.startTransaction()) { + staticMappingManager.add(tb.range(0xdeadbeef, 0xdeadbeef + 99), Range.closed(2L, 5L), new URL("ghidra://static"), "DEADBEEF"); } - File tmp = b.save(); + File tmp = tb.save(); try (ToyDBTraceBuilder b = new ToyDBTraceBuilder(tmp)) { DBTraceStaticMappingManager staticMappingManager = b.trace.getStaticMappingManager(); DBTraceStaticMapping found = @@ -161,8 +166,9 @@ public class DBTraceStaticMappingManagerTest extends AbstractGhidraHeadlessInteg @Test public void testAddButAbortedStillEmpty() throws Exception { - try (UndoableTransaction tid = UndoableTransaction.start(b.trace, "Testing", true)) { - staticMappingManager.add(b.range(0xdeadbeef, 0xdeadbeef + 99), Range.closedOpen(2L, 5L), + try (UndoableTransaction tid = tb.startTransaction()) { + staticMappingManager.add(tb.range(0xdeadbeef, 0xdeadbeef + 99), + Range.closedOpen(2L, 5L), new URL("ghidra://static"), "DEADBEEF"); tid.abort(); } @@ -172,29 +178,31 @@ public class DBTraceStaticMappingManagerTest extends AbstractGhidraHeadlessInteg @Test public void testAddThenUndo() throws Exception { - try (UndoableTransaction tid = UndoableTransaction.start(b.trace, "Testing", true)) { - staticMappingManager.add(b.range(0xdeadbeef, 0xdeadbeef + 99), Range.closedOpen(2L, 5L), + try (UndoableTransaction tid = tb.startTransaction()) { + staticMappingManager.add(tb.range(0xdeadbeef, 0xdeadbeef + 99), + Range.closedOpen(2L, 5L), new URL("ghidra://static"), "DEADBEEF"); } - b.trace.undo(); + tb.trace.undo(); assertEquals(0, staticMappingManager.getAllEntries().size()); } @Test public void testAddThenRemoveThenUndo() throws Exception { - try (UndoableTransaction tid = UndoableTransaction.start(b.trace, "Testing", true)) { - staticMappingManager.add(b.range(0xdeadbeef, 0xdeadbeef + 99), Range.closedOpen(2L, 5L), + try (UndoableTransaction tid = tb.startTransaction()) { + staticMappingManager.add(tb.range(0xdeadbeef, 0xdeadbeef + 99), + Range.closedOpen(2L, 5L), new URL("ghidra://static"), "DEADBEEF"); } assertEquals(1, staticMappingManager.getAllEntries().size()); - try (UndoableTransaction tid = UndoableTransaction.start(b.trace, "Testing", true)) { + try (UndoableTransaction tid = tb.startTransaction()) { for (TraceStaticMapping m : staticMappingManager.getAllEntries()) { m.delete(); } } assertEquals(0, staticMappingManager.getAllEntries().size()); - b.trace.undo(); + tb.trace.undo(); assertEquals(1, staticMappingManager.getAllEntries().size()); } } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceDisassemblerIntegrationTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceDisassemblerIntegrationTest.java index a996c98fd8..9c7ce63c1f 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceDisassemblerIntegrationTest.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceDisassemblerIntegrationTest.java @@ -142,7 +142,7 @@ public class DBTraceDisassemblerIntegrationTest extends AbstractGhidraHeadlessIn public void testThumbSampleProgramDB() throws Exception { ProgramBuilder b = new ProgramBuilder(getName(), ProgramBuilder._ARM); try (UndoableTransaction tid = - UndoableTransaction.start(b.getProgram(), "Disassemble (THUMB)", true)) { + UndoableTransaction.start(b.getProgram(), "Disassemble (THUMB)")) { MemoryBlock text = b.createMemory(".text", "b6fa2cd0", 32, "Sample", (byte) 0); text.putBytes(b.addr(0xb6fa2cdc), new byte[] { // GDB: stmdb sp!, {r4,r5,r6,r7,r8,lr} diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/pcode/struct/DefaultVar.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/pcode/struct/DefaultVar.java index 37fc9a3b16..54c020d460 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/pcode/struct/DefaultVar.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/pcode/struct/DefaultVar.java @@ -83,7 +83,7 @@ class DefaultVar implements LValInternal, Var { check.check(ctx.parser, name); this.ctx = ctx; this.name = name; - try (UndoableTransaction tid = UndoableTransaction.start(ctx.dtm, "Resolve type", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(ctx.dtm, "Resolve type")) { this.type = ctx.dtm.resolve(type, DataTypeConflictHandler.DEFAULT_HANDLER); } } diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/pcode/struct/Expr.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/pcode/struct/Expr.java index 4812568118..0bca8e83dd 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/pcode/struct/Expr.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/pcode/struct/Expr.java @@ -26,7 +26,7 @@ public abstract class Expr implements RValInternal { protected Expr(StructuredSleigh ctx, DataType type) { this.ctx = ctx; - try (UndoableTransaction tid = UndoableTransaction.start(ctx.dtm, "Resolve type", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(ctx.dtm, "Resolve type")) { this.type = ctx.dtm.resolve(type, DataTypeConflictHandler.DEFAULT_HANDLER); } } diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/AbstractDirectedLongKeyIterator.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/AbstractDirectedLongKeyIterator.java index 02dc07a3e2..019ab23dec 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/AbstractDirectedLongKeyIterator.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/AbstractDirectedLongKeyIterator.java @@ -19,9 +19,21 @@ import java.io.IOException; import db.DBLongIterator; +/** + * An abstract implementation of {@link DirectedLongKeyIterator} + * + *

+ * Essentially, this just wraps a {@link DBLongIterator}, but imposes and encapsulates its + * direction. + */ public abstract class AbstractDirectedLongKeyIterator implements DirectedLongKeyIterator { protected final DBLongIterator it; + /** + * Wrap the given iterator + * + * @param it the iterator + */ public AbstractDirectedLongKeyIterator(DBLongIterator it) { this.it = it; } diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/AbstractDirectedRecordIterator.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/AbstractDirectedRecordIterator.java index 4a5120b3ea..e8d8f1ebdc 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/AbstractDirectedRecordIterator.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/AbstractDirectedRecordIterator.java @@ -19,9 +19,21 @@ import java.io.IOException; import db.RecordIterator; +/** + * An abstract implementation of {@link DirectedRecordIterator} + * + *

+ * Essentially, this just wraps a {@link RecordIterator}, but imposes and encapsulates its + * direction. + */ public abstract class AbstractDirectedRecordIterator implements DirectedRecordIterator { protected final RecordIterator it; + /** + * Wrap the given iterator + * + * @param it the iterator + */ public AbstractDirectedRecordIterator(RecordIterator it) { this.it = it; } diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/BackwardLongKeyIterator.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/BackwardLongKeyIterator.java index 43a3272de9..dff5136fbd 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/BackwardLongKeyIterator.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/BackwardLongKeyIterator.java @@ -19,6 +19,10 @@ import java.io.IOException; import db.DBLongIterator; +/** + * A wrapper of {@link DBLongIterator} that runs it backward and implements + * {@link DirectedLongKeyIterator} + */ public class BackwardLongKeyIterator extends AbstractDirectedLongKeyIterator { public BackwardLongKeyIterator(DBLongIterator it) { super(it); diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/BackwardRecordIterator.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/BackwardRecordIterator.java index 718aaa3c78..17989ce787 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/BackwardRecordIterator.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/BackwardRecordIterator.java @@ -20,6 +20,10 @@ import java.io.IOException; import db.DBRecord; import db.RecordIterator; +/** + * A wrapper of {@link RecordIterator} that runs it backward and implements + * {@link DirectedRecordIterator} + */ public class BackwardRecordIterator extends AbstractDirectedRecordIterator { public BackwardRecordIterator(RecordIterator it) { super(it); diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBAnnotatedObject.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBAnnotatedObject.java index 2edc25eade..86a3d82876 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBAnnotatedObject.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBAnnotatedObject.java @@ -22,16 +22,115 @@ import db.DBRecord; import ghidra.program.database.DatabaseObject; import ghidra.util.LockHold; import ghidra.util.database.DBCachedObjectStoreFactory.DBFieldCodec; +import ghidra.util.database.annot.DBAnnotatedObjectInfo; +/** + * An object backed by a {@link DBRecord} + * + *

+ * Essentially, this is a data access object (DAO) for Ghidra's custom database engine. Not all + * object fields necessarily have a corresponding database field. Instead, those fields are + * annotated, and various methods are provided for updating the record, and conversely, re-loading + * fields from the record. These objects are managed using a {@link DBCachedObjectStore}. An example + * object definition: + * + *

+ * interface Person {
+ * 	// ...
+ * }
+ * 
+ * @DBAnnotatedObjectInfo(version = 1)
+ * public class DBPerson extends DBAnnotatedObject implements Person {
+ * 	public static final String TABLE_NAME = "Person"; // Conventionally defined here
+ * 
+ * 	// Best practice is to define column names, then use in annotations
+ * 	static final String NAME_COLUMN_NAME = "Name";
+ * 	static final String ADDRESS_COLUMN_NAME = "Address";
+ * 
+ * 	// Column handles
+ * 	@DBAnnotatedColumn(NAME_COLUMN_NAME)
+ * 	static DBObjectColumn NAME_COLUMN;
+ * 	@DBAnnotatedColumn(ADDRESS_COLUMN_NAME)
+ * 	static DBObjectColumn ADDRESS_COLUMN;
+ * 
+ * 	// Column-backed fields
+ * 	@DBAnnotatedField(column = NAME_COLUMN_NAME, indexed = true)
+ * 	private String name;
+ * 	@DBAnnotatedField(column = ADDRESS_COLUMN_NAME)
+ * 	private String address;
+ * 
+ * 	DBPerson(DBCachedObjectStore store, DBRecord record) {
+ * 		super(store, record);
+ * 	}
+ * 
+ * 	// Not required, but best practice
+ * 	private void set(String name, String address) {
+ * 		this.name = name;
+ * 		this.address = address;
+ * 		update(NAME_COLUMN, ADDRESS_COLUMN);
+ * 	}
+ * 
+ * 	// ... other methods, getters, setters
+ * }
+ * 
+ * + *

+ * See {@link DBCachedObjectStoreFactory} for example code that uses the example {@code DBPerson} + * class. + * + *

+ * All realizations of {@link DBAnnotatedObject} must be annotated with + * {@link DBAnnotatedObjectInfo}. This, along with the field annotations, are used to derive the + * table schema. Note the inclusion of a {@code TABLE_NAME} field. It is not required, nor is it + * used implicitly. It's included in this example as a manner of demonstrating best practice. When + * instantiating the object store, the field is used to provide the table name. + *

+ * Next, we define the column names. These are not required nor used implicitly, but using literal + * strings in the column annotations is discouraged. Next, we declare variables to receive column + * handles. These are essentially the column numbers, but we have a named handle for each. They are + * initialized automatically the first time a store is created for this class. + *

+ * Next we declare the variables representing the actual column values. Their initialization varies + * depending on how the object is instantiated. When creating a new object, the fields remain + * uninitialized. In some cases, it may be appropriate to provide an initial (default) value in the + * usual fashion, e.g., {@code private String address = "123 Pine St.";} In this case, the + * corresponding database field of the backing record is implicitly initialized upon creation. If + * the object is being loaded from a table, its fields are initialized with values from its backing + * record. + * + *

+ * Next we define the constructor. There are no requirements on its signature, but it must call + * {@link #DBAnnotatedObject(DBCachedObjectStore, DBRecord) super}, so it likely takes its + * containing store and its backing record. Having the same signature as its super constructor + * allows the store to be created using a simple method reference, e.g., {@code DBPerson::new}. + * Additional user-defined parameters may be accepted. To pass such parameters, a lambda is + * recommended when creating the object store. + *

+ * Finally, we demonstrate how to update the record. The record is not implicitly updated + * by direct modification of an annotated field. All setters must call + * {@link #update(DBObjectColumn...)} after updating a field. A common practice, especially when the + * object will have all its fields set at once, is to include a {@code set} method that initializes + * the fields and updates the record in one {@link #update(DBObjectColumn...)}. + * + *

+ * Note that there is no way to specify the primary key. For object stores, the primary key is + * always the object id, and its type is always {@code long}. + */ public class DBAnnotatedObject extends DatabaseObject { private final DBCachedObjectStore store; private final DBCachedDomainObjectAdapter adapter; - private final List> codecs; + private final List> codecs; // The codecs, ordered by field - DBRecord record; + DBRecord record; // The backing record + /** + * The object constructor + * + * @param store the store containing this object + * @param record the record backing this object + */ @SuppressWarnings({ "unchecked", "rawtypes" }) - public DBAnnotatedObject(DBCachedObjectStore store, DBRecord record) { + protected DBAnnotatedObject(DBCachedObjectStore store, DBRecord record) { super(store == null ? null : store.cache, record == null ? -1 : record.getKey()); this.store = store; this.record = record; @@ -51,54 +150,77 @@ public class DBAnnotatedObject extends DatabaseObject { * @return the opaque object id */ public ObjectKey getObjectKey() { - return new ObjectKey(store.adapter, store.table.getName(), key); + return new ObjectKey(store.table, key); } @SuppressWarnings({ "rawtypes", "unchecked" }) - protected void write(DBObjectColumn column) { + protected void doWrite(DBObjectColumn column) { DBFieldCodec codec = codecs.get(column.columnNumber); codec.store(this, record); } + /** + * 1-arity version of {@link #update(DBObjectColumn...)} + * + * @param column the column + */ protected void update(DBObjectColumn column) { - write(column); + doWrite(column); try (LockHold hold = LockHold.lock(store.writeLock())) { - updated(); + doUpdated(); } catch (IOException e) { store.dbError(e); } } + /** + * 2-arity version of {@link #update(DBObjectColumn...)} + * + * @param col1 a column + * @param col2 another column + */ protected void update(DBObjectColumn col1, DBObjectColumn col2) { - write(col1); - write(col2); + doWrite(col1); + doWrite(col2); try (LockHold hold = LockHold.lock(store.writeLock())) { - updated(); + doUpdated(); } catch (IOException e) { store.dbError(e); } } + /** + * 2-arity version of {@link #update(DBObjectColumn...)} + * + * @param col1 a column + * @param col2 another column + * @param col3 another column + */ protected void update(DBObjectColumn col1, DBObjectColumn col2, DBObjectColumn col3) { - write(col1); - write(col2); - write(col3); + doWrite(col1); + doWrite(col2); + doWrite(col3); try (LockHold hold = LockHold.lock(store.writeLock())) { - updated(); + doUpdated(); } catch (IOException e) { store.dbError(e); } } + /** + * Write the given columns into the record and update the table + * + * @param columns the columns to update + */ protected void update(DBObjectColumn... columns) { for (DBObjectColumn c : columns) { - write(c); + doWrite(c); } try (LockHold hold = LockHold.lock(store.writeLock())) { - updated(); + doUpdated(); } catch (IOException e) { store.dbError(e); @@ -110,28 +232,36 @@ public class DBAnnotatedObject extends DatabaseObject { for (DBFieldCodec codec : codecs) { codec.store(this, record); } - updated(); + doUpdated(); } - protected void updated() throws IOException { + protected void doUpdated() throws IOException { store.table.putRecord(record); } /** - * Called when the object's fields are populated. + * Extension point: Called when the object's fields are populated. * - * This provides an opportunity for the object to initialize any remaining (usually - * non-database-backed) fields. + *

+ * This provides an opportunity for the object to initialize any non-database-backed fields that + * depend on the database-backed fields. Note that its use may indicate a situation better + * solved by a custom {@link DBFieldCodec}. If both the database-backed and non-database-backed + * fields are used frequently, then a codec may not be indicated. If the database-backed fields + * are only used in this method or to encode another frequently-used field, then a codec is + * likely better. * + *

* For a new object, the database-backed fields remain at their initial values. They will be * saved after this method returns, so they may be further initialized with custom logic. * - * For an object loaded from the database, the database-backed fields were already populated - * from the record. They are not automatically saved after this method returns. This - * method should not further initialize database-backed fields in this case. + *

+ * For an object loaded from the database, the database-backed fields are already populated from + * the record when this method is called. They are not automatically saved after this + * method returns. This method should not further initialize database-backed fields in this + * case. * - * @param created {@code true} to indicate the object is being created, or {@code false} to - * indicate it is being restored. + * @param created {@code true} when object is being created, or {@code false} when it is being + * loaded. * @throws IOException if further initialization fails. */ protected void fresh(boolean created) throws IOException { @@ -187,6 +317,12 @@ public class DBAnnotatedObject extends DatabaseObject { return true; } + /** + * Check if this object has been deleted + * + * @see #isDeleted(ghidra.util.Lock) + * @return true if deleted + */ public boolean isDeleted() { return super.isDeleted(adapter.getLock()); } diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBAnnotatedObjectFactory.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBAnnotatedObjectFactory.java index 69b9568638..0af1ee253e 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBAnnotatedObjectFactory.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBAnnotatedObjectFactory.java @@ -17,6 +17,11 @@ package ghidra.util.database; import db.DBRecord; +/** + * Needed by a {@link DBCachedObjectStore} to describe how to construct the objects it manages + * + * @param the type of objects in the store + */ public interface DBAnnotatedObjectFactory { T create(DBCachedObjectStore store, DBRecord record); } diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedDomainObjectAdapter.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedDomainObjectAdapter.java index b764528809..8878fbe6d4 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedDomainObjectAdapter.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedDomainObjectAdapter.java @@ -24,6 +24,15 @@ import ghidra.util.Msg; import ghidra.util.Swing; import ghidra.util.task.TaskMonitor; +/** + * A domain object that can use {@link DBCachedObjectStoreFactory}. + * + *

+ * Technically, this only introduces a read-write lock to the domain object. The + * {@link DBCachedObjectStoreFactory} and related require this read-write lock. Sadly, this idea + * didn't pan out, and that read-write lock is just a degenerate wrapper of the Ghidra + * {@link ghidra.util.Lock}, which is not a read-write lock. This class may disappear. + */ public abstract class DBCachedDomainObjectAdapter extends DBDomainObjectSupport { static class SwingAwareReadWriteLock extends ReentrantReadWriteLock { @@ -151,12 +160,20 @@ public abstract class DBCachedDomainObjectAdapter extends DBDomainObjectSupport protected ReadWriteLock rwLock; + /** + * @see {@link DBDomainObjectSupport} + */ protected DBCachedDomainObjectAdapter(DBHandle dbh, DBOpenMode openMode, TaskMonitor monitor, String name, int timeInterval, int bufSize, Object consumer) { super(dbh, openMode, monitor, name, timeInterval, bufSize, consumer); this.rwLock = new GhidraLockWrappingRWLock(lock); } + /** + * Get the "read-write" lock + * + * @return the lock + */ public ReadWriteLock getReadWriteLock() { return rwLock; } diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectIndex.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectIndex.java index 83d44385d4..2e818b3592 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectIndex.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectIndex.java @@ -27,12 +27,20 @@ import ghidra.util.database.DBCachedObjectStoreFactory.DBFieldCodec; import ghidra.util.database.DirectedIterator.Direction; /** + * An index on a field in a {@link DBCachedObjectStore} * - * NOTE: This seems ripe for implementing a collection interface, but each defies implementation on - * our DB framework. + *

+ * This provides access to a table index backing the store, allowing clients to retrieve objects + * having specified field values. Its methods are inspired by {@link NavigableMap}; however, its + * semantics permit duplicate keys, so this cannot implement it in the manner desired. + * + * @implNote This seems rife for implementing a collection interface, but each defies implementation + * on our DB framework. Probably because it's better understood as a multimap, which is + * not a standard Java collection. Guava's proved too burdensome to implement. We never + * tried Apache's. * - * @param - * @param + * @param the type of keys in the index, i.e., the indexed field's type + * @param the type of objects in the store */ public class DBCachedObjectIndex { protected final DBCachedObjectStore store; @@ -43,6 +51,19 @@ public class DBCachedObjectIndex { protected final Range fieldRange; protected final Direction direction; + /** + * Construct an index + * + *

+ * Clients should use {@link DBCachedObjectStore#getIndex(Class, DBObjectColumn)}. + * + * @param store the store containing the indexed objects + * @param errHandler an error handler + * @param codec the codec for the indexed field/column + * @param columnIndex the column number + * @param fieldRange required: the restricted range, can be {@link Range#all()} + * @param direction the sort order / direction of iteration + */ protected DBCachedObjectIndex(DBCachedObjectStore store, ErrorHandler errHandler, DBFieldCodec codec, int columnIndex, Range fieldRange, Direction direction) { @@ -54,45 +75,83 @@ public class DBCachedObjectIndex { this.direction = direction; } - public DBCachedObjectStoreFoundKeysValueCollection get(K key) { - Field field = codec.encodeField(key); - if (!fieldRange.contains(field)) { - return null; - } + protected Collection get(Field encoded) { try { - return store.findObjects(columnIndex, field); + return store.findObjects(columnIndex, encoded); } catch (IOException e) { errHandler.dbError(e); - return null; + return List.of(); } } /** + * Get the objects having the given value in the indexed field * - * NOTE: Not sensitive to bounds at all + *

+ * NOTE: The objects' primary keys are retrieved immediately, but the returned collection + * loads each requested object lazily. This may have timing implications. If the returned + * collection is used at a later time, the keys found may no longer be valid, and even if they + * are, the indexed field may no longer have the requested value when retrieved. See + * {@link #getLazily(Object)}. * - * @param key - * @return + * @param key the value + * @return the collection of objects + */ + public Collection get(K key) { + Field encoded = codec.encodeField(key); + if (!fieldRange.contains(encoded)) { + return List.of(); + } + return get(encoded); + } + + /** + * Get the objects having the given value in the index field + * + *

+ * This differs from {@link #get(Object)} in that the keys are retrieved each time the + * collection is iterated. The returned collection can be saved and used later. The iterator + * itself still has a fixed set of keys, though, so clients should use it and discard it in a + * timely fashion, and/or while holding the domain object's lock. + * + * @param key the value + * @return the lazy collection of objects */ public Collection getLazily(K key) { + Field encoded = codec.encodeField(key); + if (!fieldRange.contains(encoded)) { + return List.of(); + } return new AbstractCollection<>() { @Override public Iterator iterator() { - return get(key).iterator(); + return get(encoded).iterator(); } @Override public int size() { - return countKey(key); + return countKey(encoded); } public boolean isEmpty() { - return !containsKey(key); + return !containsKey(encoded); } }; } + /** + * Get a unique object having the given value in the index field + * + *

+ * Clients should use this method when the index behaves like a map, rather than a multimap. It + * is the client's responsibility to ensure that duplicate values do not exist in the indexed + * column. + * + * @param value the value + * @return the object, if found, or null + * @throws IllegalStateException if the object is not unique + */ public T getOne(K value) { Field field = codec.encodeField(value); if (!fieldRange.contains(field)) { @@ -107,6 +166,14 @@ public class DBCachedObjectIndex { } } + /** + * Iterate over the values of the indexed column, in order + * + *

+ * Despite being called keys, the values may not be unique + * + * @return the iterator + */ public Iterable keys() { return new Iterable<>() { @Override @@ -134,6 +201,11 @@ public class DBCachedObjectIndex { }; } + /** + * Iterate over the objects as ordered by the index + * + * @return the iterator + */ public Iterable values() { return new Iterable<>() { @Override @@ -149,6 +221,15 @@ public class DBCachedObjectIndex { }; } + /** + * Iterate over the entries as ordered by the index + * + *

+ * Each entry is a key-value value where the "key" is the value of the indexed field, and the + * "value" is the object. + * + * @return the iterator + */ public Iterable> entries() { return new Iterable<>() { @Override @@ -181,17 +262,23 @@ public class DBCachedObjectIndex { return it.hasNext() ? it.next() : null; } + /** + * Check if this index is empty + * + *

+ * Except for sub-ranged indexes, this is equivalent to checking if the object store is empty. + * For sub-ranged indexes, this checks if the store contains any object whose value for the + * indexed field falls within the restricted range. + * + * @return true if empty + */ public boolean isEmpty() { return values().iterator().hasNext(); } - public boolean containsKey(K key) { - Field field = codec.encodeField(key); - if (!fieldRange.contains(field)) { - return false; - } + protected boolean containsKey(Field encoded) { try { - return store.table.hasRecord(field, columnIndex); + return store.table.hasRecord(encoded, columnIndex); } catch (IOException e) { store.dbError(e); @@ -199,6 +286,33 @@ public class DBCachedObjectIndex { } } + /** + * Check if there is any object having the given value for its indexed field + * + *

+ * This method is more efficient than using {@code get(key).isEmpty()}, since it need only find + * one match, whereas {@link #get(Object)} will retrieve every match. Granted, it doesn't make + * sense to immediately call {@link #get(Object)} after {@link #containsKey(Object)} returns + * true. + */ + public boolean containsKey(K key) { + Field encoded = codec.encodeField(key); + if (!fieldRange.contains(encoded)) { + return false; + } + return containsKey(encoded); + } + + /** + * Check if the given object is in the index + * + *

+ * Except for sub-ranged indexes, this is equivalent to checking if the object is in the store. + * For a sub-ranged index, the value of its indexed field must fall within the restricted range. + * + * @param value the object + * @return true if it appears in this (sub-ranged) index. + */ public boolean containsValue(T value) { if (!fieldRange.contains(value.record.getFieldValue(columnIndex))) { return false; @@ -206,13 +320,9 @@ public class DBCachedObjectIndex { return store.contains(value); } - public int countKey(K key) { - Field field = codec.encodeField(key); - if (!fieldRange.contains(field)) { - return 0; - } + protected int countKey(Field encoded) { try { - return store.table.getMatchingRecordCount(field, columnIndex); + return store.table.getMatchingRecordCount(encoded, columnIndex); } catch (IOException e) { store.dbError(e); @@ -220,78 +330,239 @@ public class DBCachedObjectIndex { } } + /** + * Count the number of objects whose indexed field has the given value + * + * @param key the value + * @return the count + */ + public int countKey(K key) { + Field encoded = codec.encodeField(key); + if (!fieldRange.contains(encoded)) { + return 0; + } + return countKey(encoded); + } + + /** + * Get the first key in the index + * + * @see #descending() + * @see #sub(Object, boolean, Object, boolean) + * @return the first key, or null + */ public K firstKey() { return firstOf(keys()); } + /** + * Get the first object in the index + * + * @see #descending() + * @see #sub(Object, boolean, Object, boolean) + * @return the first object, or null + */ public T firstValue() { return firstOf(values()); } + /** + * Get the first entry in the index + * + * @see #descending() + * @see #sub(Object, boolean, Object, boolean) + * @return the first key, or null + */ public Entry firstEntry() { return firstOf(entries()); } + /** + * Get the last key in the index + * + * @see #descending() + * @see #sub(Object, boolean, Object, boolean) + * @return the first key, or null + */ public K lastKey() { return firstOf(descending().keys()); } + /** + * Get the last object in the index + * + * @see #descending() + * @see #sub(Object, boolean, Object, boolean) + * @return the first object, or null + */ public T lastValue() { return firstOf(descending().values()); } + /** + * Get the last entry in the index + * + * @see #descending() + * @see #sub(Object, boolean, Object, boolean) + * @return the first key, or null + */ public Entry lastEntry() { return firstOf(descending().entries()); } + /** + * Get the key before the given key + * + * @param key the key + * @see #descending() + * @see #sub(Object, boolean, Object, boolean) + * @return the previous key, or null + */ public K lowerKey(K key) { return firstOf(head(key, false).descending().keys()); } + /** + * Get the value before the given key + * + * @param key the key + * @see #descending() + * @see #sub(Object, boolean, Object, boolean) + * @return the the value of the previous key, or null + */ public T lowerValue(K key) { return firstOf(head(key, false).descending().values()); } + /** + * Get the entry before the given key + * + * @param key the key + * @see #descending() + * @see #sub(Object, boolean, Object, boolean) + * @return the entry of the previous key, or null + */ public Entry lowerEntry(K key) { return firstOf(head(key, false).descending().entries()); } + /** + * Get the key at or before the given key + * + * @param key the key + * @see #descending() + * @see #sub(Object, boolean, Object, boolean) + * @return the same or previous key, or null + */ public K floorKey(K key) { return firstOf(head(key, true).descending().keys()); } + /** + * Get the value at or before the given key + * + * @param key the key + * @see #descending() + * @see #sub(Object, boolean, Object, boolean) + * @return the value of the same or previous key, or null + */ public T floorValue(K key) { return firstOf(head(key, true).descending().values()); } + /** + * Get the entry at or before the given key + * + * @param key the key + * @see #descending() + * @see #sub(Object, boolean, Object, boolean) + * @return the entry of the same or previous key, or null + */ public Entry floorEntry(K key) { return firstOf(head(key, true).descending().entries()); } + /** + * Get the key at or after the given key + * + * @param key the key + * @see #descending() + * @see #sub(Object, boolean, Object, boolean) + * @return the same or next key, or null + */ public K ceilingKey(K key) { return firstOf(tail(key, true).keys()); } + /** + * Get the value at or after the given key + * + * @param key the key + * @see #descending() + * @see #sub(Object, boolean, Object, boolean) + * @return the value of the same or next key, or null + */ public T ceilingValue(K key) { return firstOf(tail(key, true).values()); } + /** + * Get the entry at or after the given key + * + * @param key the key + * @see #descending() + * @see #sub(Object, boolean, Object, boolean) + * @return the entry of the same or next key, or null + */ public Entry ceilingEntry(K key) { return firstOf(tail(key, true).entries()); } + /** + * Get the key after the given key + * + * @param key the key + * @see #descending() + * @see #sub(Object, boolean, Object, boolean) + * @return the same or next key, or null + */ public K higherKey(K key) { return firstOf(tail(key, false).keys()); } + /** + * Get the value after the given key + * + * @param key the key + * @see #descending() + * @see #sub(Object, boolean, Object, boolean) + * @return the value of the next key, or null + */ public T higherValue(K key) { return firstOf(tail(key, false).values()); } + /** + * Get the entry after the given key + * + * @param key the key + * @see #descending() + * @see #sub(Object, boolean, Object, boolean) + * @return the entry of the next key, or null + */ public Entry higherEntry(K key) { return firstOf(tail(key, false).entries()); } + /** + * Get a sub-ranged view of this index, limited to entries whose keys occur before the given key + * + * @param to the upper bound + * @param toInclusive whether the upper bound is included in the restricted view + * @see #descending() + * @see #sub(Object, boolean, Object, boolean) + * @return the restricted view + */ public DBCachedObjectIndex head(K to, boolean toInclusive) { Range rng = DBCachedObjectStore.toRangeHead(codec.encodeField(to), toInclusive, direction); @@ -299,6 +570,15 @@ public class DBCachedObjectIndex { fieldRange.intersection(rng), direction); } + /** + * Get a sub-ranged view of this index, limited to entries whose keys occur after the given key + * + * @param from the lower bound + * @param fromInclusive whether the lower bound is included in the restricted view + * @see #descending() + * @see #sub(Object, boolean, Object, boolean) + * @return the restricted view + */ public DBCachedObjectIndex tail(K from, boolean fromInclusive) { Range rng = DBCachedObjectStore.toRangeTail(codec.encodeField(from), fromInclusive, direction); @@ -306,6 +586,16 @@ public class DBCachedObjectIndex { fieldRange.intersection(rng), direction); } + /** + * Get a sub-ranged view of this index + * + * @param from the lower bound + * @param fromInclusive whether the lower bound is included in the restricted view + * @param to the upper bound + * @param toInclusive whether the upper bound is included in the restricted view + * @see #descending() + * @return the restricted view + */ public DBCachedObjectIndex sub(K from, boolean fromInclusive, K to, boolean toInclusive) { Range rng = DBCachedObjectStore.toRange(codec.encodeField(from), fromInclusive, codec.encodeField(to), toInclusive, direction); @@ -313,6 +603,18 @@ public class DBCachedObjectIndex { fieldRange.intersection(rng), direction); } + /** + * Get a reversed view of this index + * + *

+ * This affects iteration as well as all the navigation and sub-ranging methods. E.g., + * {@link #lowerKey(Object)} in the reversed view will behave like {@link #higherKey(Object)} in + * the original. In other words, the returned index is equivalent to the original, but with a + * negated comparator. Calling {@link #descending()} on the returned view will return a view + * equivalent to the original. + * + * @return the reversed view + */ public DBCachedObjectIndex descending() { return new DBCachedObjectIndex<>(store, errHandler, codec, columnIndex, fieldRange, Direction.reverse(direction)); diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStore.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStore.java index 737b75719f..97ccdd8b70 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStore.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStore.java @@ -20,6 +20,7 @@ import java.util.*; import java.util.Map.Entry; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; +import java.util.function.Supplier; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; @@ -35,7 +36,28 @@ import ghidra.program.model.address.KeyRange; import ghidra.util.LockHold; import ghidra.util.database.DBCachedObjectStoreFactory.DBFieldCodec; import ghidra.util.database.DirectedIterator.Direction; +import ghidra.util.database.annot.DBAnnotatedField; +/** + * An object store backed by a {@link db.Table} + * + *

+ * Essentially, this provides object-based accessed to records in the table via DAOs. See + * {@link DBAnnotatedObject} for further documentation including an example object definition. The + * store keeps a cache of objects using {@link DBObjectCache}. See + * {@link DBCachedObjectStoreFactory} for documentation describing how to create a store, including + * for the example object definition. + * + *

+ * The store provides views for locating, iterating, and retrieving its objects in a variety of + * fashions. This includes the primary key (object id), or any indexed column (see + * {@link DBAnnotatedField#indexed()}). These views generally implement an interface from Java's + * Collections API, providing for familiar semantics. A notable exception is that none of the + * interfaces support mutation, aside from deletion. The store is populated only via the + * {@link #create()} methods. + * + * @param the type of objects stored + */ public class DBCachedObjectStore implements ErrorHandler { private static final Comparator KEY_COMPARATOR = Long::compare; @@ -65,14 +87,119 @@ public class DBCachedObjectStore implements ErrorHa return Range.upTo(from, fromInclusive ? BoundType.CLOSED : BoundType.OPEN); } - protected abstract class BoundedStuff { - abstract U fromRecord(DBRecord record) throws IOException; + /** + * Abstractions for navigating within a given view + * + *

+ * Generally, these are all methods that facilitate implementation of a {@link Collection} or + * {@link NavigableMap}. The idea is that the abstract methods are required to translate from + * various object types and to facilitate table access. This class then provides all the methods + * needed to navigate the table with respect to a desired element type. These types will be + * those typically exposed as collections by the {@link Map} interface: keys, values, and + * entries. The implementations of those collections can then call those methods as needed. + * + *

+ * The methods are implemented in various groups and with a variety of parameters. The first + * group is the abstract methods. The next simply wraps the table's navigations methods to + * retrieve elements of the view. Many of these accept an optional range to limit the search or + * effect. This is to facilitate the implementation of sub-maps. The next are named after their + * counterparts in the navigable interfaces. In addition to the optional range, many of these + * take a direction. This is to facilitate the implementation of reversed collections. To best + * understand the methods, examine the callers-to tree and see the relevant documentation, + * probably in the Java Collections API. + * + * @param the type of elements exposed by the view + * @param the type used to navigate the view's backing + */ + protected abstract class BoundedStuff { + /** + * Get the element from a given record + * + * @param record the table record + * @return the element + * @throws IOException if there's an issue reading the record + */ + abstract E fromRecord(DBRecord record) throws IOException; - abstract U fromObject(T value); + /** + * Get the element from a given store object + * + * @param value the store object + * @return the element + */ + abstract E fromObject(T value); - abstract Long getKey(U of); + /** + * Get the key of the record backing the given element + * + * @param of the element + * @return the key + */ + abstract Long getKey(E of); - U getMax() throws IOException { + /** + * Check that the object is the expected element type and return it or null + * + *

+ * This is needed to implement {@link Collection#contains(Object)} and similar, because its + * signature accepts any object. The first step is to type check it. Note that if {@link E} + * is parameterized, it's fields may also require type checking. + * + * @param o the object whose type to check + * @return the object if its type matches an element, or null + */ + abstract E checkAndConvert(Object o); + + /** + * Check if the given element is contained in the view + * + * @param e the element + * @return true if contained in the view + * @throws IOException if there's an issue reading the table + */ + abstract boolean typedContains(E e) throws IOException; + + /** + * Remove the given element from the view + * + * @param e the element + * @return the store object removed or null if no effect + * @throws IOException if there's an issue accessing the table + */ + abstract T typedRemove(E e) throws IOException; + + /** + * Get an iterator over the raw components of the table for the given range + * + * @param direction the direction of iteration + * @param keyRange the range of keys + * @return the iterator + * @throws IOException if there's an issue reading the table + */ + abstract DirectedIterator rawIterator(Direction direction, Range keyRange) + throws IOException; + + /** + * Convert the raw component to an element + * + * @param raw the raw component + * @return the element + * @throws IOException if there's an issue reading the table + */ + abstract E fromRaw(R raw) throws IOException; + + // Utilities + + E filter(E candidate, Range keyRange) { + if (candidate == null || !keyRange.contains(getKey(candidate))) { + return null; + } + return candidate; + } + + // Methods which wrap the table's navigation methods + + E getMax() throws IOException { long max = table.getMaxKey(); if (max == Long.MIN_VALUE) { return null; @@ -80,11 +207,11 @@ public class DBCachedObjectStore implements ErrorHa return get(max); } - U getBefore(long key) throws IOException { + E getBefore(long key) throws IOException { return fromRecord(table.getRecordBefore(key)); } - U getBefore(long key, Range keyRange) throws IOException { + E getBefore(long key, Range keyRange) throws IOException { if (!keyRange.hasUpperBound() || key <= keyRange.upperEndpoint()) { return filter(getBefore(key), keyRange); } @@ -96,11 +223,11 @@ public class DBCachedObjectStore implements ErrorHa } } - U getAtOrBefore(long key) throws IOException { + E getAtOrBefore(long key) throws IOException { return fromRecord(table.getRecordAtOrBefore(key)); } - U getAtOrBefore(long key, Range keyRange) throws IOException { + E getAtOrBefore(long key, Range keyRange) throws IOException { if (!keyRange.hasUpperBound() || key < keyRange.upperEndpoint()) { return filter(getAtOrBefore(key), keyRange); } @@ -112,7 +239,7 @@ public class DBCachedObjectStore implements ErrorHa } } - U get(long key) throws IOException { + E get(long key) throws IOException { T cached = cache.get(key); if (cached != null) { return fromObject(cached); @@ -120,11 +247,11 @@ public class DBCachedObjectStore implements ErrorHa return fromRecord(table.getRecord(key)); } - U getAtOrAfter(long key) throws IOException { + E getAtOrAfter(long key) throws IOException { return fromRecord(table.getRecordAtOrAfter(key)); } - U getAtOrAfter(long key, Range keyRange) throws IOException { + E getAtOrAfter(long key, Range keyRange) throws IOException { if (!keyRange.hasLowerBound() || key > keyRange.lowerEndpoint()) { return filter(getAtOrAfter(key), keyRange); } @@ -136,11 +263,11 @@ public class DBCachedObjectStore implements ErrorHa } } - U getAfter(long key) throws IOException { + E getAfter(long key) throws IOException { return fromRecord(table.getRecordAfter(key)); } - U getAfter(long key, Range keyRange) throws IOException { + E getAfter(long key, Range keyRange) throws IOException { if (!keyRange.hasLowerBound() || key >= keyRange.lowerEndpoint()) { return filter(getAfter(key), keyRange); } @@ -152,12 +279,8 @@ public class DBCachedObjectStore implements ErrorHa } } - abstract U checkAndConvert(Object o); - - abstract boolean typedContains(U u) throws IOException; - boolean contains(Object o) throws IOException { - U u = checkAndConvert(o); + E u = checkAndConvert(o); if (u == null) { return false; } @@ -165,7 +288,7 @@ public class DBCachedObjectStore implements ErrorHa } boolean contains(Object o, Range keyRange) throws IOException { - U u = checkAndConvert(o); + E u = checkAndConvert(o); if (u == null) { return false; } @@ -193,10 +316,8 @@ public class DBCachedObjectStore implements ErrorHa return true; } - abstract T typedRemove(U u) throws IOException; - boolean remove(Object o) throws IOException { - U u = checkAndConvert(o); + E u = checkAndConvert(o); if (u == null) { return false; } @@ -204,7 +325,7 @@ public class DBCachedObjectStore implements ErrorHa } boolean remove(Object o, Range keyRange) throws IOException { - U u = checkAndConvert(o); + E u = checkAndConvert(o); if (u == null) { return false; } @@ -230,18 +351,13 @@ public class DBCachedObjectStore implements ErrorHa return result; } - U filter(U candidate, Range keyRange) { - if (candidate == null || !keyRange.contains(getKey(candidate))) { - return null; - } - return candidate; - } + // Methods for implementing navigable maps and collections - U first() throws IOException { + E first() throws IOException { return getAtOrAfter(Long.MIN_VALUE); } - U first(Range keyRange) throws IOException { + E first(Range keyRange) throws IOException { if (!keyRange.hasLowerBound()) { return filter(first(), keyRange); } @@ -253,25 +369,25 @@ public class DBCachedObjectStore implements ErrorHa } } - U first(Direction direction) throws IOException { + E first(Direction direction) throws IOException { if (direction == Direction.FORWARD) { return first(); } return last(); } - U first(Direction direction, Range keyRange) throws IOException { + E first(Direction direction, Range keyRange) throws IOException { if (direction == Direction.FORWARD) { return first(keyRange); } return last(keyRange); } - U last() throws IOException { + E last() throws IOException { return getMax(); } - U last(Range keyRange) throws IOException { + E last(Range keyRange) throws IOException { if (!keyRange.hasUpperBound()) { return filter(last(), keyRange); } @@ -283,82 +399,77 @@ public class DBCachedObjectStore implements ErrorHa } } - U last(Direction direction) throws IOException { + E last(Direction direction) throws IOException { if (direction == Direction.FORWARD) { return last(); } return first(); } - U last(Direction direction, Range keyRange) throws IOException { + E last(Direction direction, Range keyRange) throws IOException { if (direction == Direction.FORWARD) { return last(keyRange); } return first(keyRange); } - U lower(Direction direction, long key) throws IOException { + E lower(Direction direction, long key) throws IOException { if (direction == Direction.FORWARD) { return getBefore(key); } return getAfter(key); } - U lower(Direction direction, long key, Range keyRange) throws IOException { + E lower(Direction direction, long key, Range keyRange) throws IOException { if (direction == Direction.FORWARD) { return getBefore(key, keyRange); } return getAfter(key, keyRange); } - U floor(Direction direction, long key) throws IOException { + E floor(Direction direction, long key) throws IOException { if (direction == Direction.FORWARD) { return getAtOrBefore(key); } return getAtOrAfter(key); } - U floor(Direction direction, long key, Range keyRange) throws IOException { + E floor(Direction direction, long key, Range keyRange) throws IOException { if (direction == Direction.FORWARD) { return getAtOrBefore(key, keyRange); } return getAtOrAfter(key, keyRange); } - U ceiling(Direction direction, long key) throws IOException { + E ceiling(Direction direction, long key) throws IOException { if (direction == Direction.FORWARD) { return getAtOrAfter(key); } return getAtOrBefore(key); } - U ceiling(Direction direction, long key, Range keyRange) throws IOException { + E ceiling(Direction direction, long key, Range keyRange) throws IOException { if (direction == Direction.FORWARD) { return getAtOrAfter(key, keyRange); } return getAtOrBefore(key, keyRange); } - U higher(Direction direction, long key) throws IOException { + E higher(Direction direction, long key) throws IOException { if (direction == Direction.FORWARD) { return getAfter(key); } return getBefore(key); } - U higher(Direction direction, long key, Range keyRange) throws IOException { + E higher(Direction direction, long key, Range keyRange) throws IOException { if (direction == Direction.FORWARD) { return getAfter(key, keyRange); } return getBefore(key, keyRange); } - abstract DirectedIterator rawIterator(Direction direction, Range keyRange) - throws IOException; - - abstract U fromRaw(V raw) throws IOException; - - Iterator iterator(DirectedIterator it) { + Iterator iterator(DirectedIterator it) { return new Iterator<>() { @Override public boolean hasNext() { @@ -372,7 +483,7 @@ public class DBCachedObjectStore implements ErrorHa } @Override - public U next() { + public E next() { try (LockHold hold = LockHold.lock(lock.readLock())) { return fromRaw(it.next()); } @@ -394,7 +505,7 @@ public class DBCachedObjectStore implements ErrorHa }; } - Iterator iterator(Direction direction, Range keyRange) { + Iterator iterator(Direction direction, Range keyRange) { if (keyRange != null && keyRange.isEmpty()) { return Collections.emptyIterator(); } @@ -407,12 +518,12 @@ public class DBCachedObjectStore implements ErrorHa } } - void intoArray(U[] arr, Direction direction, Range keyRange) { + void intoArray(E[] arr, Direction direction, Range keyRange) { if (keyRange != null && keyRange.isEmpty()) { return; } try (LockHold hold = LockHold.lock(lock.readLock())) { - DirectedIterator it = rawIterator(direction, keyRange); + DirectedIterator it = rawIterator(direction, keyRange); for (int i = 0; it.hasNext(); i++) { arr[i] = fromRaw(it.next()); } @@ -422,12 +533,12 @@ public class DBCachedObjectStore implements ErrorHa } } - void toList(List list, Direction direction, Range keyRange) { + void toList(List list, Direction direction, Range keyRange) { if (keyRange != null && keyRange.isEmpty()) { return; } try (LockHold hold = LockHold.lock(lock.readLock())) { - DirectedIterator it = rawIterator(direction, keyRange); + DirectedIterator it = rawIterator(direction, keyRange); while (it.hasNext()) { list.add(fromRaw(it.next())); } @@ -438,7 +549,7 @@ public class DBCachedObjectStore implements ErrorHa } Object[] toArray(Direction direction, Range keyRange) { - ArrayList list = new ArrayList<>(); + ArrayList list = new ArrayList<>(); toList(list, direction, keyRange); return list.toArray(); } @@ -455,7 +566,7 @@ public class DBCachedObjectStore implements ErrorHa toList(list, direction, keyRange); return list.toArray(a); } - intoArray((U[]) a, direction, keyRange); + intoArray((E[]) a, direction, keyRange); for (int i = size; i < a.length; i++) { a[i] = null; } @@ -468,9 +579,9 @@ public class DBCachedObjectStore implements ErrorHa } boolean result = false; try (LockHold hold = LockHold.lock(lock.writeLock())) { - DirectedIterator it = rawIterator(Direction.FORWARD, keyRange); + DirectedIterator it = rawIterator(Direction.FORWARD, keyRange); while (it.hasNext()) { - U u = fromRaw(it.next()); + E u = fromRaw(it.next()); if (!c.contains(u)) { it.delete(); cache.delete(getKey(u)); @@ -485,6 +596,14 @@ public class DBCachedObjectStore implements ErrorHa } } + /** + * The implementation of {@link BoundedStuff} to facilitate the implementation of + * {@link Map#keySet()}. + * + *

+ * Because tables let us navigate keys directly, we use the key as the raw component here + * instead of the full record. + */ protected final BoundedStuff keys = new BoundedStuff<>() { @Override Long fromRecord(DBRecord record) { @@ -557,6 +676,10 @@ public class DBCachedObjectStore implements ErrorHa } }; + /** + * The implementation of {@link BoundedStuff} to facilitate the implementation of + * {@link Map#values()}. + */ protected final BoundedStuff objects = new BoundedStuff<>() { @Override T fromRecord(DBRecord record) throws IOException { @@ -620,6 +743,10 @@ public class DBCachedObjectStore implements ErrorHa } }; + /** + * The implementation of {@link BoundedStuff} to facilitate the implementation of + * {@link Map#entrySet()}. + */ protected final BoundedStuff, DBRecord> entries = new BoundedStuff<>() { @Override Entry fromRecord(DBRecord record) throws IOException { @@ -702,7 +829,19 @@ public class DBCachedObjectStore implements ErrorHa Table table; - public DBCachedObjectStore(DBCachedDomainObjectAdapter adapter, Class objectType, + /** + * Construct a store + * + *

+ * Users should instead construct stores using + * {@link DBCachedObjectStoreFactory#getOrCreateCachedStore(String, Class, DBAnnotatedObjectFactory, boolean)}. + * + * @param adapter the domain object backed by the same database as this store + * @param objectType the type of objects stored + * @param factory the factory creating this store + * @param table the table backing this store + */ + protected DBCachedObjectStore(DBCachedDomainObjectAdapter adapter, Class objectType, DBAnnotatedObjectFactory factory, Table table) { this.adapter = adapter; this.dbh = adapter.getDBHandle(); @@ -738,7 +877,8 @@ public class DBCachedObjectStore implements ErrorHa /** * Get the maximum key which has ever existed in this store * - * Note, the key need not actually be present + *

+ * Note, the returned key may not actually be present * * @return the maximum, or null if the store is unused */ @@ -755,6 +895,7 @@ public class DBCachedObjectStore implements ErrorHa /** * Count the number of keys in a given range. * + *

* This implementation is not very efficient. It must visit at least every record in the range. * * @param keyRange the range of keys @@ -785,6 +926,7 @@ public class DBCachedObjectStore implements ErrorHa /** * Check if any keys exist within the given range. * + *

* This implementation is more efficient than using {@link #getKeyCount(Range)} and comparing to * 0, since there's no need to visit more than one record in the range. * @@ -820,6 +962,16 @@ public class DBCachedObjectStore implements ErrorHa } } + /** + * Check if an object with the given key exists in the store + * + *

+ * Using this is preferred to {@link #getObjectAt(long)} and checking for null, if that object + * does not actually need to be retrieved. + * + * @param key the key + * @return true if it exists + */ public boolean containsKey(long key) { try (LockHold hold = LockHold.lock(lock.readLock())) { return keys.typedContains(key); @@ -830,6 +982,16 @@ public class DBCachedObjectStore implements ErrorHa } } + /** + * Check if the given object exists in the store + * + *

+ * No matter the definition of {@link T#equals(Object)}, this requires the identical object to + * be present. + * + * @param obj the object + * @return + */ public boolean contains(T obj) { try (LockHold hold = LockHold.lock(lock.readLock())) { return objects.typedContains(obj); @@ -852,6 +1014,7 @@ public class DBCachedObjectStore implements ErrorHa /** * Create a new object with the given key. * + *

* If the key already exists in the table, the existing record is overwritten. * * @param key the key for the new object @@ -882,6 +1045,13 @@ public class DBCachedObjectStore implements ErrorHa } } + /** + * Get the column number given a column name + * + * @param name the name + * @return the number (0-up index) for the column + * @throws NoSuchElementException if no column with the given name exists + */ protected int getColumnByName(String name) { int index = ArrayUtils.indexOf(schema.getFieldNames(), name); if (index < 0) { @@ -890,7 +1060,16 @@ public class DBCachedObjectStore implements ErrorHa return index; } - protected DBCachedObjectIndex getIndex(Class valueType, int columnIndex) { + /** + * Get the table index for the given column number + * + * @param the type of the object field for the indexed column + * @param fieldClass the class specifying {@link K} + * @param columnIndex the column number + * @return the index + * @throws IllegalArgumentException if the column has a different type than {@link K} + */ + protected DBCachedObjectIndex getIndex(Class fieldClass, int columnIndex) { if (!ArrayUtils.contains(table.getIndexedColumns(), columnIndex)) { throw new IllegalArgumentException( "Column " + schema.getFieldNames()[columnIndex] + " is not indexed"); @@ -898,9 +1077,9 @@ public class DBCachedObjectStore implements ErrorHa DBFieldCodec codec = codecs.get(columnIndex); Class exp = codec.getValueType(); - if (valueType != exp) { + if (fieldClass != exp) { throw new IllegalArgumentException("Column " + schema.getFieldNames()[columnIndex] + - " is not of type " + valueType + "! It is " + exp); + " is not of type " + fieldClass + "! It is " + exp); } @SuppressWarnings("unchecked") DBFieldCodec castCodec = (DBFieldCodec) codec; @@ -908,15 +1087,45 @@ public class DBCachedObjectStore implements ErrorHa Direction.FORWARD); } + /** + * Get the index for a given column + * + *

+ * See {@link DBCachedObjectStoreFactory} for an example that includes use of an index + * + * @param the type of the object field for the indexed column + * @param fieldClass the class specifying {@link K} + * @param column the indexed column + * @return the index + * @throws IllegalArgumentException if the column has a different type than {@link K} + */ public DBCachedObjectIndex getIndex(Class fieldClass, DBObjectColumn column) { return getIndex(fieldClass, column.columnNumber); } + /** + * Get the index for a given column by name + * + *

+ * See {@link DBCachedObjectStoreFactory} for an example that includes use of an index + * + * @param the type of the object field for the indexed column + * @param fieldClass the class specifying {@link K} + * @param columnName the name of the indexed column + * @return the index + * @throws IllegalArgumentException if the given column is not indexed + */ public DBCachedObjectIndex getIndex(Class fieldClass, String columnName) { int columnIndex = getColumnByName(columnName); return getIndex(fieldClass, columnIndex); } + /** + * Delete the given object + * + * @param obj the object + * @return true if the object was removed, false for no effect + */ public boolean delete(T obj) { try (LockHold hold = LockHold.lock(lock.writeLock())) { return objects.typedRemove(obj) != null; @@ -927,6 +1136,12 @@ public class DBCachedObjectStore implements ErrorHa } } + /** + * Delete the object with the given key + * + * @param key the key + * @return true if the key was removed, false for no effect + */ public T deleteKey(long key) { try (LockHold hold = LockHold.lock(lock.writeLock())) { return keys.typedRemove(key); @@ -937,6 +1152,9 @@ public class DBCachedObjectStore implements ErrorHa } } + /** + * Clear the entire table + */ public void deleteAll() { try (LockHold hold = LockHold.lock(lock.writeLock())) { table.deleteAll(); @@ -966,10 +1184,24 @@ public class DBCachedObjectStore implements ErrorHa } } + /** + * A variation of {@link Supplier} that allows {@link IOException} to pass through + * + * @param the type of object supplied + */ protected interface SupplierAllowsIOException { U get() throws IOException; } + /** + * Invoke the given supplier with a lock, directing {@link IOException}s to the domain object + * adapter + * + * @param the type of the result + * @param l the lock to hold during invocation + * @param supplier the supplier to invoke + * @return the result + */ protected U safe(Lock l, SupplierAllowsIOException supplier) { try (LockHold hold = LockHold.lock(l)) { return supplier.get(); @@ -980,6 +1212,12 @@ public class DBCachedObjectStore implements ErrorHa } } + /** + * Get the object having the given key + * + * @param key the key + * @return the object, or null + */ public T getObjectAt(long key) { try (LockHold hold = LockHold.lock(lock.readLock())) { return objects.get(key); @@ -990,14 +1228,36 @@ public class DBCachedObjectStore implements ErrorHa } } + /** + * Get the key comparator + * + * @implNote this is probably vestigial, left from when we attempted to allow customization of + * the primary key. This currently just gives the natural ordering of longs. + * + * @return the comparator + */ protected Comparator keyComparator() { return KEY_COMPARATOR; } + /** + * Provides access to the store as a {@link NavigableMap}. + * + * @return the map + */ public DBCachedObjectStoreMap asMap() { return asForwardMap; } + /** + * Search a column index for a single object having the given value + * + * @param columnIndex the indexed column's number + * @param field a field holding the value to seek + * @return the object, if found, or null + * @throws IOException if there's an issue reading the table + * @throws IllegalStateException if the object is not unique + */ protected T findOneObject(int columnIndex, Field field) throws IOException { // TODO: Support non-long keys, eventually. Field[] found = table.findRecords(field, columnIndex); @@ -1010,12 +1270,29 @@ public class DBCachedObjectStore implements ErrorHa return getObjectAt(found[0].getLongValue()); } + /** + * Search a column index for all objects having the given value + * + * @param columnIndex the indexed column's number + * @param field a field holding the value to seek + * @return the collection of objects found, possibly empty but never null + * @throws IOException if there's an issue reading the table + */ protected DBCachedObjectStoreFoundKeysValueCollection findObjects(int columnIndex, Field field) throws IOException { Field[] found = table.findRecords(field, columnIndex); return new DBCachedObjectStoreFoundKeysValueCollection<>(this, adapter, lock, found); } + /** + * Search a column index and iterate over objects having the given value + * + * @param columnIndex the indexed column's number + * @param fieldRange required: the range to consider + * @param direction the direction of iteration + * @return the iterator, possibly empty but never null + * @throws IOException if there's an issue reading the table + */ protected Iterator iterator(int columnIndex, Range fieldRange, Direction direction) throws IOException { DirectedRecordIterator it = @@ -1023,18 +1300,39 @@ public class DBCachedObjectStore implements ErrorHa return objects.iterator(it); } + /** + * For testing: check if the given key is in the cache + * + * @param key the key + * @return true if cached + */ boolean isCached(long key) { return cache.get(key) != null; } + /** + * Get the read lock + * + * @return the lock + */ public Lock readLock() { return lock.readLock(); } + /** + * Get the write lock + * + * @return the lock + */ public Lock writeLock() { return lock.writeLock(); } + /** + * Get the read-write lock + * + * @return the lock + */ public ReadWriteLock getLock() { return lock; } @@ -1047,6 +1345,7 @@ public class DBCachedObjectStore implements ErrorHa /** * Display useful information about this cached store * + *

* Please avoid calling this except for debugging. * * @return a string representation of the store's cache @@ -1059,6 +1358,13 @@ public class DBCachedObjectStore implements ErrorHa return builder.toString(); } + /** + * Invalidate this store's cache + * + *

+ * This should be called whenever the table may have changed in a way not caused by the store + * itself, e.g., whenever {@link DBHandle#undo()} is called. + */ public void invalidateCache() { try (LockHold hold = LockHold.lock(lock.writeLock())) { cache.invalidate(); diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreEntrySet.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreEntrySet.java index 4a0a3c2902..5d929a7188 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreEntrySet.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreEntrySet.java @@ -26,6 +26,15 @@ import com.google.common.collect.Range; import db.util.ErrorHandler; import ghidra.util.database.DirectedIterator.Direction; +/** + * This provides the implementation of {@link Map#entrySet()} for + * {@link DBCachedObjectStore#asMap()} + * + *

+ * The store acts as a map from object id to object, thus an entry has a long key and object value. + * + * @param the type of objects in the store + */ public class DBCachedObjectStoreEntrySet implements NavigableSet> { protected final DBCachedObjectStore store; diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreEntrySubSet.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreEntrySubSet.java index 7ffd54f268..890801fd91 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreEntrySubSet.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreEntrySubSet.java @@ -25,6 +25,14 @@ import com.google.common.collect.Range; import db.util.ErrorHandler; import ghidra.util.database.DirectedIterator.Direction; +/** + * This is the sub-ranged form of {@link DBCachedObjectStoreEntrySet} + * + *

+ * For example, this can be obtained via {@code store.asMap().subMap(...).entrySet()}. + * + * @param the type of objects in the store + */ public class DBCachedObjectStoreEntrySubSet extends DBCachedObjectStoreEntrySet { diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreFactory.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreFactory.java index 44fa8c77f3..f8de282c18 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreFactory.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreFactory.java @@ -33,21 +33,225 @@ import ghidra.util.database.annot.DBAnnotatedField.DefaultCodec; import ghidra.util.database.err.NoDefaultCodecException; import ghidra.util.exception.VersionException; +/** + * A factory for creating object stores for classes extending {@link DBAnnotatedObject} + * + *

+ * See {@link DBAnnotatedObject} for more documentation, including an example object definition. To + * create a store, e.g., for {@code Person}: + * + *

+ * interface MyDomainObject {
+ * 	Person createPerson(String name, String address);
+ * 
+ * 	Person getPerson(long id);
+ * 
+ * 	Collection getPeopleNamed(String name);
+ * }
+ * 
+ * public class DBMyDomainObject extends DBCachedDomainObjectAdapter implements MyDomainObject {
+ * 	private final DBCachedObjectStoreFactory factory;
+ * 	private final DBCachedObjectStore people;
+ * 	private final DBCachedObjectIndex peopleByName;
+ * 
+ * 	public DBMyDomainObject() { // Constructor parameters elided
+ * 		// super() invocation elided
+ * 		factory = new DBCachedObjectStoreFactory(this);
+ * 		try {
+ * 			people = factory.getOrCreateCachedStore(DBPerson.TABLE_NAME, DBPerson.class,
+ * 				DBPerson::new, false);
+ * 			peopleByName = people.getIndex(String.class, DBPerson.NAME_COLUMN);
+ * 		}
+ * 		catch (VersionException e) {
+ * 			// ...
+ * 		}
+ * 		catch (IOException e) {
+ * 			// ...
+ * 		}
+ * 	}
+ * 
+ * 	@Override
+ * 	public Person createPerson(String name, String address) {
+ * 		// Locking details elided
+ * 		DBPerson person = people.create();
+ * 		person.set(name, address);
+ * 		return person;
+ * 	}
+ * 
+ * 	@Override
+ * 	public Person getPerson(int id) {
+ * 		// Locking details elided
+ * 		return people.getAt(id);
+ * 	}
+ * 
+ * 	@Override
+ * 	public Collection getPeopleNamed(String name) {
+ * 		// Locking details elided
+ * 		return peopleByName.get(name);
+ * 	}
+ * }
+ * 
+ * + *

+ * The factory manages tables on behalf of the domain object, so it is typically the first thing + * constructed. In practice, complex domain objects should be composed of several managers, each of + * which constructs its own stores, but for simplicity in this example, we construct the people + * store in the domain object. This will check the schema and could throw a + * {@link VersionException}. Typically, immediately after constructing the store, all desired + * indexes of the store are retrieved. The domain object then provides API methods for creating and + * retrieving people. Providing direct API client access to the store from a domain object is highly + * discouraged. + * + * @implNote This class bears the responsibility of processing the {@link DBAnnotatedField}, + * {@link DBAnnotatedColumn}, and {@link DBAnnotatedObjectInfo} annotations. The relevant + * entry point is {{@link #buildInfo(Class)}. It creates a {@link TableInfo} for the given + * class, which builds the schema for creating the {@link Table} that backs an object + * store for that class. + */ public class DBCachedObjectStoreFactory { + /** + * A codec for encoding alternative data types + * + *

+ * The database framework supports limited types of fields, each capable for storing a specific + * Java data type. A simple codec is provided for "encoding" each of the supported types into + * its corresponding {@link db.Field} type. For other types, additional custom codecs must be + * implemented. Custom codecs must be explicitly selected using the + * {@link DBAnnotatedField#codec()} attribute. + * + *

+ * NOTE: When changing the implementation of a codec, keep in mind whether or not it + * implies a change to the schema of tables that use the codec. If it does, their schema + * versions, i.e., {@link DBAnnotatedObjectInfo#version()} should be incremented and + * considerations made for supporting upgrades. + * + *

+ * In some cases, the codec may require context information from the containing object. This is + * facilitated via the {@link OT} type parameter. If no additional context is required, + * {@link DBAnnotatedObject} is sufficient. If context is required, then additional interfaces + * can be required via type intersection: + * + *

+	 * public interface MyContext {
+	 * 	// ...
+	 * }
+	 * 
+	 * public interface ContextProvider {
+	 * 	MyContext getContext();
+	 * }
+	 * 
+	 * public static class MyDBFieldCodec extends
+	 * 		AbstractDBFieldCodec {
+	 * 
+	 * 	public MyDBFieldCodec(Class objectType, Field field, int column) {
+	 * 		super(MyType.class, objectType, BinaryField.class, field, column);
+	 * 	}
+	 * 
+	 * 	@Override
+	 * 	protected void doStore(OT obj, DBRecord record) {
+	 * 		MyContext ctx = obj.getContext();
+	 * 		// ...
+	 * 	}
+	 * 	// ...
+	 * }
+	 * 
+ * + *

+ * Note that this implementation uses {@link AbstractDBFieldCodec}, which is highly recommended. + * Whether or not the abstract codec is used, the constructor must have the signature + * {@code (Class, Field, int)}, which are the containing object's actual type, the field of + * the Java class whose values to encode, and the record column number into which to store those + * encoded values. The type variables {@link VT} and {@link FT} of the codec indicate it can + * encode values of type {@code MyType} into a byte array for storage into a + * {@link BinaryField}. See {@link ByteDBFieldCodec} for the simplest example with actual + * encoding and decoding implementations. To use the example codec in an object: + * + *

+	 * @DBAnnotatedObjectInfo(version = 1)
+	 * public static class SomeObject extends DBAnnotatedObject implements ContextProvider {
+	 * 	static final String MY_COLUMN_NAME = "My";
+	 * 
+	 * 	@DBAnnotatedColumn(MY_COLUMN_NAME)
+	 * 	static DBObjectColumn MY_COLUMN;
+	 * 
+	 * 	@DBAnnotatedField(column = MY_COLUMN_NAME, codec = MyDBFieldCodec.class)
+	 * 	private MyType my;
+	 * 
+	 * 	// ...
+	 * 
+	 * 	@Override
+	 * 	public MyContext getContext() {
+	 * 		// ...
+	 * 	}
+	 * }
+	 * 
+ * + *

+ * Notice that {@code SomeObject} must implement {@code ContextProvider}. This restriction is + * checked at runtime when the object store is created, but a compile-time annotation processor + * can check this restriction sooner. This has been implemented, at least in part, in the + * {@code AnnotationProcessor} project. It is recommended that at most one additional interface + * is required in by {@link OT}. If multiple contexts are required, consider declaring an + * interface that extends the multiple required interfaces. Alternatively, consider a new + * interface that provides one composite context. + * + * @param the type of the value encoded, i.e., the object field's Java type + * @param the upper bound on objects containing the field + * @param the type of the database field into which the value is encoded + */ public interface DBFieldCodec { + /** + * Encode the field from the given object into the given record + * + * @param obj the source object + * @param record the destination record + */ void store(OT obj, DBRecord record); + /** + * Encode the given field value into the given field + * + * @param value the value + * @param f the field + */ void store(VT value, FT f); + /** + * Decode the field from the given record into the given object + * + * @param obj the destination object + * @param record the source record + */ void load(OT obj, DBRecord record); + /** + * Get the type of values encoded and decoded + * + * @return the value type + */ Class getValueType(); + /** + * Get the upper bound on objects with fields using this codec + * + * @return the upper bound + */ Class getObjectType(); + /** + * Get the type of field storing the values + * + * @return the field type + */ Class getFieldType(); + /** + * Encode the given value into a new field + * + * @param value the value + * @return the field with the encoded value + */ default FT encodeField(VT value) { try { FT field = getFieldType().getConstructor().newInstance(); @@ -60,9 +264,22 @@ public class DBCachedObjectStoreFactory { } } + /** + * Get the value from the object + * + * @param obj the source object + * @return the value + */ VT getValue(OT obj); } + /** + * An abstract implementation of {@link DBFieldCodec} + * + *

+ * This reduces the implementation burden to {@link #doLoad(DBAnnotatedObject, DBRecord)}, + * {@link #doStore(DBAnnotatedObject, DBRecord)}, and {@link #store(Object, db.Field)}. + */ public static abstract class AbstractDBFieldCodec implements DBFieldCodec { protected final Class valueType; @@ -71,6 +288,15 @@ public class DBCachedObjectStoreFactory { protected final Field field; protected final int column; + /** + * Construct a codec + * + * @param valueType + * @param objectType + * @param fieldType + * @param field + * @param column + */ public AbstractDBFieldCodec(Class valueType, Class objectType, Class fieldType, Field field, int column) { if (!field.getDeclaringClass().isAssignableFrom(objectType)) { @@ -133,18 +359,35 @@ public class DBCachedObjectStoreFactory { } } + /** + * Set the value of the object + * + * @param obj the object whose field to set + * @param value the value to assign + * @throws IllegalArgumentException as in {@link Field#set(Object, Object)} + * @throws IllegalAccessException as in {@link Field#set(Object, Object)} + */ protected void setValue(OT obj, VT value) throws IllegalArgumentException, IllegalAccessException { field.set(obj, value); } + /** + * Same as {@link #store(DBAnnotatedObject, DBRecord)}, but permits exceptions + */ protected abstract void doStore(OT obj, DBRecord record) throws IllegalArgumentException, IllegalAccessException; + /** + * Same as {@link #load(DBAnnotatedObject, DBRecord), but permits exceptions + */ protected abstract void doLoad(OT obj, DBRecord record) throws IllegalArgumentException, IllegalAccessException; } + /** + * The built-in codec for {@code boolean} + */ public static class BooleanDBFieldCodec extends AbstractDBFieldCodec { public BooleanDBFieldCodec(Class objectType, Field field, int column) { @@ -169,6 +412,9 @@ public class DBCachedObjectStoreFactory { } } + /** + * The built-in codec for {@code byte} + */ public static class ByteDBFieldCodec extends AbstractDBFieldCodec { public ByteDBFieldCodec(Class objectType, Field field, int column) { @@ -193,6 +439,9 @@ public class DBCachedObjectStoreFactory { } } + /** + * The built-in codec for {@code short} + */ public static class ShortDBFieldCodec extends AbstractDBFieldCodec { public ShortDBFieldCodec(Class objectType, Field field, int column) { @@ -217,6 +466,9 @@ public class DBCachedObjectStoreFactory { } } + /** + * The built-in codec for {@code int} + */ public static class IntDBFieldCodec extends AbstractDBFieldCodec { public IntDBFieldCodec(Class objectType, Field field, int column) { @@ -241,6 +493,9 @@ public class DBCachedObjectStoreFactory { } } + /** + * The built-in codec for {@code long} + */ public static class LongDBFieldCodec extends AbstractDBFieldCodec { public LongDBFieldCodec(Class objectType, Field field, int column) { @@ -265,6 +520,9 @@ public class DBCachedObjectStoreFactory { } } + /** + * The built-in codec for {@link String} + */ public static class StringDBFieldCodec extends AbstractDBFieldCodec { public StringDBFieldCodec(Class objectType, Field field, int column) { @@ -289,6 +547,9 @@ public class DBCachedObjectStoreFactory { } } + /** + * The built-in codec for {@code byte[]} + */ public static class ByteArrayDBFieldCodec extends AbstractDBFieldCodec { public ByteArrayDBFieldCodec(Class objectType, Field field, int column) { @@ -313,6 +574,9 @@ public class DBCachedObjectStoreFactory { } } + /** + * The built-in codec for {@code long[]} + */ public static class LongArrayDBFieldCodec extends AbstractDBFieldCodec { @@ -361,6 +625,9 @@ public class DBCachedObjectStoreFactory { } } + /** + * The built-in codec for {@link Enum} + */ public static class EnumDBByteFieldCodec> extends AbstractDBFieldCodec { private final E[] consts; @@ -410,15 +677,50 @@ public class DBCachedObjectStoreFactory { } } + /** + * Codec for a primitive type + * + *

+ * This is used by {@link VariantDBFieldCodec} to encode primitive values. Sadly, the existing + * primitive field codecs cannot be used, since they write to fields directly. All these encode + * into byte buffers, since the variant codec uses {@link BinaryField}. + * + * @param the type of values encoded + */ public interface PrimitiveCodec { + /** + * A byte value which identifies this codec's type as the selected type + * + * @return the selector + */ byte getSelector(); + /** + * Decode the value from the given buffer + * + * @param buffer the source buffer + * @return the value + */ T decode(ByteBuffer buffer); + /** + * Encode the value into the given buffer + * + * @param buffer the destination buffer + * @param value the value + */ void encode(ByteBuffer buffer, T value); + /** + * The the class describing {@link T} + * + * @return the class + */ Class getValueClass(); + /** + * An abstract implementation of {@link PrimitiveCodec} + */ abstract class AbstractPrimitiveCodec implements PrimitiveCodec { static byte nextSelector = 0; protected final byte selector = nextSelector++; @@ -439,6 +741,9 @@ public class DBCachedObjectStoreFactory { } } + /** + * A implementation of {@link PrimitiveCodec} from lambdas or method references + */ class SimplePrimitiveCodec extends AbstractPrimitiveCodec { protected final Function decode; protected final BiConsumer encode; @@ -461,11 +766,19 @@ public class DBCachedObjectStoreFactory { } } + /** + * An implementation of an array codec, using its element codec, where elements can be + * primitives + * + * @param the type of elements + * @param the type of the value, i.e., would be {@code E[]}, except we want {@link E} to + * be primitive. + */ class ArrayPrimitiveCodec extends AbstractPrimitiveCodec { protected final PrimitiveCodec elemCodec; protected final Class elemClass; - public

ArrayPrimitiveCodec(Class valueClass, PrimitiveCodec elemCodec) { + public ArrayPrimitiveCodec(Class valueClass, PrimitiveCodec elemCodec) { super(valueClass); assert valueClass.isArray(); this.elemCodec = elemCodec; @@ -495,6 +808,11 @@ public class DBCachedObjectStoreFactory { } } + /** + * An implementation of an array codec, using its element codec, where elements are objects + * + * @param the type of elements + */ class ArrayObjectCodec extends ArrayPrimitiveCodec { @SuppressWarnings("unchecked") public ArrayObjectCodec(PrimitiveCodec elemCodec) { @@ -503,6 +821,9 @@ public class DBCachedObjectStoreFactory { } } + /** + * A codec which encodes length-value, using the (unbounded) codec for value + */ class LengthBoundCodec extends AbstractPrimitiveCodec { protected final PrimitiveCodec unbounded; @@ -535,18 +856,30 @@ public class DBCachedObjectStoreFactory { } } + /* + * WARNING: Careful changing the order of these declarations, as this will change the + * selectors. Doing so would require a schema version bump of any table using the + * {@link VariantDBFieldCodec}. + */ + /** Codec for {@code boolean} */ PrimitiveCodec BOOL = new SimplePrimitiveCodec<>(Boolean.class, buf -> buf.get() != 0, (buf, b) -> buf.put((byte) (b ? 1 : 0))); + /** Codec for {@code byte} */ PrimitiveCodec BYTE = new SimplePrimitiveCodec<>(Byte.class, ByteBuffer::get, ByteBuffer::put); + /** Codec for {@code char} */ PrimitiveCodec CHAR = new SimplePrimitiveCodec<>(Character.class, ByteBuffer::getChar, ByteBuffer::putChar); + /** Codec for {@code short} */ PrimitiveCodec SHORT = new SimplePrimitiveCodec<>(Short.class, ByteBuffer::getShort, ByteBuffer::putShort); + /** Codec for {@code int} */ PrimitiveCodec INT = new SimplePrimitiveCodec<>(Integer.class, ByteBuffer::getInt, ByteBuffer::putInt); + /** Codec for {@code long} */ PrimitiveCodec LONG = new SimplePrimitiveCodec<>(Long.class, ByteBuffer::getLong, ByteBuffer::putLong); + /** Codec for {@link String} */ PrimitiveCodec STRING = new AbstractPrimitiveCodec<>(String.class) { final Charset cs = Charset.forName("UTF-8"); @@ -568,7 +901,9 @@ public class DBCachedObjectStoreFactory { enc.encode(CharBuffer.wrap(value), buffer, true); } }; + /** Codec for {@code boolean[]} */ PrimitiveCodec BOOL_ARR = new ArrayPrimitiveCodec<>(boolean[].class, BOOL); + /** Codec for {@code byte[]} */ PrimitiveCodec BYTE_ARR = new AbstractPrimitiveCodec<>(byte[].class) { @Override public byte[] decode(ByteBuffer buffer) { @@ -582,10 +917,15 @@ public class DBCachedObjectStoreFactory { buffer.put(value); } }; + /** Codec for {@code char[]} */ PrimitiveCodec CHAR_ARR = new ArrayPrimitiveCodec<>(char[].class, CHAR); + /** Codec for {@code short[]} */ PrimitiveCodec SHORT_ARR = new ArrayPrimitiveCodec<>(short[].class, SHORT); + /** Codec for {@code int[]} */ PrimitiveCodec INT_ARR = new ArrayPrimitiveCodec<>(int[].class, INT); + /** Codec for {@code long[]} */ PrimitiveCodec LONG_ARR = new ArrayPrimitiveCodec<>(long[].class, LONG); + /** Codec for {@code String[]} */ PrimitiveCodec STRING_ARR = new ArrayObjectCodec<>(new LengthBoundCodec<>(STRING)); @@ -597,6 +937,14 @@ public class DBCachedObjectStoreFactory { .stream() .collect(Collectors.toMap(c -> c.getValueClass(), c -> c)); + /** + * Get the codec for the given type + * + * @param the type + * @param cls the class describing {@link T} + * @return the codec + * @throws IllegalArgumentException if the type is not supported + */ static PrimitiveCodec getCodec(Class cls) { @SuppressWarnings("unchecked") PrimitiveCodec obj = (PrimitiveCodec) CODECS_BY_CLASS.get(cls); @@ -606,6 +954,13 @@ public class DBCachedObjectStoreFactory { return obj; } + /** + * Get the codec for the given selector + * + * @param sel the selector + * @return the codec + * @throws IllegalArgumentException if the selector is unknown + */ static PrimitiveCodec getCodec(byte sel) { PrimitiveCodec obj = CODECS_BY_SELECTOR.get(sel); if (obj == null) { @@ -615,15 +970,27 @@ public class DBCachedObjectStoreFactory { } } - public static abstract class AbstractVariantDBFieldCodec + /** + * A custom codec for field of "variant" type + * + *

+ * This is suitable for use on fields of type {@link Object}; however, only certain types can + * actually be encoded. The encoding uses a 1-byte type selector followed by the byte-array + * encoded value. + */ + public static class VariantDBFieldCodec extends AbstractDBFieldCodec { - public AbstractVariantDBFieldCodec(Class objectType, Field field, int column) { + public VariantDBFieldCodec(Class objectType, Field field, int column) { super(Object.class, objectType, BinaryField.class, field, column); } - protected abstract PrimitiveCodec getPrimitiveCodec(Class cls); + protected PrimitiveCodec getPrimitiveCodec(Class cls) { + return PrimitiveCodec.getCodec(cls); + } - protected abstract PrimitiveCodec getPrimitiveCodec(OT obj, byte sel); + protected PrimitiveCodec getPrimitiveCodec(OT obj, byte sel) { + return PrimitiveCodec.getCodec(sel); + } protected byte[] encode(Object value) { if (value == null) { @@ -676,30 +1043,28 @@ public class DBCachedObjectStoreFactory { } } - public static class VariantDBFieldCodec - extends AbstractVariantDBFieldCodec { - public VariantDBFieldCodec(Class objectType, Field field, int column) { - super(objectType, field, column); - } - - @Override - protected PrimitiveCodec getPrimitiveCodec(Class cls) { - return PrimitiveCodec.getCodec(cls); - } - - @Override - protected PrimitiveCodec getPrimitiveCodec(OT obj, byte sel) { - return PrimitiveCodec.getCodec(sel); - } - } - + /** + * The information needed to construct a {@link Table} and store objects into it + * + * @param the type of object stored in the table + */ private static class TableInfo { public final Schema schema; public final int[] indexColumns; public final ArrayList> codecs; + /** + * Derive the table information + * + * @param objectType the class of objects being described + * @param schemaVersion the schema version as given in + * {@link DBAnnotatedObjectInfo#version()} + * @param fieldsByColumnName the class fields by user-defined column name + * @param indexFields the fields selected for table indexes + * @param sparseFields the fields selected for sparse storage + */ TableInfo(Class objectType, int schemaVersion, Map fieldsByColumnName, - Collection indexFields) { + Collection indexFields, Collection sparseFields) { codecs = new ArrayList<>(fieldsByColumnName.size()); List indexCols = new ArrayList<>(indexFields.size()); SchemaBuilder builder = new SchemaBuilder(); @@ -714,16 +1079,19 @@ public class DBCachedObjectStoreFactory { indexCols.add(next); } codecs.add(codec); - builder.field(ent.getKey(), codec.getFieldType()); + builder.field(ent.getKey(), codec.getFieldType(), sparseFields.contains(field)); } schema = builder.build(); - indexColumns = new int[indexCols.size()]; - for (int i = 0; i < indexColumns.length; i++) { - indexColumns[i] = indexCols.get(i); - } + indexColumns = SchemaBuilder.toIntArray(indexCols); } + /** + * Initialize the static {@link DBObjectColumn} fields marked with {@link DBAnnotatedColumn} + * + * @param objectType the clas of objects being described + * @param numbersByName the assigned column numbers by user-defined name + */ void writeColumnNumbers(Class objectType, Map numbersByName) { Class superType = objectType.getSuperclass(); @@ -771,6 +1139,11 @@ public class DBCachedObjectStoreFactory { } } + /** + * Initialize the static {@link DBObjectColumn} fields marked with {@link DBAnnotatedColumn} + * + * @param objectType the clas of objects being described + */ void writeColumnNumbers(Class objectType) { Map numbersByName = new HashMap<>(); String[] names = schema.getFieldNames(); @@ -781,9 +1154,19 @@ public class DBCachedObjectStoreFactory { } } + /** + * A cache of derived table information by class + */ private static final Map, TableInfo> INFO_MAP = new HashMap<>(); + /** + * Get a built-in codec for a field of the given type + * + * @param type the type + * @return the built-in codec + * @throws NoDefaultCodecException if there is no built-in codec for the field + */ private static Class getDefaultCodecClass(Class type) { if (type == boolean.class || type == Boolean.class) { return BooleanDBFieldCodec.class; @@ -817,6 +1200,20 @@ public class DBCachedObjectStoreFactory { type + " does not have a default codec. Please specify a codec."); } + /** + * Construct the codec for the given field + * + *

+ * This adheres to the custom codec, if specified on the fields annotation. + * + * @param the type of objects being described + * @param objectType the class describing {@link OT} + * @param field the field to encode and decode + * @param column the column number in the record + * @return the codec + * @throws IllegalArgumentException if the selected codec's constructor does not have the + * required signature + */ @SuppressWarnings({ "unchecked" }) private static DBFieldCodec makeCodec( Class objectType, Field field, int column) throws IllegalArgumentException { @@ -844,19 +1241,36 @@ public class DBCachedObjectStoreFactory { } } + /** + * Get the table information for the given class + * + * @param the type of objects to store in a table + * @param cls the class describing {@link T} + * @return the table information + */ @SuppressWarnings("unchecked") - public static TableInfo getInfo(Class cls) { + private static TableInfo getInfo(Class cls) { synchronized (INFO_MAP) { return (TableInfo) INFO_MAP.computeIfAbsent(cls, DBCachedObjectStoreFactory::buildInfo); } } + /** + * Get the codecs for the given class + * + * @param the type of objects to store in the table + * @param objectType the class describing {@link OT} + * @return the codecs, in column order + */ static List> getCodecs( Class objectType) { return getInfo(objectType).codecs; } + /** + * The non-cached implementation of {@link #getInfo(Class)} + */ private static TableInfo buildInfo(Class objectType) { DBAnnotatedObjectInfo info = objectType.getAnnotation(DBAnnotatedObjectInfo.class); if (info == null) { @@ -867,19 +1281,29 @@ public class DBCachedObjectStoreFactory { Map fields = new LinkedHashMap<>(); List indexFields = new ArrayList<>(); - collectFields(objectType, fields, indexFields); + List sparseFields = new ArrayList<>(); + collectFields(objectType, fields, indexFields, sparseFields); - TableInfo tableInfo = new TableInfo<>(objectType, info.version(), fields, indexFields); + TableInfo tableInfo = + new TableInfo<>(objectType, info.version(), fields, indexFields, sparseFields); tableInfo.writeColumnNumbers(objectType); return tableInfo; } + /** + * Collect the fields of the given class, recursively, starting with its super class + * + * @param cls the class + * @param fields a map to receive the fields + * @param indexFields a list for receiving fields to be indexed + * @param sparseFields a list for receiving fields to have sparse storage + */ private static void collectFields(Class cls, Map fields, - List indexFields) { + List indexFields, List sparseFields) { Class superclass = cls.getSuperclass(); if (superclass != null) { - collectFields(superclass, fields, indexFields); + collectFields(superclass, fields, indexFields, sparseFields); } for (Field f : cls.getDeclaredFields()) { DBAnnotatedField annotation = f.getAnnotation(DBAnnotatedField.class); @@ -899,17 +1323,39 @@ public class DBCachedObjectStoreFactory { if (annotation.indexed()) { indexFields.add(f); } + if (annotation.sparse()) { + sparseFields.add(f); + } } } private final DBHandle handle; private final DBCachedDomainObjectAdapter adapter; + /** + * Construct an object store factory + * + * @param adapter the object whose tables to manage + */ public DBCachedObjectStoreFactory(DBCachedDomainObjectAdapter adapter) { this.handle = adapter.getDBHandle(); this.adapter = adapter; } + /** + * Get or create the table needed to store objects of the given class + * + *

+ * See {@link #getOrCreateCachedStore(String, Class, DBAnnotatedObjectFactory, boolean)} + * + * @param name the table name + * @param cls the type of objects to store + * @param upgradable true if {@link VersionException}s should be marked upgradable when an + * existing table's version is earlier than expected + * @return the table + * @throws IOException if there's an issue accessing the database + * @throws VersionException if an existing table's version does not match that expected + */ public Table getOrCreateTable(String name, Class cls, boolean upgradable) throws IOException, VersionException { // TODO: System of upgraders @@ -926,6 +1372,19 @@ public class DBCachedObjectStoreFactory { return table; } + /** + * Get or create a cached store of objects of the given class + * + * @param the type of objects in the store + * @param tableName the table name + * @param cls the class describing {@link T} + * @param factory the object's constructor, usually a method reference or lambda + * @param upgradable true if {@link VersionException}s should be marked upgradable when an + * existing table's version is earlier than expected + * @return the table + * @throws IOException if there's an issue accessing the database + * @throws VersionException if an existing table's version does not match that expected + */ public DBCachedObjectStore getOrCreateCachedStore( String tableName, Class cls, DBAnnotatedObjectFactory factory, boolean upgradable) throws VersionException, IOException { diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreFoundKeysValueCollection.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreFoundKeysValueCollection.java index 15f7814162..0ab07c1e33 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreFoundKeysValueCollection.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreFoundKeysValueCollection.java @@ -26,19 +26,24 @@ import db.Field; import db.util.ErrorHandler; import ghidra.util.LockHold; +/** + * This provides the implementation of {@link DBCachedObjectIndex#get(Object)} + * + * @param the type of objects in the store + */ public class DBCachedObjectStoreFoundKeysValueCollection implements Collection { protected final DBCachedObjectStore store; protected final ErrorHandler errHandler; protected final ReadWriteLock lock; - protected final Set keys; + protected final List keys; public DBCachedObjectStoreFoundKeysValueCollection(DBCachedObjectStore store, ErrorHandler errHandler, ReadWriteLock lock, Field[] keys) { this.store = store; this.errHandler = errHandler; this.lock = lock; - this.keys = Stream.of(keys).map(Field::getLongValue).collect(Collectors.toSet()); + this.keys = Stream.of(keys).map(Field::getLongValue).collect(Collectors.toList()); } @Override diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreKeySet.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreKeySet.java index c722dadb8c..14b009fd6e 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreKeySet.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreKeySet.java @@ -25,6 +25,9 @@ import com.google.common.collect.Range; import db.util.ErrorHandler; import ghidra.util.database.DirectedIterator.Direction; +/** + * This provides the implementation of {@link Map#keySet()} for {@link DBCachedObjectStore#asMap()} + */ public class DBCachedObjectStoreKeySet implements NavigableSet { protected final DBCachedObjectStore store; protected final ErrorHandler errHandler; diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreKeySubSet.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreKeySubSet.java index 6d02e6f057..c305c19a24 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreKeySubSet.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreKeySubSet.java @@ -24,6 +24,13 @@ import com.google.common.collect.Range; import db.util.ErrorHandler; import ghidra.util.database.DirectedIterator.Direction; +/** + * This is the sub-ranged form of {@link DBCachedObjectStoreKeySubSet} + * + *

+ * For example, this can be obtained via {@code store.asMap().subMap(...).keySet()} or + * {@code map.keySet().subSet(...)}. + */ public class DBCachedObjectStoreKeySubSet extends DBCachedObjectStoreKeySet { protected final Range keyRange; diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreMap.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreMap.java index 9717ff3b28..f48d8fa0d6 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreMap.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreMap.java @@ -25,6 +25,16 @@ import com.google.common.collect.Range; import db.util.ErrorHandler; import ghidra.util.database.DirectedIterator.Direction; +/** + * This provides the implementation of {@link DBCachedObjectStore#asMap()} + * + *

+ * This implements a map from object id (long) to object. Objects cannot be added directly to this + * map, e.g., {@link #put(Long, DBAnnotatedObject)} is not supported. Instead use + * {@link DBCachedObjectStore#create(long)}. + * + * @param the type of objects in the store + */ public class DBCachedObjectStoreMap implements NavigableMap { protected final DBCachedObjectStore store; protected final ErrorHandler errHandler; diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreSubMap.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreSubMap.java index d53b34d311..13ca16e6d6 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreSubMap.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreSubMap.java @@ -22,6 +22,14 @@ import com.google.common.collect.Range; import db.util.ErrorHandler; import ghidra.util.database.DirectedIterator.Direction; +/** + * This is the sub-ranged form of {@link DBCachedObjectStoreMap} + * + *

+ * For example, this can be obtained via {@code store.asMap().subMap(...)}. + * + * @param the type of objects in the store + */ public class DBCachedObjectStoreSubMap extends DBCachedObjectStoreMap { protected final Range keyRange; diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreValueCollection.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreValueCollection.java index 1287ec83b2..f57bd9b66d 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreValueCollection.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreValueCollection.java @@ -15,13 +15,17 @@ */ package ghidra.util.database; -import java.util.Collection; -import java.util.Iterator; +import java.util.*; import java.util.concurrent.locks.ReadWriteLock; import db.util.ErrorHandler; import ghidra.util.database.DirectedIterator.Direction; +/** + * This provides the implementation of {@link Map#values()} for {@link DBCachedObjectStore#asMap()} + * + * @param the type of objects in the store + */ public class DBCachedObjectStoreValueCollection implements Collection { protected final DBCachedObjectStore store; diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreValueSubCollection.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreValueSubCollection.java index 848c28f6d5..d10b339f84 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreValueSubCollection.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreValueSubCollection.java @@ -24,6 +24,12 @@ import com.google.common.collect.Range; import db.util.ErrorHandler; import ghidra.util.database.DirectedIterator.Direction; +/** + * This is the sub-ranged form of {@link DBCachedObjectStoreValueCollection} + * + *

+ * For example, this can be obtained via {@code store.asMap().subMap(...).values()}. + */ public class DBCachedObjectStoreValueSubCollection extends DBCachedObjectStoreValueCollection { protected final Range keyRange; diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBObjectColumn.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBObjectColumn.java index c70e26c1a3..2dde67779a 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBObjectColumn.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBObjectColumn.java @@ -18,6 +18,18 @@ package ghidra.util.database; import java.util.ArrayList; import java.util.List; +import ghidra.util.database.annot.DBAnnotatedColumn; + +/** + * An opaque handle to the column backing an object field + * + *

+ * Each should be declared as a static field of the same class whose field it describes, probably + * with package-only access. Each must also be annotated with {@link DBAnnotatedColumn}. For an + * example, see the documentation of {@link DBAnnotatedObject}. The annotated field receives its + * value the first time a store is created for the containing class. Until then, it is + * uninitialized. + */ public class DBObjectColumn { static List instances = new ArrayList<>(20); diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBOpenMode.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBOpenMode.java index 12df83e38d..7716f69701 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBOpenMode.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBOpenMode.java @@ -17,6 +17,9 @@ package ghidra.util.database; import db.DBConstants; +/** + * An enum, providing a type-safe version of {@link DBConstants}. + */ public enum DBOpenMode { CREATE(DBConstants.CREATE), UPDATE(DBConstants.UPDATE), diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBTransaction.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBTransaction.java deleted file mode 100644 index afdb5d601a..0000000000 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBTransaction.java +++ /dev/null @@ -1,56 +0,0 @@ -/* ### - * IP: GHIDRA - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ghidra.util.database; - -import java.io.IOException; - -import db.DBHandle; - -public class DBTransaction implements AutoCloseable { - public static DBTransaction start(DBHandle handle, boolean commitByDefault) { - long tid = handle.startTransaction(); - return new DBTransaction(handle, tid, commitByDefault); - } - - private final DBHandle handle; - private final long tid; - - private boolean commit; - private boolean open = true; - - private DBTransaction(DBHandle handle, long tid, boolean commitByDefault) { - this.handle = handle; - this.tid = tid; - this.commit = commitByDefault; - } - - public void abort() throws IOException { - open = false; - handle.endTransaction(tid, false); - } - - public void commit() throws IOException { - open = false; - handle.endTransaction(tid, true); - } - - @Override - public void close() throws IOException { - if (open) { - handle.endTransaction(tid, commit); - } - } -} diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DirectedIterator.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DirectedIterator.java index 801936e58f..0d6385a37e 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DirectedIterator.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DirectedIterator.java @@ -20,18 +20,55 @@ import java.io.IOException; import com.google.common.collect.BoundType; import com.google.common.collect.Range; -public interface DirectedIterator { - public enum Direction { - FORWARD, BACKWARD; +import db.Table; - static Direction reverse(Direction direction) { - if (direction == FORWARD) { +/** + * An iterator over some component of a {@link Table} + * + * @param the type of the component, i.e., a key or record + */ +public interface DirectedIterator { + /** + * The direction of iteration + */ + public enum Direction { + FORWARD { + @Override + Direction reverse() { return BACKWARD; } - return FORWARD; + }, + BACKWARD { + @Override + Direction reverse() { + return FORWARD; + } + }; + + /** + * Get the reverse of this direction + * + * @return the reverse + */ + abstract Direction reverse(); + + /** + * Get the reverse of the given direction + * + * @param direction the direction + * @return the reverse + */ + static Direction reverse(Direction direction) { + return direction.reverse(); } } + /** + * Get the discrete lower bound of the given range + * + * @param range the range + * @return the lower bound + */ static long toIteratorMin(Range range) { if (range == null) { return Long.MIN_VALUE; @@ -47,6 +84,12 @@ public interface DirectedIterator { } } + /** + * Get the discrete upper bound of the given range + * + * @param range the range + * @return the upper bound + */ static long toIteratorMax(Range range) { if (range == null) { return Long.MAX_VALUE; @@ -62,17 +105,51 @@ public interface DirectedIterator { } } + /** + * Compute the effective starting point for a forward iterator starting at the given bound + * + * @param range the range describing a limited view of keys + * @param bound the starting key + * @param inclusive whether the starting key is included + * @return the starting point, inclusive + */ static long clampLowerBound(Range range, long bound, boolean inclusive) { return Math.max(toIteratorMin(range), inclusive ? bound : bound + 1); } + /** + * Compute the effective starting point for a backward iterator starting at the given bound + * + * @param range the range describing a limited view of keys + * @param bound the starting key + * @param inclusive whether the starting key is included + * @return the starting point, inclusive + */ static long clampUpperBound(Range range, long bound, boolean inclusive) { return Math.min(toIteratorMax(range), inclusive ? bound : bound - 1); } + /** + * Check if the table has another record + * + * @return true if so + * @throws IOException if the table cannot be read + */ boolean hasNext() throws IOException; + /** + * Get the component of the next record + * + * @return the component + * @throws IOException if the table cannot be read + */ T next() throws IOException; + /** + * Delete the current record + * + * @return true if successful + * @throws IOException if the table cannot be accessed + */ boolean delete() throws IOException; } diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DirectedLongKeyIterator.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DirectedLongKeyIterator.java index 9100996986..14a89c41f1 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DirectedLongKeyIterator.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DirectedLongKeyIterator.java @@ -21,7 +21,19 @@ import com.google.common.collect.Range; import db.Table; +/** + * An iterator over keys of a table + */ public interface DirectedLongKeyIterator extends DirectedIterator { + /** + * Get an iterator over the table, restricted to the given range, in the given direction + * + * @param table the table + * @param keyRange the limited range + * @param direction the direction + * @return the iterator + * @throws IOException if the table cannot be read + */ public static AbstractDirectedLongKeyIterator getIterator(Table table, Range keyRange, Direction direction) throws IOException { long min = DirectedIterator.toIteratorMin(keyRange); diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DirectedRecordIterator.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DirectedRecordIterator.java index 2e57f2e2ef..1171217d09 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DirectedRecordIterator.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DirectedRecordIterator.java @@ -22,8 +22,20 @@ import com.google.common.collect.Range; import db.*; +/** + * An iterator over records of a table + */ public interface DirectedRecordIterator extends DirectedIterator { + /** + * Get an iterator over the table, restricted to the given range of keys, in the given direction + * + * @param table the table + * @param keyRange the limited range + * @param direction the direction + * @return the iterator + * @throws IOException if the table cannot be read + */ public static AbstractDirectedRecordIterator getIterator(Table table, Range keyRange, Direction direction) throws IOException { long min = DirectedIterator.toIteratorMin(keyRange); @@ -34,6 +46,13 @@ public interface DirectedRecordIterator extends DirectedIterator { return new BackwardRecordIterator(table.iterator(min, max, max)); } + /** + * Given an iterator over a closed range. Change its behavior to exclude the lower bound + * + * @param it the iterator over the closed range + * @param columnIndex the column number whose index being iterated + * @param exclude the lower bound to be excluded + */ private static DirectedRecordIterator applyBegFilter(DirectedRecordIterator it, int columnIndex, Field exclude) throws IOException { return new DirectedRecordIterator() { @@ -71,6 +90,13 @@ public interface DirectedRecordIterator extends DirectedIterator { }; } + /** + * Given an iterator over a closed range. Change its behavior to exclude the upper bound + * + * @param it the iterator over the closed range + * @param columnIndex the column number whose index being iterated + * @param exclude the upper bound to be excluded + */ private static DirectedRecordIterator applyEndFilter(DirectedRecordIterator it, int columnIndex, Field exclude) throws IOException { return new DirectedRecordIterator() { @@ -108,6 +134,17 @@ public interface DirectedRecordIterator extends DirectedIterator { return it; } + /** + * Get an iterator over the table using a given index, restricted to the given range of values, + * in the given direction + * + * @param table the table + * @param columnIndex the column number of the index + * @param fieldRange the limited range + * @param direction the direction + * @return the iterator + * @throws IOException if the table cannot be read + */ public static DirectedRecordIterator getIndexIterator(Table table, int columnIndex, Range fieldRange, Direction direction) throws IOException { Field lower = fieldRange.hasLowerBound() ? fieldRange.lowerEndpoint() : null; diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/ForwardLongKeyIterator.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/ForwardLongKeyIterator.java index 1a0cc33ac1..b706ea3ead 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/ForwardLongKeyIterator.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/ForwardLongKeyIterator.java @@ -19,6 +19,10 @@ import java.io.IOException; import db.DBLongIterator; +/** + * A wrapper of {@link DBLongIterator} that runs it forward and implements + * {@link DirectedLongKeyIterator} + */ public class ForwardLongKeyIterator extends AbstractDirectedLongKeyIterator { public ForwardLongKeyIterator(DBLongIterator it) { super(it); diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/ForwardRecordIterator.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/ForwardRecordIterator.java index e14146459c..3a5f327ef9 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/ForwardRecordIterator.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/ForwardRecordIterator.java @@ -20,6 +20,10 @@ import java.io.IOException; import db.DBRecord; import db.RecordIterator; +/** + * A wrapper of {@link RecordIterator} that runs it forward and implements + * {@link DirectedRecordIterator} + */ public class ForwardRecordIterator extends AbstractDirectedRecordIterator { public ForwardRecordIterator(RecordIterator it) { super(it); diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/ObjectKey.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/ObjectKey.java index 92e915cd1a..6efb46da31 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/ObjectKey.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/ObjectKey.java @@ -17,24 +17,22 @@ package ghidra.util.database; import java.util.Objects; -import ghidra.framework.data.DomainObjectAdapterDB; +import db.Table; /** - * Enough information to uniquely identify a trace object + * An opaque handle uniquely identifying a database-backed object */ public class ObjectKey implements Comparable { - private final DomainObjectAdapterDB adapter; - private final String tableName; + private final Table table; private final long key; private final int hash; - public ObjectKey(DomainObjectAdapterDB adapter, String tableName, long key) { - this.adapter = adapter; - this.tableName = tableName; + public ObjectKey(Table table, long key) { + this.table = table; this.key = key; - this.hash = Objects.hash(System.identityHashCode(adapter), tableName, key); + this.hash = Objects.hash(System.identityHashCode(table), key); } @Override @@ -43,10 +41,7 @@ public class ObjectKey implements Comparable { return false; } ObjectKey that = (ObjectKey) obj; - if (this.adapter != that.adapter) { - return false; - } - if (!(Objects.equals(this.tableName, that.tableName))) { + if (this.table != that.table) { return false; } if (this.key != that.key) { @@ -63,16 +58,8 @@ public class ObjectKey implements Comparable { @Override public int compareTo(ObjectKey that) { int result; - if (this.adapter != that.adapter) { - result = this.adapter.getName().compareTo(that.adapter.getName()); - if (result != 0) { - return result; - } - return System.identityHashCode(this.adapter) - System.identityHashCode(that.adapter); - } - result = this.tableName.compareTo(that.tableName); - if (result != 0) { - return result; + if (this.table != that.table) { + return System.identityHashCode(this.table) - System.identityHashCode(that.table); } result = Long.compareUnsigned(this.key, that.key); if (result != 0) { diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/SchemaBuilder.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/SchemaBuilder.java index c5b4dc21cd..1e7c040114 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/SchemaBuilder.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/SchemaBuilder.java @@ -22,7 +22,38 @@ import org.apache.commons.lang3.ArrayUtils; import db.*; +/** + * A builder for {@link Schema} + * + *

+ * Provides a more fluent syntax for creating table schemas. For example: + * + *

+ * new Schema(1, StringField.class, "UUID",
+ * 	new Class[] { StringField.class, IntField.class }, new String[] { "Name", "Flags" },
+ * 	new int[] { 1 });
+ * 
+ * + *

+ * Can be expressed using the builder: + * + *

+ * new SchemaBuilder().keyField("UUID", StringField.class)
+ * 		.field("Name", StringField.class)
+ * 		.field("Flags", IntField.class, true)
+ * 		.build();
+ * 
+ */ public class SchemaBuilder { + + public static int[] toIntArray(List list) { + int[] arr = new int[list.size()]; + for (int i = 0; i < arr.length; i++) { + arr[i] = list.get(i); + } + return arr; + } + public static int getColumnIndex(Schema schema, String name) { return ArrayUtils.indexOf(schema.getFieldNames(), name); } @@ -30,10 +61,11 @@ public class SchemaBuilder { private int version = 0; private String keyFieldName = "Key"; private Class keyFieldClass = LongField.class; - private List fieldNames = new ArrayList<>(); - private List> fieldClasses = new ArrayList<>(); + private final List fieldNames = new ArrayList<>(); + private final List> fieldClasses = new ArrayList<>(); + private final List sparseColumns = new ArrayList<>(); - public SchemaBuilder version(@SuppressWarnings("hiding") int version) { + public SchemaBuilder version(int version) { this.version = version; return this; } @@ -44,12 +76,20 @@ public class SchemaBuilder { return this; } - public SchemaBuilder field(String name, Class cls) { + public SchemaBuilder field(String name, Class cls, boolean sparse) { + int index = fieldCount(); this.fieldNames.add(name); this.fieldClasses.add(cls); + if (sparse) { + this.sparseColumns.add(index); + } return this; } + public SchemaBuilder field(String name, Class cls) { + return field(name, cls, false); + } + public int fieldCount() { return fieldNames.size(); } @@ -57,6 +97,6 @@ public class SchemaBuilder { public Schema build() { return new Schema(version, keyFieldClass, keyFieldName, fieldClasses.toArray(new Class[fieldClasses.size()]), - fieldNames.toArray(new String[fieldNames.size()])); + fieldNames.toArray(new String[fieldNames.size()]), toIntArray(sparseColumns)); } } diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/UndoableTransaction.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/UndoableTransaction.java index b6fc85dc52..6c43edc230 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/UndoableTransaction.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/UndoableTransaction.java @@ -15,51 +15,132 @@ */ package ghidra.util.database; +import java.io.IOException; + import javax.help.UnsupportedOperationException; +import db.DBHandle; +import db.NoTransactionException; +import db.util.ErrorHandler; import ghidra.framework.model.AbortedTransactionListener; import ghidra.framework.model.UndoableDomainObject; import ghidra.program.model.data.DataTypeManager; import ghidra.program.model.listing.ProgramUserData; import ghidra.util.Msg; +/** + * Provides syntax for opening a database transaction using a try-with-resources block + * + *

+ * For example, using {@link UndoableDomainObject#startTransaction(String)} directly: + * + *

+ * int txid = program.startTransaction("Do a thing");
+ * try {
+ * 	// ... Do that thing
+ * }
+ * finally {
+ * 	program.endTransaction(txid, true);
+ * }
+ * 
+ * + *

+ * Can be expressed using an undoable transaction instead: + * + *

+ * try (UndoableTransaction txid = UndoableTransaction.start(program, "Do a thing", true)) {
+ * 	// ... Do that thing
+ * }
+ * 
+ */ public interface UndoableTransaction extends AutoCloseable { - public static UndoableTransaction start(UndoableDomainObject domainObject, String description, - boolean commitByDefault) { + /** + * Open a transaction directly on a database handle + * + * @param handle the handle + * @param errHandler a handler for database errors, usually the domain object + * @return the transaction handle + */ + public static UndoableTransaction start(DBHandle handle, ErrorHandler errHandler) { + long tid = handle.startTransaction(); + return new DBHandleUndoableTransaction(handle, tid, errHandler); + } + + /** + * Open a transaction on a domain object + * + * @param domainObject the domain object + * @param description a description of the change + * @return the transaction handle + */ + public static UndoableTransaction start(UndoableDomainObject domainObject, String description) { int tid = domainObject.startTransaction(description); - return new DomainObjectUndoableTransaction(domainObject, tid, commitByDefault); + return new DomainObjectUndoableTransaction(domainObject, tid); } + /** + * Open a transaction on a domain object + * + *

+ * Even if this transaction is committed, if a sub-transaction is aborted, this transaction + * could become aborted, too. The listener can be used to detect this situation. + * + * @param domainObject the domain object + * @param description a description of the change + * @param listener a listener for aborted transactions + * @param commitByDefault true to commit at the end of the block + * @return the transaction handle + */ public static UndoableTransaction start(UndoableDomainObject domainObject, String description, - AbortedTransactionListener listener, boolean commitByDefault) { + AbortedTransactionListener listener) { int tid = domainObject.startTransaction(description, listener); - return new DomainObjectUndoableTransaction(domainObject, tid, commitByDefault); + return new DomainObjectUndoableTransaction(domainObject, tid); } - public static UndoableTransaction start(DataTypeManager dataTypeManager, String description, - boolean commitByDefault) { + /** + * Open a transaction on a data type manager + * + * @param dataTypeManager the data type manager + * @param description a description of the change + * @param commitByDefault true to commit at the end of the block + * @return the transaction handle + */ + public static UndoableTransaction start(DataTypeManager dataTypeManager, String description) { int tid = dataTypeManager.startTransaction(description); - return new DataTypeManagerUndoableTransaction(dataTypeManager, tid, commitByDefault); + return new DataTypeManagerUndoableTransaction(dataTypeManager, tid); } + /** + * Open a transaction on program user data + * + * @param userData the user data + * @return the transaction handle + */ public static UndoableTransaction start(ProgramUserData userData) { int tid = userData.startTransaction(); return new ProgramUserDataUndoableTransaction(userData, tid); } abstract class AbstractUndoableTransaction implements UndoableTransaction { - protected final int transactionID; - private boolean commit; + private boolean commit = true; private boolean open = true; - private AbstractUndoableTransaction(int transactionID, boolean commitByDefault) { - this.transactionID = transactionID; - this.commit = commitByDefault; + protected AbstractUndoableTransaction() { } abstract void endTransaction(@SuppressWarnings("hiding") boolean commit); + @Override + public void abortOnClose() { + commit = false; + } + + @Override + public void commitOnClose() { + commit = true; + } + @Override public void abort() { if (open) { @@ -85,12 +166,54 @@ public interface UndoableTransaction extends AutoCloseable { } } - class DomainObjectUndoableTransaction extends AbstractUndoableTransaction { + abstract class AbstractLongUndoableTransaction extends AbstractUndoableTransaction { + final long transactionID; + + public AbstractLongUndoableTransaction(long transactionID) { + super(); + this.transactionID = transactionID; + } + } + + abstract class AbstractIntUndoableTransaction extends AbstractUndoableTransaction { + final int transactionID; + + public AbstractIntUndoableTransaction(int transactionID) { + super(); + this.transactionID = transactionID; + } + } + + class DBHandleUndoableTransaction extends AbstractLongUndoableTransaction { + private final DBHandle handle; + private final ErrorHandler errHandler; + + public DBHandleUndoableTransaction(DBHandle handle, long transactionID, + ErrorHandler errHandler) { + super(transactionID); + this.handle = handle; + this.errHandler = errHandler; + } + + @Override + void endTransaction(boolean commit) { + if (!commit) { + Msg.debug(this, "Aborting transaction"); + } + try { + handle.endTransaction(transactionID, commit); + } + catch (IOException e) { + errHandler.dbError(e); + } + } + } + + class DomainObjectUndoableTransaction extends AbstractIntUndoableTransaction { private final UndoableDomainObject domainObject; - private DomainObjectUndoableTransaction(UndoableDomainObject domainObject, int tid, - boolean commitByDefault) { - super(tid, commitByDefault); + private DomainObjectUndoableTransaction(UndoableDomainObject domainObject, int tid) { + super(tid); this.domainObject = domainObject; } @@ -103,12 +226,11 @@ public interface UndoableTransaction extends AutoCloseable { } } - class DataTypeManagerUndoableTransaction extends AbstractUndoableTransaction { + class DataTypeManagerUndoableTransaction extends AbstractIntUndoableTransaction { private final DataTypeManager dataTypeManager; - private DataTypeManagerUndoableTransaction(DataTypeManager dataTypeManager, int tid, - boolean commitByDefault) { - super(tid, commitByDefault); + private DataTypeManagerUndoableTransaction(DataTypeManager dataTypeManager, int tid) { + super(tid); this.dataTypeManager = dataTypeManager; } @@ -118,14 +240,19 @@ public interface UndoableTransaction extends AutoCloseable { } } - class ProgramUserDataUndoableTransaction extends AbstractUndoableTransaction { + class ProgramUserDataUndoableTransaction extends AbstractIntUndoableTransaction { private final ProgramUserData userData; private ProgramUserDataUndoableTransaction(ProgramUserData userData, int tid) { - super(tid, true); + super(tid); this.userData = userData; } + @Override + public void abortOnClose() { + throw new UnsupportedOperationException(); + } + @Override public void abort() { throw new UnsupportedOperationException(); @@ -137,8 +264,48 @@ public interface UndoableTransaction extends AutoCloseable { } } + /** + * Set this transaction to commit when closed + * + *

+ * This is the default behavior. If an error occurs, or when the end of the try block is + * reached, the transaction will be committed. The user is expected to undo unwanted + * transactions, including those committed with an error. It could be the results are still + * mostly correct. Additionally, aborting a transaction can roll back other concurrent + * transactions. + */ + void commitOnClose(); + + /** + * Set this transaction to abort by when closed + * + *

+ * Ordinarily, if an error occurs, the transaction is committed as is. The user is expected to + * undo unwanted transactions. Calling this method will cause the transaction to be aborted + * instead. WARNING: Aborting this transaction may abort other concurrent transactions. + * Use with extreme care. NOTE: Use of this method requires that the transaction be + * explicitly committed using {@link #commit()}. When this transaction is closed, if it hasn't + * been committed, it will be aborted. + */ + void abortOnClose(); + + /** + * Commit the transaction and close it immediately + * + *

+ * Note that attempting to make changes after this call will likely result in a + * {@link NoTransactionException}. + */ void commit(); + /** + * Abort the transaction and close it immediately + * + *

+ * Note that attempting to make changes after this call will likely result in a + * {@link NoTransactionException}. WARNING: Aborting this transaction may abort other + * concurrent transactions. Use with extreme care. + */ void abort(); @Override diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/annot/DBAnnotatedColumn.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/annot/DBAnnotatedColumn.java index 5dee428880..03291ea8d1 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/annot/DBAnnotatedColumn.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/annot/DBAnnotatedColumn.java @@ -17,8 +17,22 @@ package ghidra.util.database.annot; import java.lang.annotation.*; +import ghidra.util.database.DBAnnotatedObject; +import ghidra.util.database.DBObjectColumn; + +/** + * Mark a {@link DBObjectColumn} to receive a column handle + * + * @see DBAnnotatedObject + */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface DBAnnotatedColumn { + /** + * The name of the column + * + *

+ * There should be a {@link DBAnnotatedField} annotation with the same column name + */ String value(); } diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/annot/DBAnnotatedField.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/annot/DBAnnotatedField.java index 1afc7c3ff8..74c8c25690 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/annot/DBAnnotatedField.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/annot/DBAnnotatedField.java @@ -17,19 +17,58 @@ package ghidra.util.database.annot; import java.lang.annotation.*; +import db.Field; import ghidra.util.database.DBAnnotatedObject; import ghidra.util.database.DBCachedObjectStoreFactory.DBFieldCodec; +/** + * Mark a field to be stored in a table column + * + * @see DBAnnotatedObject + */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface DBAnnotatedField { + /** + * The name of the column + * + *

+ * There should be a {@link DBAnnotatedColumn} annotation with the same column name + */ String column(); + /** + * True to index the column + */ boolean indexed() default false; + /** + * True to use sparse storage + * + *

+ * If the {@link Field} used by the codec does not support null values, this can be set to true + * to allow null values. + */ + boolean sparse() default false; + + /** + * Specify a custom codec + * + *

+ * This is not required for types supported directly by a {@link Field}. + * + * @see DBFieldCodec + */ @SuppressWarnings("rawtypes") Class codec() default DefaultCodec.class; + /** + * A placeholder class + * + *

+ * A reference to this class type indicates that {@link DBAnnotatedField#codec()} was not set. + * The framework will instead check for a built-in codec. + */ static abstract class DefaultCodec implements DBFieldCodec { private DefaultCodec() { diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/annot/DBAnnotatedIndex.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/annot/DBAnnotatedIndex.java deleted file mode 100644 index 14c34adc79..0000000000 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/annot/DBAnnotatedIndex.java +++ /dev/null @@ -1,25 +0,0 @@ -/* ### - * IP: GHIDRA - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package ghidra.util.database.annot; - -import java.lang.annotation.*; - -// TODO: Process these and specify or build indices accordingly. -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -public @interface DBAnnotatedIndex { - // None -} diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/annot/DBAnnotatedObjectInfo.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/annot/DBAnnotatedObjectInfo.java index 457d8be4f8..11cb14387e 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/annot/DBAnnotatedObjectInfo.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/annot/DBAnnotatedObjectInfo.java @@ -17,8 +17,30 @@ package ghidra.util.database.annot; import java.lang.annotation.*; +import ghidra.util.database.DBAnnotatedObject; + +/** + * Required annotation for {@link DBAnnotatedObject} + */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface DBAnnotatedObjectInfo { + /** + * The schema version + * + *

+ * This should be incremented in many situtations, including but not limited to: + *

    + *
  • A field is added or removed
  • + *
  • A field's type changes
  • + *
  • A field's column name changes. See {@link DBAnnotatedField#column()}
  • + *
  • A field's codec changes. See {@link DBAnnotatedField#codec()}
  • + *
  • A field's sparse-storage flag changes. See {@link DBAnnotatedField#sparse()}
  • + *
  • A field's index flag changes. See {@link DBAnnotatedField#indexed()}
  • + *
  • The order of field declarations changes.
  • + *
  • The codec used by a field changes how it encodes values
  • + *
  • The fields of a superclass change in any of the above ways
  • + *
+ */ int version(); } diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/err/NoDefaultCodecException.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/err/NoDefaultCodecException.java index afe0a113a7..5ef05c05a2 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/err/NoDefaultCodecException.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/err/NoDefaultCodecException.java @@ -15,6 +15,9 @@ */ package ghidra.util.database.err; +/** + * Exception when a custom codec is required + */ @SuppressWarnings("serial") public class NoDefaultCodecException extends RuntimeException { public NoDefaultCodecException() { diff --git a/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/pcode/emu/linux/EmuLinuxAmd64SyscallUseropLibraryTest.java b/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/pcode/emu/linux/EmuLinuxAmd64SyscallUseropLibraryTest.java index 179ce80ad9..2445c32f61 100644 --- a/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/pcode/emu/linux/EmuLinuxAmd64SyscallUseropLibraryTest.java +++ b/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/pcode/emu/linux/EmuLinuxAmd64SyscallUseropLibraryTest.java @@ -114,7 +114,7 @@ public class EmuLinuxAmd64SyscallUseropLibraryTest extends AbstractGhidraHeadles start = space.getAddress(0x00400000); size = 0x1000; - try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize")) { block = program.getMemory() .createInitializedBlock(".text", start, size, (byte) 0, TaskMonitor.DUMMY, false); @@ -194,7 +194,7 @@ public class EmuLinuxAmd64SyscallUseropLibraryTest extends AbstractGhidraHeadles @Test public void testWriteStdout() throws Exception { - try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize")) { asm.assemble(start, "MOV RAX," + SYSCALLNO_WRITE, "MOV RDI," + EmuUnixFileDescriptor.FD_STDOUT, @@ -226,7 +226,7 @@ public class EmuLinuxAmd64SyscallUseropLibraryTest extends AbstractGhidraHeadles @Test public void testReadStdin() throws Exception { - try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize")) { asm.assemble(start, "MOV RAX," + SYSCALLNO_READ, "MOV RDI," + EmuUnixFileDescriptor.FD_STDIN, @@ -258,7 +258,7 @@ public class EmuLinuxAmd64SyscallUseropLibraryTest extends AbstractGhidraHeadles @Test public void testWritevStdout() throws Exception { - try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize")) { Address data = space.getAddress(0x00400800); ByteBuffer buf = ByteBuffer.allocate(64).order(ByteOrder.LITTLE_ENDIAN); @@ -313,7 +313,7 @@ public class EmuLinuxAmd64SyscallUseropLibraryTest extends AbstractGhidraHeadles public void testReadvStdin() throws Exception { Address strHello; Address strWorld; - try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize")) { Address data = space.getAddress(0x00400800); ByteBuffer buf = ByteBuffer.allocate(64).order(ByteOrder.LITTLE_ENDIAN); @@ -369,7 +369,7 @@ public class EmuLinuxAmd64SyscallUseropLibraryTest extends AbstractGhidraHeadles @Test public void testOpenWriteClose() throws Exception { - try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize")) { asm.assemble(start, "MOV RAX," + SYSCALLNO_OPEN, "LEA RDI,[0x00400880]", @@ -407,7 +407,7 @@ public class EmuLinuxAmd64SyscallUseropLibraryTest extends AbstractGhidraHeadles @Test public void testOpenReadClose() throws Exception { - try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize")) { asm.assemble(start, "MOV RAX," + SYSCALLNO_OPEN, "LEA RDI,[0x00400880]", diff --git a/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/pcode/emu/linux/EmuLinuxX86SyscallUseropLibraryTest.java b/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/pcode/emu/linux/EmuLinuxX86SyscallUseropLibraryTest.java index 9eecda38e6..594dccb2ec 100644 --- a/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/pcode/emu/linux/EmuLinuxX86SyscallUseropLibraryTest.java +++ b/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/pcode/emu/linux/EmuLinuxX86SyscallUseropLibraryTest.java @@ -114,7 +114,7 @@ public class EmuLinuxX86SyscallUseropLibraryTest extends AbstractGhidraHeadlessI start = space.getAddress(0x00400000); size = 0x1000; - try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize")) { block = program.getMemory() .createInitializedBlock(".text", start, size, (byte) 0, TaskMonitor.DUMMY, false); @@ -194,7 +194,7 @@ public class EmuLinuxX86SyscallUseropLibraryTest extends AbstractGhidraHeadlessI @Test public void testWriteStdout() throws Exception { - try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize")) { asm.assemble(start, "MOV EAX," + SYSCALLNO_WRITE, "MOV EBX," + EmuUnixFileDescriptor.FD_STDOUT, @@ -226,7 +226,7 @@ public class EmuLinuxX86SyscallUseropLibraryTest extends AbstractGhidraHeadlessI @Test public void testReadStdin() throws Exception { - try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize")) { asm.assemble(start, "MOV EAX," + SYSCALLNO_READ, "MOV EBX," + EmuUnixFileDescriptor.FD_STDIN, @@ -258,7 +258,7 @@ public class EmuLinuxX86SyscallUseropLibraryTest extends AbstractGhidraHeadlessI @Test public void testWritevStdout() throws Exception { - try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize")) { Address data = space.getAddress(0x00400800); ByteBuffer buf = ByteBuffer.allocate(64).order(ByteOrder.LITTLE_ENDIAN); @@ -313,7 +313,7 @@ public class EmuLinuxX86SyscallUseropLibraryTest extends AbstractGhidraHeadlessI public void testReadvStdin() throws Exception { Address strHello; Address strWorld; - try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize")) { Address data = space.getAddress(0x00400800); ByteBuffer buf = ByteBuffer.allocate(64).order(ByteOrder.LITTLE_ENDIAN); @@ -369,7 +369,7 @@ public class EmuLinuxX86SyscallUseropLibraryTest extends AbstractGhidraHeadlessI @Test public void testOpenWriteClose() throws Exception { - try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize")) { asm.assemble(start, "MOV EAX," + SYSCALLNO_OPEN, "LEA EBX,[0x00400880]", @@ -407,7 +407,7 @@ public class EmuLinuxX86SyscallUseropLibraryTest extends AbstractGhidraHeadlessI @Test public void testOpenReadClose() throws Exception { - try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize")) { asm.assemble(start, "MOV EAX," + SYSCALLNO_OPEN, "LEA EBX,[0x00400880]", diff --git a/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/pcode/emu/sys/EmuAmd64SyscallUseropLibraryTest.java b/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/pcode/emu/sys/EmuAmd64SyscallUseropLibraryTest.java index 229919ae58..e6373850c2 100644 --- a/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/pcode/emu/sys/EmuAmd64SyscallUseropLibraryTest.java +++ b/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/pcode/emu/sys/EmuAmd64SyscallUseropLibraryTest.java @@ -128,7 +128,7 @@ public class EmuAmd64SyscallUseropLibraryTest extends AbstractGhidraHeadlessInte start = space.getAddress(0x00400000); size = 0x1000; - try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize")) { block = program.getMemory() .createInitializedBlock(".text", start, size, (byte) 0, TaskMonitor.DUMMY, false); @@ -177,7 +177,7 @@ public class EmuAmd64SyscallUseropLibraryTest extends AbstractGhidraHeadlessInte @Test public void testSyscallWithStdcallConvention() throws Exception { - try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize")) { asm.assemble(start, "MOV RAX,0", "MOV RCX,0xbeef", @@ -196,7 +196,7 @@ public class EmuAmd64SyscallUseropLibraryTest extends AbstractGhidraHeadlessInte @Test public void testSyscallWithSyscallConvention() throws Exception { - try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(program, "Initialize")) { asm.assemble(start, "MOV RAX,1", "MOV RCX,0xdead", diff --git a/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/util/database/DBCachedObjectStoreFactoryTest.java b/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/util/database/DBCachedObjectStoreFactoryTest.java index 2d5bbb4349..17aafec642 100644 --- a/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/util/database/DBCachedObjectStoreFactoryTest.java +++ b/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/util/database/DBCachedObjectStoreFactoryTest.java @@ -671,7 +671,7 @@ public class DBCachedObjectStoreFactoryTest { DBHandle handle = new DBHandle(); MyDomainObject myDO = new MyDomainObject(handle, "Testing", this); DBCachedObjectStoreFactory factory = new DBCachedObjectStoreFactory(myDO); - try (UndoableTransaction trans = UndoableTransaction.start(myDO, "Create Tables", true)) { + try (UndoableTransaction trans = UndoableTransaction.start(myDO, "Create Tables")) { factory.getOrCreateCachedStore(MyObject.TABLE_NAME, MyObject.class, MyObject::new, false); factory.getOrCreateCachedStore(MyExtObject.TABLE_NAME, MyExtObject.class, @@ -715,7 +715,7 @@ public class DBCachedObjectStoreFactoryTest { DBHandle handle = new DBHandle(); MyDomainObject myDO = new MyDomainObject(handle, "Testing", this); DBCachedObjectStoreFactory factory = new DBCachedObjectStoreFactory(myDO); - try (UndoableTransaction trans = UndoableTransaction.start(myDO, "Create Tables", true)) { + try (UndoableTransaction trans = UndoableTransaction.start(myDO, "Create Tables")) { factory.getOrCreateCachedStore("MyTable", MyFromAbstract.class, MyFromAbstract::new, false); } @@ -734,7 +734,7 @@ public class DBCachedObjectStoreFactoryTest { MyDomainObject myDO = new MyDomainObject(handle, "Testing", this); DBCachedObjectStoreFactory factory = new DBCachedObjectStoreFactory(myDO); DBCachedObjectStore store; - try (UndoableTransaction trans = UndoableTransaction.start(myDO, "Create Tables", true)) { + try (UndoableTransaction trans = UndoableTransaction.start(myDO, "Create Tables")) { store = factory.getOrCreateCachedStore(MyKitchenSink.TABLE_NAME, MyKitchenSink.class, MyKitchenSink::new, false); @@ -779,7 +779,7 @@ public class DBCachedObjectStoreFactoryTest { DBHandle handle = new DBHandle(); MyDomainObject myDO = new MyDomainObject(handle, "Testing", this); DBCachedObjectStoreFactory factory = new DBCachedObjectStoreFactory(myDO); - try (UndoableTransaction trans = UndoableTransaction.start(myDO, "Create Tables", true)) { + try (UndoableTransaction trans = UndoableTransaction.start(myDO, "Create Tables")) { factory.getOrCreateCachedStore(MyUsesMyEnumTooBig.TABLE_NAME, MyUsesMyEnumTooBig.class, MyUsesMyEnumTooBig::new, false); fail(); diff --git a/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/util/database/DBCachedObjectStoreTest.java b/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/util/database/DBCachedObjectStoreTest.java index 6508272ca7..14091a6605 100644 --- a/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/util/database/DBCachedObjectStoreTest.java +++ b/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/util/database/DBCachedObjectStoreTest.java @@ -72,7 +72,7 @@ public class DBCachedObjectStoreTest { super(new DBHandle(), DBOpenMode.CREATE, new ConsoleTaskMonitor(), name, timeInterval, bufSize, consumer); this.storeFactory = new DBCachedObjectStoreFactory(this); - try (DBTransaction tid = DBTransaction.start(dbh, true)) { + try (UndoableTransaction tid = UndoableTransaction.start(dbh, this)) { this.store = storeFactory.getOrCreateCachedStore(OBJECTS_TABLE_NAME, MyObject.class, MyObject::new, false); } @@ -83,7 +83,7 @@ public class DBCachedObjectStoreTest { throws VersionException, IOException { super(handle, openMode, monitor, null, timeInterval, bufSize, consumer); this.storeFactory = new DBCachedObjectStoreFactory(this); - try (DBTransaction tid = DBTransaction.start(handle, true)) { + try (UndoableTransaction tid = UndoableTransaction.start(handle, this)) { this.store = storeFactory.getOrCreateCachedStore(OBJECTS_TABLE_NAME, MyObject.class, MyObject::new, false); } @@ -119,14 +119,14 @@ public class DBCachedObjectStoreTest { public void setF1(long f1) { if (this.f1 != f1) { this.f1 = f1; - write(COL1); + doWrite(COL1); } } public void setF2(int f2) { if (this.f2 != f2) { this.f2 = f2; - write(COL2); + doWrite(COL2); } } } @@ -145,7 +145,7 @@ public class DBCachedObjectStoreTest { DBCachedObjectStoreEntrySet rEntrySet; protected UndoableTransaction trans() { - return UndoableTransaction.start(myDomainObject, "Test", true); + return UndoableTransaction.start(myDomainObject, "Test"); } protected void populateStore(long... keys) { @@ -270,7 +270,7 @@ public class DBCachedObjectStoreTest { MyObject obj = store.create(); obj.setF1(0x801); obj.setF2(0x802); - obj.updated(); + obj.doUpdated(); Table table = handle.getTable(OBJECTS_TABLE_NAME); DBRecord record = table.getRecord(obj.getKey()); assertEquals(0x801, record.getLongValue(0)); @@ -2622,15 +2622,15 @@ public class DBCachedObjectStoreTest { try (UndoableTransaction tid = trans()) { MyObject obj0 = store.create(0); obj0.setF2(10); - obj0.updated(); + obj0.doUpdated(); MyObject obj1 = store.create(1); obj1.setF2(5); - obj1.updated(); + obj1.doUpdated(); MyObject obj2 = store.create(2); obj2.setF2(5); - obj2.updated(); + obj2.doUpdated(); } DBCachedObjectIndex index = store.getIndex(int.class, COL2_NAME); return index; @@ -2668,7 +2668,7 @@ public class DBCachedObjectStoreTest { @SuppressWarnings("unlikely-arg-type") public void testFoundContains() throws IOException { DBCachedObjectIndex index = populateAndGetIndex(); - DBCachedObjectStoreFoundKeysValueCollection found5 = index.get(5); + Collection found5 = index.get(5); assertFalse(found5.contains(null)); assertFalse(found5.contains("Wrong type")); @@ -2679,7 +2679,7 @@ public class DBCachedObjectStoreTest { @Test public void testFoundIterator() throws IOException { DBCachedObjectIndex index = populateAndGetIndex(); - DBCachedObjectStoreFoundKeysValueCollection found5 = index.get(5); + Collection found5 = index.get(5); assertEquals(Set.of(store.getObjectAt(1), store.getObjectAt(2)), new HashSet<>(IteratorUtils.toList(found5.iterator()))); @@ -2688,7 +2688,7 @@ public class DBCachedObjectStoreTest { @Test public void testFoundToArray() throws IOException { DBCachedObjectIndex index = populateAndGetIndex(); - DBCachedObjectStoreFoundKeysValueCollection found5 = index.get(5); + Collection found5 = index.get(5); assertEquals(Set.of(store.getObjectAt(1), store.getObjectAt(2)), new HashSet<>(Arrays.asList(found5.toArray()))); @@ -2697,7 +2697,7 @@ public class DBCachedObjectStoreTest { @Test public void testFoundToTypedArray() throws IOException { DBCachedObjectIndex index = populateAndGetIndex(); - DBCachedObjectStoreFoundKeysValueCollection found5 = index.get(5); + Collection found5 = index.get(5); assertEquals(Set.of(store.getObjectAt(1), store.getObjectAt(2)), new HashSet<>(Arrays.asList(found5.toArray(new MyObject[0])))); @@ -2712,7 +2712,7 @@ public class DBCachedObjectStoreTest { @Test public void testFoundContainsAll() throws VersionException, IOException { DBCachedObjectIndex index = populateAndGetIndex(); - DBCachedObjectStoreFoundKeysValueCollection found5 = index.get(5); + Collection found5 = index.get(5); assertTrue(found5.containsAll(List.of())); assertFalse(found5.containsAll(List.of(store.getObjectAt(1), "Wrong Type"))); @@ -2722,7 +2722,7 @@ public class DBCachedObjectStoreTest { final MyObject altObj1; MyDomainObject altDomainObject = new MyDomainObject("Alternative Dummy", 500, 1000, this); try (UndoableTransaction tid = - UndoableTransaction.start(altDomainObject, "Create Obj2", true)) { + UndoableTransaction.start(altDomainObject, "Create Obj2")) { altObj1 = altDomainObject.store.create(1); } diff --git a/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/util/database/spatial/RStarTreeMapTest.java b/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/util/database/spatial/RStarTreeMapTest.java index 35f3a37bfb..a67cd90c76 100644 --- a/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/util/database/spatial/RStarTreeMapTest.java +++ b/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/util/database/spatial/RStarTreeMapTest.java @@ -636,7 +636,7 @@ public class RStarTreeMapTest { super(new DBHandle(), DBOpenMode.CREATE, new ConsoleTaskMonitor(), "Testing", 500, 1000, consumer); storeFactory = new DBCachedObjectStoreFactory(this); - try (UndoableTransaction tid = UndoableTransaction.start(this, "CreateMaps", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(this, "CreateMaps")) { tree = new IntRStarTree(storeFactory, DBIntRectStringDataRecord.TABLE_NAME, true, MAX_CHILDREN); map = tree.asSpatialMap(); @@ -858,7 +858,7 @@ public class RStarTreeMapTest { List> entries = generateRandom(rect(0, 100, 0, 100), 10, 10, 125); obj.tree.checkIntegrity(); - try (UndoableTransaction tid = UndoableTransaction.start(obj, "AddRandom", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(obj, "AddRandom")) { for (Entry ent : entries) { obj.map.put(ent.getKey(), ent.getValue()); obj.tree.checkIntegrity(); @@ -874,7 +874,7 @@ public class RStarTreeMapTest { // NOTE: This "thrashing" test covers nearly all the R*-Tree insertion logic. List> entries = generateRandom(rect(0, 100, 0, 100), 10, 10, 1000); Consumer>> inserter = list -> { - try (UndoableTransaction tid = UndoableTransaction.start(obj, "AddRandom", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(obj, "AddRandom")) { int i = 0; for (Entry ent : list) { obj.map.put(ent.getKey(), ent.getValue()); @@ -903,7 +903,7 @@ public class RStarTreeMapTest { @Test public void testIntegrityWith2000VerticallyStackedRects() throws Exception { - try (UndoableTransaction tid = UndoableTransaction.start(obj, "AddVertical", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(obj, "AddVertical")) { for (int i = 0; i < 2000; i++) { obj.map.put(rect(0, 10, i, i + 1), "Ent" + i); // Note, underlying tree is not synchronized, but map is @@ -916,7 +916,7 @@ public class RStarTreeMapTest { @Test public void testSaveAndLoad() throws IOException, CancelledException, VersionException { - try (UndoableTransaction tid = UndoableTransaction.start(obj, "AddRecord", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(obj, "AddRecord")) { obj.map.put(rect(1, 5, 6, 10), "Some value"); } @@ -958,7 +958,7 @@ public class RStarTreeMapTest { // NOTE: This test is made also to cover the visitation logic. assertTrue(obj.map.isEmpty()); - try (UndoableTransaction tid = UndoableTransaction.start(obj, "AddPoints", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(obj, "AddPoints")) { for (Entry ent : generatePoints(rect(1, 12, 1, 12))) { obj.map.put(ent.getKey(), ent.getValue()); } @@ -977,7 +977,7 @@ public class RStarTreeMapTest { @Test public void testFirst() { - try (UndoableTransaction tid = UndoableTransaction.start(obj, "AddPoints", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(obj, "AddPoints")) { for (Entry ent : generatePoints(rect(1, 12, 1, 12))) { obj.map.put(ent.getKey(), ent.getValue()); } @@ -1015,7 +1015,7 @@ public class RStarTreeMapTest { @Test public void testIterator() { List> points = generatePoints(rect(1, 12, 1, 12)); - try (UndoableTransaction tid = UndoableTransaction.start(obj, "AddPoints", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(obj, "AddPoints")) { for (Entry ent : points) { obj.map.put(ent.getKey(), ent.getValue()); } @@ -1045,7 +1045,7 @@ public class RStarTreeMapTest { @Test public void testOrderedIterator() { List> points = generatePoints(rect(1, 12, 1, 12)); - try (UndoableTransaction tid = UndoableTransaction.start(obj, "AddPoints", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(obj, "AddPoints")) { for (Entry ent : points) { obj.map.put(ent.getKey(), ent.getValue()); } @@ -1073,13 +1073,13 @@ public class RStarTreeMapTest { public void testRemove() { // TODO: Add a "minimal query including" abstract method to reduce search for removed item List> points = generatePoints(rect(1, 12, 1, 12)); - try (UndoableTransaction tid = UndoableTransaction.start(obj, "AddPoints", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(obj, "AddPoints")) { for (Entry ent : points) { obj.map.put(ent.getKey(), ent.getValue()); } } - try (UndoableTransaction tid = UndoableTransaction.start(obj, "RemovePoints", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(obj, "RemovePoints")) { assertFalse(obj.map.reduce(IntRectQuery.enclosed(rect(6, 6, 6, 6))).isEmpty()); obj.map.remove(rect(6, 6, 6, 6), "NotHere"); assertFalse(obj.map.reduce(IntRectQuery.enclosed(rect(6, 6, 6, 6))).isEmpty()); @@ -1099,13 +1099,13 @@ public class RStarTreeMapTest { @Test public void testClear() { List> points = generatePoints(rect(1, 12, 1, 12)); - try (UndoableTransaction tid = UndoableTransaction.start(obj, "AddPoints", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(obj, "AddPoints")) { for (Entry ent : points) { obj.map.put(ent.getKey(), ent.getValue()); } } - try (UndoableTransaction tid = UndoableTransaction.start(obj, "RemovePoints", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(obj, "RemovePoints")) { obj.map.reduce(IntRectQuery.enclosed(rect(6, 6, 6, 6))).clear(); obj.tree.checkIntegrity(); assertEquals(143, obj.map.size()); @@ -1135,7 +1135,7 @@ public class RStarTreeMapTest { @Test public void testValuesToArray() { List> points = generatePoints(rect(1, 12, 1, 12)); - try (UndoableTransaction tid = UndoableTransaction.start(obj, "AddPoints", true)) { + try (UndoableTransaction tid = UndoableTransaction.start(obj, "AddPoints")) { for (Entry ent : points) { obj.map.put(ent.getKey(), ent.getValue()); }