";
}
/**
- * Get the shift from the source address set to this address set
+ * Get the shift from the source address range to this address range
*
*
- * The meaning depends on what returned this view. If this view is the "static" set, then
+ * The meaning depends on what returned this view. If this view is the "static" range, then
* this shift describes what was added to the offset of the "dynamic" address to get a
- * particular address in this set. Note that since not all addresses from the requested
- * source set may have been mapped, you cannot simply compare min addresses to obtain this
- * shift. To "map back" to the source address from a destination address in this set,
- * subtract this shift.
+ * particular address in the "static" range.
*
* @return the shift
*/
@@ -516,12 +527,107 @@ public interface DebuggerStaticMappingService {
}
/**
- * Get the destination address set view as mapped from the source address set
+ * Map an address in the source range to the corresponding address in the destination range
*
- * @return the address set
+ * @param saddr the source address (not validated)
+ * @return the destination address
*/
- public AddressSetView getAddressSetView() {
- return view;
+ public Address mapSourceToDestination(Address saddr) {
+ return dstRange.getAddressSpace().getAddress(saddr.getOffset() + shift);
+ }
+
+ /**
+ * Map an address in the destination range to the corresponding address in the source range
+ *
+ * @param daddr the destination address (not validated)
+ * @return the source address
+ */
+ public Address mapDestinationToSource(Address daddr) {
+ return srcRange.getAddressSpace().getAddress(daddr.getOffset() - shift);
+ }
+
+ /**
+ * Map a sub-range of the source to the corresponding sub-range of the destination
+ *
+ * @param srng the source sub-range
+ * @return the destination sub-range
+ */
+ public AddressRange mapSourceToDestination(AddressRange srng) {
+ try {
+ return new AddressRangeImpl(mapSourceToDestination(srng.getMinAddress()),
+ srng.getLength());
+ }
+ catch (AddressOverflowException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ /**
+ * Map a sub-range of the destination to the corresponding sub-range of the source
+ *
+ * @param drng the destination sub-range
+ * @return the source sub-range
+ */
+ public AddressRange mapDestinationToSource(AddressRange drng) {
+ try {
+ return new AddressRangeImpl(mapDestinationToSource(drng.getMinAddress()),
+ drng.getLength());
+ }
+ catch (AddressOverflowException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ /**
+ * Get the source address range
+ *
+ * @return the address range
+ */
+ public AddressRange getSourceAddressRange() {
+ return srcRange;
+ }
+
+ /**
+ * Get the destination address range
+ *
+ * @return the address range
+ */
+ public AddressRange getDestinationAddressRange() {
+ return dstRange;
+ }
+
+ @Override
+ public int compareTo(MappedAddressRange that) {
+ int c;
+ c = this.dstRange.compareTo(that.dstRange);
+ if (c != 0) {
+ return c;
+ }
+ c = this.srcRange.compareTo(that.srcRange);
+ if (c != 0) {
+ return c;
+ }
+ return 0;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof MappedAddressRange)) {
+ return false;
+ }
+ MappedAddressRange that = (MappedAddressRange) obj;
+ if (!this.dstRange.equals(that.dstRange)) {
+ return false;
+ }
+ if (!this.srcRange.equals(that.srcRange)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return hashCode;
}
}
@@ -570,8 +676,7 @@ public interface DebuggerStaticMappingService {
boolean truncateExisting) throws TraceConflictedMappingException;
/**
- * ======= >>>>>>> d694542c5 (GP-660: Put program filler back in. Need to performance test.) Add
- * several static mappings (relocations)
+ * Add several static mappings (relocations)
*
*
* This will group the entries by trace and add each's entries in a single transaction. If any
@@ -669,9 +774,9 @@ public interface DebuggerStaticMappingService {
* @param trace the source trace
* @param set the source address set
* @param snap the source snap
- * @return a map of destination programs to corresponding computed destination address sets
+ * @return a map of destination programs to corresponding computed destination address ranges
*/
- Map getOpenMappedViews(Trace trace,
+ Map> getOpenMappedViews(Trace trace,
AddressSetView set, long snap);
/**
@@ -679,9 +784,9 @@ public interface DebuggerStaticMappingService {
*
* @param program the destination program, from which we are mapping back
* @param set the destination address set, from which we are mapping back
- * @return a map of source traces to corresponding computed source address sets
+ * @return a map of source traces to corresponding computed source address ranges
*/
- Map getOpenMappedViews(Program program,
+ Map> getOpenMappedViews(Program program,
AddressSetView set);
/**
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
new file mode 100644
index 0000000000..da6c33a62d
--- /dev/null
+++ b/Ghidra/Debug/Debugger/src/screen/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyActionsPluginScreenShots.java
@@ -0,0 +1,157 @@
+/* ###
+ * IP: GHIDRA
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package ghidra.app.plugin.core.debug.gui.copying;
+
+import java.util.Set;
+
+import org.junit.*;
+
+import com.google.common.collect.Range;
+
+import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest.TestDebuggerTargetTraceMapper;
+import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingPlugin;
+import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingProvider;
+import ghidra.app.plugin.core.debug.service.model.DebuggerModelServicePlugin;
+import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingServicePlugin;
+import ghidra.app.plugin.core.debug.service.tracemgr.DebuggerTraceManagerServicePlugin;
+import ghidra.app.plugin.core.progmgr.ProgramManagerPlugin;
+import ghidra.app.services.*;
+import ghidra.dbg.model.TestDebuggerModelBuilder;
+import ghidra.framework.model.DomainFolder;
+import ghidra.program.model.address.AddressSpace;
+import ghidra.program.model.mem.Memory;
+import ghidra.program.util.ProgramLocation;
+import ghidra.program.util.ProgramSelection;
+import ghidra.trace.database.ToyDBTraceBuilder;
+import ghidra.trace.database.memory.DBTraceMemoryManager;
+import ghidra.trace.database.module.DBTraceModuleManager;
+import ghidra.trace.model.DefaultTraceLocation;
+import ghidra.trace.model.memory.TraceMemoryFlag;
+import ghidra.trace.model.modules.TraceModule;
+import ghidra.util.database.UndoableTransaction;
+import ghidra.util.task.TaskMonitor;
+import help.screenshot.GhidraScreenShotGenerator;
+
+public class DebuggerCopyActionsPluginScreenShots extends GhidraScreenShotGenerator {
+
+ ProgramManager programManager;
+ DebuggerTraceManagerService traceManager;
+ DebuggerModelService modelService;
+ DebuggerStaticMappingServicePlugin mappingService;
+ DebuggerListingPlugin listingPlugin;
+ DebuggerListingProvider listingProvider;
+ DebuggerCopyActionsPlugin copyPlugin;
+ TestDebuggerModelBuilder mb;
+ ToyDBTraceBuilder tb;
+
+ @Before
+ public void setUpMine() throws Throwable {
+ programManager = addPlugin(tool, ProgramManagerPlugin.class);
+ traceManager = addPlugin(tool, DebuggerTraceManagerServicePlugin.class);
+ modelService = addPlugin(tool, DebuggerModelServicePlugin.class);
+ mappingService = addPlugin(tool, DebuggerStaticMappingServicePlugin.class);
+ listingPlugin = addPlugin(tool, DebuggerListingPlugin.class);
+ copyPlugin = addPlugin(tool, DebuggerCopyActionsPlugin.class);
+
+ listingProvider = waitForComponentProvider(DebuggerListingProvider.class);
+
+ mb = new TestDebuggerModelBuilder();
+ mb.createTestModel();
+ mb.createTestProcessesAndThreads();
+ TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
+ new TestDebuggerTargetTraceMapper(mb.testProcess1));
+ tb = new ToyDBTraceBuilder(recorder.getTrace());
+ }
+
+ @After
+ public void tearDownMine() {
+ tb.close();
+
+ if (program != null) {
+ program.release(this);
+ }
+ }
+
+ @Test
+ public void testCaptureDebuggerCopyIntoProgramDialog() throws Throwable {
+ long snap;
+ try (UndoableTransaction tid = tb.startTransaction()) {
+ snap = tb.trace.getTimeManager().createSnapshot("First").getKey();
+ DBTraceMemoryManager mem = tb.trace.getMemoryManager();
+ mem.createRegion(".text", snap, tb.range(0x55550000, 0x5555ffff),
+ Set.of(TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE));
+ mem.createRegion(".data", snap, tb.range(0x55560000, 0x5556ffff),
+ Set.of(TraceMemoryFlag.READ, TraceMemoryFlag.WRITE));
+ mem.createRegion("[stack]", snap, tb.range(0x00100000, 0x001fffff),
+ Set.of(TraceMemoryFlag.READ, TraceMemoryFlag.WRITE));
+
+ DBTraceModuleManager mods = tb.trace.getModuleManager();
+
+ TraceModule modEcho = mods.addLoadedModule("Modules[/bin/echo]", "/bin/echo",
+ tb.range(0x55550000, 0x5556ffff), snap);
+ modEcho.addSection("Modules[/bin/echo].Sections[.text]", ".text",
+ tb.range(0x55550000, 0x5555ffff));
+ modEcho.addSection("Modules[/bin/echo].Sections[.data]", ".data",
+ tb.range(0x55560000, 0x5556ffff));
+ }
+
+ program = createDefaultProgram("echo", "Toy:BE:64:default", this);
+ AddressSpace stSpace = program.getAddressFactory().getDefaultAddressSpace();
+
+ try (UndoableTransaction tid = UndoableTransaction.start(program, "Add memory", true)) {
+ program.setImageBase(tb.addr(stSpace, 0x00400000), true);
+ Memory memory = program.getMemory();
+ memory.createInitializedBlock(".text", tb.addr(stSpace, 0x00400000), 0x10000, (byte) 0,
+ TaskMonitor.DUMMY, false);
+ memory.createInitializedBlock(".data", tb.addr(stSpace, 0x00600000), 0x10000, (byte) 0,
+ TaskMonitor.DUMMY, false);
+ }
+
+ DomainFolder root = tool.getProject().getProjectData().getRootFolder();
+ root.createFile(tb.trace.getName(), tb.trace, TaskMonitor.DUMMY);
+ root.createFile(program.getName(), program, TaskMonitor.DUMMY);
+
+ try (UndoableTransaction tid = tb.startTransaction()) {
+ mappingService.addMapping(
+ new DefaultTraceLocation(tb.trace, null, Range.atLeast(snap), tb.addr(0x55550000)),
+ new ProgramLocation(program, tb.addr(stSpace, 0x00400000)), 0x10000, true);
+ mappingService.addMapping(
+ new DefaultTraceLocation(tb.trace, null, Range.atLeast(snap), tb.addr(0x55560000)),
+ new ProgramLocation(program, tb.addr(stSpace, 0x00600000)), 0x10000, true);
+ }
+
+ traceManager.openTrace(tb.trace);
+ traceManager.activateTrace(tb.trace);
+
+ programManager.openProgram(program);
+
+ listingProvider.requestFocus();
+ waitForSwing();
+
+ listingProvider.setSelection(
+ new ProgramSelection(tb.trace.getMemoryManager().getRegionsAddressSet(snap)));
+
+ waitForCondition(() -> copyPlugin.actionCopyIntoCurrentProgram.isEnabled());
+ performAction(copyPlugin.actionCopyIntoCurrentProgram, false);
+ DebuggerCopyIntoProgramDialog dialog =
+ waitForDialogComponent(DebuggerCopyIntoProgramDialog.class);
+ dialog.setRelocate(true);
+ dialog.reset();
+ waitForSwing();
+
+ captureDialog(DebuggerCopyIntoProgramDialog.class, 700, 600);
+ }
+}
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
new file mode 100644
index 0000000000..8b532e3c18
--- /dev/null
+++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyActionsPluginTest.java
@@ -0,0 +1,505 @@
+/* ###
+ * IP: GHIDRA
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package ghidra.app.plugin.core.debug.gui.copying;
+
+import static org.junit.Assert.*;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.collect.Range;
+
+import generic.Unique;
+import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest;
+import ghidra.app.plugin.core.debug.gui.action.AutoReadMemorySpec;
+import ghidra.app.plugin.core.debug.gui.action.NoneAutoReadMemorySpec;
+import ghidra.app.plugin.core.debug.gui.copying.DebuggerCopyIntoProgramDialog.RangeEntry;
+import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingPlugin;
+import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingProvider;
+import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingServicePlugin;
+import ghidra.app.services.DebuggerStaticMappingService;
+import ghidra.app.services.TraceRecorder;
+import ghidra.dbg.DebuggerModelListener;
+import ghidra.dbg.target.TargetObject;
+import ghidra.program.model.address.Address;
+import ghidra.program.model.address.AddressSpace;
+import ghidra.program.model.listing.Program;
+import ghidra.program.model.mem.MemoryBlock;
+import ghidra.program.util.ProgramLocation;
+import ghidra.program.util.ProgramSelection;
+import ghidra.test.ToyProgramBuilder;
+import ghidra.trace.database.memory.DBTraceMemoryManager;
+import ghidra.trace.model.DefaultTraceLocation;
+import ghidra.trace.model.TraceLocation;
+import ghidra.trace.model.memory.TraceMemoryFlag;
+import ghidra.util.database.UndoableTransaction;
+
+public class DebuggerCopyActionsPluginTest extends AbstractGhidraHeadedDebuggerGUITest {
+
+ DebuggerCopyActionsPlugin copyActionsPlugin;
+ DebuggerListingPlugin listingPlugin;
+ DebuggerStaticMappingService mappingService;
+
+ DebuggerListingProvider listingProvider;
+
+ @Before
+ public void setupCopyActionsPluginTest() throws Exception {
+ mappingService = addPlugin(tool, DebuggerStaticMappingServicePlugin.class);
+ copyActionsPlugin = addPlugin(tool, DebuggerCopyActionsPlugin.class);
+ listingPlugin = addPlugin(tool, DebuggerListingPlugin.class);
+
+ listingProvider = waitForComponentProvider(DebuggerListingProvider.class);
+ }
+
+ @Test
+ public void testActionCopyIntoCurrentProgramWithoutRelocationCreateBlocks() throws Exception {
+ assertFalse(copyActionsPlugin.actionCopyIntoCurrentProgram.isEnabled());
+
+ createProgram();
+ AddressSpace stSpace = program.getAddressFactory().getDefaultAddressSpace();
+ programManager.openProgram(program);
+ assertFalse(copyActionsPlugin.actionCopyIntoCurrentProgram.isEnabled());
+
+ createAndOpenTrace();
+ try (UndoableTransaction tid = tb.startTransaction()) {
+ tb.trace.getMemoryManager()
+ .createRegion(".text", 0, tb.range(0x00400000, 0x0040ffff),
+ TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
+ }
+ traceManager.activateTrace(tb.trace);
+ assertFalse(copyActionsPlugin.actionCopyIntoCurrentProgram.isEnabled());
+
+ listingProvider.requestFocus();
+ listingProvider
+ .setSelection(new ProgramSelection(tb.addr(0x00400000), tb.addr(0x0040ffff)));
+
+ waitForPass(() -> assertTrue(copyActionsPlugin.actionCopyIntoCurrentProgram.isEnabled()));
+ performAction(copyActionsPlugin.actionCopyIntoCurrentProgram, false);
+ DebuggerCopyIntoProgramDialog dialog =
+ waitForDialogComponent(DebuggerCopyIntoProgramDialog.class);
+ dialog.setRelocate(false);
+ dialog.reset();
+
+ RangeEntry entry = Unique.assertOne(dialog.tableModel.getModelData());
+
+ assertEquals(tb.range(stSpace, 0x00400000, 0x0040ffff), entry.getSrcRange());
+ assertEquals(tb.range(stSpace, 0x00400000, 0x0040ffff), entry.getDstRange());
+ assertEquals(".text", entry.getRegionName());
+ assertEquals(".text", entry.getBlockName());
+ assertTrue(entry.isCreate());
+ dialog.okCallback();
+ dialog.lastTask.get(1000, TimeUnit.MILLISECONDS);
+ waitForSwing();
+
+ MemoryBlock text = Unique.assertOne(Arrays.asList(program.getMemory().getBlocks()));
+ assertEquals(".text", text.getName());
+ }
+
+ @Test
+ public void testActionCopyIntoCurrentProgramWithoutRelocationCrossLanguage() throws Exception {
+ assertFalse(copyActionsPlugin.actionCopyIntoCurrentProgram.isEnabled());
+
+ createProgram(getSLEIGH_X86_LANGUAGE());
+ createAndOpenTrace(ToyProgramBuilder._X64);
+ assertFalse(copyActionsPlugin.actionCopyIntoCurrentProgram.isEnabled());
+
+ AddressSpace stSpace = program.getAddressFactory().getDefaultAddressSpace();
+
+ try (UndoableTransaction tid = UndoableTransaction.start(program, "Add blocks", true)) {
+ program.getMemory()
+ .createInitializedBlock(".text", tb.addr(stSpace, 0x00400000), 0x8000,
+ (byte) 0, monitor, false);
+ program.getMemory()
+ .createInitializedBlock(".text2", tb.addr(stSpace, 0x00408000), 0x8000,
+ (byte) 0, monitor, false);
+ }
+
+ try (UndoableTransaction tid = tb.startTransaction()) {
+ DBTraceMemoryManager mm = tb.trace.getMemoryManager();
+ mm.createRegion(".text", 0, tb.range(0x00400000, 0x0040ffff),
+ TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
+ mm.putBytes(0, tb.addr(0x00401234), tb.buf(1, 2, 3, 4));
+
+ // This region should be excluded, since it cannot be mapped identically into 32-bits
+ mm.createRegion("lib:.text", 0, tb.range(0x7fff00400000L, 0x7fff0040ffffL),
+ TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
+
+ // This region should be partially excluded, because 32-bits
+ // This is not likely to ever happen in practice, but be prepared
+ mm.createRegion(".straddle", 0, tb.range(0xfffff000L, 0x100000fffL),
+ TraceMemoryFlag.READ, TraceMemoryFlag.WRITE);
+ }
+
+ programManager.openProgram(program);
+ traceManager.activateTrace(tb.trace);
+ assertFalse(copyActionsPlugin.actionCopyIntoCurrentProgram.isEnabled());
+
+ listingProvider.requestFocus();
+ listingProvider.setSelection(new ProgramSelection(tb.set(
+ tb.range(0x00400000, 0x0040ffff),
+ tb.range(0x7fff00400000L, 0x7fff0040ffffL),
+ tb.range(0xfffff000L, 0x100000fffL))));
+
+ waitForPass(() -> assertTrue(copyActionsPlugin.actionCopyIntoCurrentProgram.isEnabled()));
+ performAction(copyActionsPlugin.actionCopyIntoCurrentProgram, false);
+ DebuggerCopyIntoProgramDialog dialog =
+ waitForDialogComponent(DebuggerCopyIntoProgramDialog.class);
+ dialog.setRelocate(false);
+ dialog.reset();
+
+ List entries = List.copyOf(dialog.tableModel.getModelData());
+ assertEquals(3, entries.size());
+ RangeEntry entry;
+
+ entry = entries.get(0);
+ assertEquals(tb.range(0x00400000, 0x00407fff), entry.getSrcRange());
+ assertEquals(tb.range(stSpace, 0x00400000, 0x00407fff), entry.getDstRange());
+ assertEquals(".text", entry.getRegionName());
+ assertEquals(".text *", entry.getBlockName());
+ assertFalse(entry.isCreate());
+
+ entry = entries.get(1);
+ assertEquals(tb.range(0x00408000, 0x0040ffff), entry.getSrcRange());
+ assertEquals(tb.range(stSpace, 0x00408000, 0x0040ffff), entry.getDstRange());
+ assertEquals(".text", entry.getRegionName());
+ assertEquals(".text2 *", entry.getBlockName());
+ assertFalse(entry.isCreate());
+
+ entry = entries.get(2);
+ assertEquals(tb.range(0xfffff000L, 0xffffffffL), entry.getSrcRange());
+ assertEquals(tb.range(stSpace, 0xfffff000L, 0xffffffffL), entry.getDstRange());
+ assertEquals(".straddle", entry.getRegionName());
+ assertEquals(".straddle", entry.getBlockName());
+ assertTrue(entry.isCreate());
+
+ dialog.okCallback();
+ dialog.lastTask.get(1000, TimeUnit.MILLISECONDS);
+ waitForSwing();
+
+ byte[] dest = new byte[4];
+ program.getMemory().getBytes(tb.addr(stSpace, 0x00401234), dest);
+ assertArrayEquals(tb.arr(1, 2, 3, 4), dest);
+ }
+
+ @Test
+ public void testActionCopyIntoCurrentProgramWithRelocationExistingBlocks() throws Exception {
+ assertFalse(copyActionsPlugin.actionCopyIntoCurrentProgram.isEnabled());
+
+ createAndOpenTrace();
+ createProgramFromTrace();
+ intoProject(program);
+ intoProject(tb.trace);
+
+ try (UndoableTransaction tid = tb.startTransaction()) {
+ tb.trace.getMemoryManager()
+ .createRegion(".text", 0, tb.range(0x55550000, 0x5555ffff),
+ TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
+ }
+ traceManager.activateTrace(tb.trace);
+ assertFalse(copyActionsPlugin.actionCopyIntoCurrentProgram.isEnabled());
+
+ programManager.openProgram(program);
+ assertFalse(copyActionsPlugin.actionCopyIntoCurrentProgram.isEnabled());
+
+ AddressSpace stSpace = program.getAddressFactory().getDefaultAddressSpace();
+ MemoryBlock block;
+ try (UndoableTransaction tid = UndoableTransaction.start(program, "Create block", true)) {
+ block = program.getMemory()
+ .createUninitializedBlock(".text", tb.addr(stSpace, 0x00400000), 0x10000,
+ false);
+ }
+
+ TraceLocation tloc =
+ new DefaultTraceLocation(tb.trace, null, Range.atLeast(0L), tb.addr(0x55550000));
+ ProgramLocation ploc = new ProgramLocation(program, tb.addr(stSpace, 0x00400000));
+ try (UndoableTransaction tid = tb.startTransaction()) {
+ mappingService.addMapping(tloc, ploc, 0x10000, true);
+ }
+
+ waitForValue(() -> mappingService
+ .getOpenMappedViews(tb.trace, tb.set(tb.range(0x55550000, 0x5555ffff)), 0)
+ .get(program));
+
+ listingProvider.requestFocus();
+ listingProvider
+ .setSelection(new ProgramSelection(tb.addr(0x55550000), tb.addr(0x5555ffff)));
+
+ waitForPass(() -> assertTrue(copyActionsPlugin.actionCopyIntoCurrentProgram.isEnabled()));
+ performAction(copyActionsPlugin.actionCopyIntoCurrentProgram, false);
+ DebuggerCopyIntoProgramDialog dialog =
+ waitForDialogComponent(DebuggerCopyIntoProgramDialog.class);
+ dialog.setRelocate(true);
+ dialog.reset();
+
+ RangeEntry entry = Unique.assertOne(dialog.tableModel.getModelData());
+
+ assertEquals(tb.range(stSpace, 0x55550000, 0x5555ffff), entry.getSrcRange());
+ assertEquals(tb.range(stSpace, 0x00400000, 0x0040ffff), entry.getDstRange());
+ assertEquals(".text", entry.getRegionName());
+ assertEquals(".text *", entry.getBlockName());
+ assertFalse(entry.isCreate());
+ dialog.okCallback();
+ dialog.lastTask.get(1000, TimeUnit.MILLISECONDS);
+ waitForSwing();
+
+ MemoryBlock text = Unique.assertOne(Arrays.asList(program.getMemory().getBlocks()));
+ assertEquals(block, text);
+ }
+
+ @Test
+ public void testActionCopyIntoCurrentProgramWithRelocationOverlayBlocks() throws Exception {
+ assertFalse(copyActionsPlugin.actionCopyIntoCurrentProgram.isEnabled());
+
+ createAndOpenTrace();
+ createProgramFromTrace();
+ intoProject(program);
+ intoProject(tb.trace);
+
+ try (UndoableTransaction tid = tb.startTransaction()) {
+ tb.trace.getMemoryManager()
+ .createRegion(".text", 0, tb.range(0x55550000, 0x5555ffff),
+ TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
+ }
+ traceManager.activateTrace(tb.trace);
+ assertFalse(copyActionsPlugin.actionCopyIntoCurrentProgram.isEnabled());
+
+ programManager.openProgram(program);
+ assertFalse(copyActionsPlugin.actionCopyIntoCurrentProgram.isEnabled());
+
+ AddressSpace stSpace = program.getAddressFactory().getDefaultAddressSpace();
+ MemoryBlock block;
+ try (UndoableTransaction tid = UndoableTransaction.start(program, "Create block", true)) {
+ block = program.getMemory()
+ .createUninitializedBlock(".text", tb.addr(stSpace, 0x00400000), 0x10000,
+ false);
+ }
+
+ TraceLocation tloc =
+ new DefaultTraceLocation(tb.trace, null, Range.atLeast(0L), tb.addr(0x55550000));
+ ProgramLocation ploc = new ProgramLocation(program, tb.addr(stSpace, 0x00400000));
+ try (UndoableTransaction tid = tb.startTransaction()) {
+ mappingService.addMapping(tloc, ploc, 0x10000, true);
+ }
+
+ waitForValue(() -> mappingService
+ .getOpenMappedViews(tb.trace, tb.set(tb.range(0x55550000, 0x5555ffff)), 0)
+ .get(program));
+
+ listingProvider.requestFocus();
+ listingProvider
+ .setSelection(new ProgramSelection(tb.addr(0x55550000), tb.addr(0x5555ffff)));
+
+ waitForPass(() -> assertTrue(copyActionsPlugin.actionCopyIntoCurrentProgram.isEnabled()));
+ performAction(copyActionsPlugin.actionCopyIntoCurrentProgram, false);
+ DebuggerCopyIntoProgramDialog dialog =
+ waitForDialogComponent(DebuggerCopyIntoProgramDialog.class);
+ dialog.setRelocate(true);
+ dialog.setUseOverlays(true);
+ dialog.reset();
+
+ RangeEntry entry = Unique.assertOne(dialog.tableModel.getModelData());
+
+ assertEquals(tb.range(stSpace, 0x55550000, 0x5555ffff), entry.getSrcRange());
+ assertEquals(tb.range(stSpace, 0x00400000, 0x0040ffff), entry.getDstRange());
+ assertEquals(".text", entry.getRegionName());
+ assertEquals(".text_2", entry.getBlockName());
+ assertTrue(entry.isCreate());
+ dialog.okCallback();
+ dialog.lastTask.get(1000, TimeUnit.MILLISECONDS);
+ waitForSwing();
+
+ MemoryBlock text2 =
+ Unique.assertOne(Arrays.asList(program.getMemory().getBlock(".text_2")));
+ assertNotEquals(block, text2);
+ assertTrue(text2.isOverlay());
+ }
+
+ @Test
+ public void testActionCopyIntoNewProgram() throws Exception {
+ assertFalse(copyActionsPlugin.actionCopyIntoNewProgram.isEnabled());
+
+ createAndOpenTrace();
+
+ try (UndoableTransaction tid = tb.startTransaction()) {
+ tb.trace.getMemoryManager()
+ .createRegion(".text", 0, tb.range(0x55550000, 0x5555ffff),
+ TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
+ }
+ traceManager.activateTrace(tb.trace);
+ assertFalse(copyActionsPlugin.actionCopyIntoNewProgram.isEnabled());
+
+ listingProvider.requestFocus();
+ listingProvider
+ .setSelection(new ProgramSelection(tb.addr(0x55550000), tb.addr(0x5555ffff)));
+
+ waitForPass(() -> assertTrue(copyActionsPlugin.actionCopyIntoNewProgram.isEnabled()));
+ performAction(copyActionsPlugin.actionCopyIntoNewProgram, false);
+ DebuggerCopyIntoProgramDialog dialog =
+ waitForDialogComponent(DebuggerCopyIntoProgramDialog.class);
+ dialog.setDestination(DebuggerCopyIntoProgramDialog.TEMP_PROGRAM);
+
+ RangeEntry entry = Unique.assertOne(dialog.tableModel.getModelData());
+
+ assertEquals(tb.range(0x55550000, 0x5555ffff), entry.getSrcRange());
+ assertEquals(tb.range(0x55550000, 0x5555ffff), entry.getDstRange());
+ assertEquals(".text", entry.getRegionName());
+ assertEquals(".text", entry.getBlockName());
+ assertTrue(entry.isCreate());
+ entry.setBlockName(".my_text");
+ dialog.okCallback();
+ dialog.lastTask.get(1000, TimeUnit.MILLISECONDS);
+ waitForSwing();
+
+ // Declare my own, or the @After will try to release it erroneously
+ Program program = waitForValue(() -> programManager.getCurrentProgram());
+ AddressSpace stSpace = program.getAddressFactory().getDefaultAddressSpace();
+
+ MemoryBlock text = Unique.assertOne(Arrays.asList(program.getMemory().getBlocks()));
+ assertEquals(tb.addr(stSpace, 0x55550000), text.getStart());
+ assertEquals(".my_text", text.getName());
+ }
+
+ @Test
+ public void testActionCopyIntoNewProgramAdjacentRegions() throws Exception {
+ assertFalse(copyActionsPlugin.actionCopyIntoNewProgram.isEnabled());
+
+ createAndOpenTrace();
+
+ try (UndoableTransaction tid = tb.startTransaction()) {
+ tb.trace.getMemoryManager()
+ .createRegion(".text", 0, tb.range(0x55550000, 0x5555ffff),
+ TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
+ tb.trace.getMemoryManager()
+ .createRegion(".data", 0, tb.range(0x55560000, 0x5556ffff),
+ TraceMemoryFlag.READ, TraceMemoryFlag.WRITE);
+ }
+ traceManager.activateTrace(tb.trace);
+ assertFalse(copyActionsPlugin.actionCopyIntoNewProgram.isEnabled());
+
+ listingProvider.requestFocus();
+ listingProvider
+ .setSelection(new ProgramSelection(tb.addr(0x55550000), tb.addr(0x5556ffff)));
+
+ waitForPass(() -> assertTrue(copyActionsPlugin.actionCopyIntoNewProgram.isEnabled()));
+ performAction(copyActionsPlugin.actionCopyIntoNewProgram, false);
+ DebuggerCopyIntoProgramDialog dialog =
+ waitForDialogComponent(DebuggerCopyIntoProgramDialog.class);
+ assertFalse(dialog.cbCapture.isEnabled());
+ assertFalse(dialog.cbCapture.isSelected());
+ dialog.setDestination(DebuggerCopyIntoProgramDialog.TEMP_PROGRAM);
+
+ assertEquals(2, dialog.tableModel.getRowCount());
+ RangeEntry entry;
+
+ entry = dialog.tableModel.getRowObject(0);
+ assertEquals(tb.range(0x55550000, 0x5555ffff), entry.getSrcRange());
+ assertEquals(tb.range(0x55550000, 0x5555ffff), entry.getDstRange());
+ assertEquals(".text", entry.getRegionName());
+ assertEquals(".text", entry.getBlockName());
+ assertTrue(entry.isCreate());
+
+ entry = dialog.tableModel.getRowObject(1);
+ assertEquals(tb.range(0x55560000, 0x5556ffff), entry.getSrcRange());
+ assertEquals(tb.range(0x55560000, 0x5556ffff), entry.getDstRange());
+ assertEquals(".data", entry.getRegionName());
+ assertEquals(".data", entry.getBlockName());
+ assertTrue(entry.isCreate());
+
+ dialog.okCallback();
+ dialog.lastTask.get(1000, TimeUnit.MILLISECONDS);
+ waitForSwing();
+
+ // Declare my own, or the @After will try to release it erroneously
+ Program program = waitForValue(() -> programManager.getCurrentProgram());
+ assertEquals(2, program.getMemory().getBlocks().length);
+ }
+
+ @Test
+ public void testActionCopyIntoNewProgramCaptureLive() throws Exception {
+ assertFalse(copyActionsPlugin.actionCopyIntoNewProgram.isEnabled());
+
+ createTestModel();
+
+ var listener = new DebuggerModelListener() {
+ int count = 0;
+
+ @Override
+ public void memoryUpdated(TargetObject memory, Address address, byte[] data) {
+ count++;
+ }
+ };
+ mb.testModel.addModelListener(listener);
+
+ mb.createTestProcessesAndThreads();
+ TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
+ new TestDebuggerTargetTraceMapper(mb.testProcess1));
+ useTrace(recorder.getTrace());
+ mb.testProcess1.memory.addRegion(".text", mb.rng(0x55550000, 0x5555ffff), "rx");
+ mb.testProcess1.memory.setMemory(mb.addr(0x55550000), mb.arr(1, 2, 3, 4, 5, 6, 7, 8));
+ waitForPass(() -> {
+ assertEquals(1, tb.trace.getMemoryManager().getAllRegions().size());
+ });
+
+ listingProvider.setAutoReadMemorySpec(
+ AutoReadMemorySpec.fromConfigName(NoneAutoReadMemorySpec.CONFIG_NAME));
+
+ traceManager.openTrace(tb.trace);
+ traceManager.activateTrace(tb.trace);
+ assertFalse(copyActionsPlugin.actionCopyIntoNewProgram.isEnabled());
+
+ listingProvider.requestFocus();
+ listingProvider
+ .setSelection(new ProgramSelection(tb.addr(0x55550000), tb.addr(0x5555ffff)));
+
+ waitForPass(() -> assertTrue(copyActionsPlugin.actionCopyIntoNewProgram.isEnabled()));
+ performAction(copyActionsPlugin.actionCopyIntoNewProgram, false);
+ DebuggerCopyIntoProgramDialog dialog =
+ waitForDialogComponent(DebuggerCopyIntoProgramDialog.class);
+ assertTrue(dialog.cbCapture.isEnabled());
+ assertTrue(dialog.cbCapture.isSelected());
+ dialog.setDestination(DebuggerCopyIntoProgramDialog.TEMP_PROGRAM);
+
+ RangeEntry entry = Unique.assertOne(dialog.tableModel.getModelData());
+
+ assertEquals(tb.range(0x55550000, 0x5555ffff), entry.getSrcRange());
+ assertEquals(tb.range(0x55550000, 0x5555ffff), entry.getDstRange());
+ assertEquals("[.text]", entry.getRegionName());
+ assertEquals("[.text]", entry.getBlockName());
+ assertTrue(entry.isCreate());
+ entry.setBlockName(".my_text");
+
+ assertEquals(0, listener.count);
+ dialog.okCallback();
+ dialog.lastTask.get(10000, TimeUnit.MILLISECONDS);
+ waitForSwing();
+ assertEquals(16, listener.count);
+
+ // Declare my own, or the @After will try to release it erroneously
+ Program program = waitForValue(() -> programManager.getCurrentProgram());
+ AddressSpace stSpace = program.getAddressFactory().getDefaultAddressSpace();
+
+ MemoryBlock text = Unique.assertOne(Arrays.asList(program.getMemory().getBlocks()));
+ assertEquals(tb.addr(stSpace, 0x55550000), text.getStart());
+ assertEquals(".my_text", text.getName());
+ byte[] arr = new byte[8];
+ text.getBytes(tb.addr(stSpace, 0x55550000), arr);
+ assertArrayEquals(tb.arr(1, 2, 3, 4, 5, 6, 7, 8), arr);
+ }
+}
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
new file mode 100644
index 0000000000..c2b21ee2ce
--- /dev/null
+++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/copying/DebuggerCopyPlanTests.java
@@ -0,0 +1,743 @@
+/* ###
+ * IP: GHIDRA
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package ghidra.app.plugin.core.debug.gui.copying;
+
+import static org.junit.Assert.*;
+
+import java.awt.Color;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.util.*;
+
+import javax.swing.JCheckBox;
+
+import org.junit.Test;
+
+import com.google.common.collect.Range;
+
+import ghidra.app.plugin.assembler.Assembler;
+import ghidra.app.plugin.assembler.Assemblers;
+import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest;
+import ghidra.app.plugin.core.debug.gui.DebuggerResources;
+import ghidra.app.plugin.core.debug.gui.copying.DebuggerCopyPlan.AllCopiers;
+import ghidra.app.util.viewer.listingpanel.PropertyBasedBackgroundColorModel;
+import ghidra.program.database.IntRangeMap;
+import ghidra.program.disassemble.Disassembler;
+import ghidra.program.disassemble.DisassemblerMessageListener;
+import ghidra.program.model.address.*;
+import ghidra.program.model.data.*;
+import ghidra.program.model.lang.Register;
+import ghidra.program.model.lang.RegisterValue;
+import ghidra.program.model.listing.*;
+import ghidra.program.model.symbol.*;
+import ghidra.trace.database.breakpoint.DBTraceBreakpointManager;
+import ghidra.trace.database.memory.DBTraceMemoryManager;
+import ghidra.trace.database.program.DBTraceVariableSnapProgramView;
+import ghidra.trace.database.symbol.*;
+import ghidra.trace.model.breakpoint.TraceBreakpointKind;
+import ghidra.trace.model.memory.TraceMemoryFlag;
+import ghidra.trace.model.memory.TraceMemoryState;
+import ghidra.util.database.UndoableTransaction;
+import ghidra.util.task.TaskMonitor;
+
+public class DebuggerCopyPlanTests extends AbstractGhidraHeadedDebuggerGUITest {
+ public static class TestDynamicDataType extends CountedDynamicDataType {
+ public static final TestDynamicDataType dataType = new TestDynamicDataType();
+
+ public TestDynamicDataType() {
+ super("test_dyn", "A test dynamic type", ShortDataType.dataType, ByteDataType.dataType,
+ 0, 2, 0xffff);
+ }
+ }
+
+ @Test
+ public void testBytes() throws Exception {
+ createTrace();
+ createProgram(getSLEIGH_X86_64_LANGUAGE());
+ AddressSpace stSpace = program.getAddressFactory().getDefaultAddressSpace();
+
+ DBTraceVariableSnapProgramView view = tb.trace.getProgramView();
+ assertTrue(AllCopiers.BYTES.isAvailable(view, program));
+
+ Random r = new Random();
+ byte src[] = new byte[0x10000];
+ r.nextBytes(src);
+ try (UndoableTransaction tid = tb.startTransaction()) {
+ DBTraceMemoryManager memory = tb.trace.getMemoryManager();
+ memory.createRegion(".text", 0, tb.range(0x55550000, 0x5555ffff),
+ TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
+ memory.putBytes(0, tb.addr(0x55550000), ByteBuffer.wrap(src));
+ }
+
+ Address paddr = tb.addr(stSpace, 0x00400000);
+ assertTrue(AllCopiers.BYTES.isRequiresInitializedMemory());
+ try (UndoableTransaction tid = UndoableTransaction.start(program, "Copy", true)) {
+ program.getMemory()
+ .createInitializedBlock(".text", paddr, 0x10000, (byte) 0, TaskMonitor.DUMMY,
+ false);
+ AllCopiers.BYTES.copy(view, tb.range(0x55550000, 0x5555ffff), program, paddr,
+ TaskMonitor.DUMMY);
+ }
+
+ byte dst[] = new byte[0x10000];
+ program.getMemory().getBytes(paddr, dst);
+
+ assertArrayEquals(src, dst);
+ }
+
+ @Test
+ public void testState() throws Exception {
+ createTrace();
+ createProgram(getSLEIGH_X86_64_LANGUAGE());
+ AddressSpace stSpace = program.getAddressFactory().getDefaultAddressSpace();
+
+ DBTraceVariableSnapProgramView view = tb.trace.getProgramView();
+ assertTrue(AllCopiers.STATE.isAvailable(view, program));
+
+ try (UndoableTransaction tid = tb.startTransaction()) {
+ DBTraceMemoryManager memory = tb.trace.getMemoryManager();
+ memory.createRegion(".text", 0, tb.range(0x55550000, 0x5555ffff),
+ TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
+ memory.putBytes(0, tb.addr(0x55550000), ByteBuffer.allocate(4096));
+ memory.setState(0, tb.addr(0x55551000), TraceMemoryState.ERROR);
+ }
+
+ Address paddr = tb.addr(stSpace, 0x00400000);
+ assertFalse(AllCopiers.STATE.isRequiresInitializedMemory());
+ try (UndoableTransaction tid = UndoableTransaction.start(program, "Copy", true)) {
+ program.getMemory()
+ .createInitializedBlock(".text", paddr, 0x10000, (byte) 0, TaskMonitor.DUMMY,
+ false);
+ AllCopiers.STATE.copy(view, tb.range(0x55550000, 0x5555ffff), program, paddr,
+ TaskMonitor.DUMMY);
+ }
+
+ IntRangeMap map =
+ program.getIntRangeMap(PropertyBasedBackgroundColorModel.COLOR_PROPERTY_NAME);
+ AddressSet staleSet =
+ map.getAddressSet(DebuggerResources.DEFAULT_COLOR_BACKGROUND_STALE.getRGB());
+ assertEquals(tb.set(tb.range(stSpace, 0x00401001, 0x0040ffff)), staleSet);
+ AddressSet errorSet =
+ map.getAddressSet(DebuggerResources.DEFAULT_COLOR_BACKGROUND_ERROR.getRGB());
+ assertEquals(tb.set(tb.range(stSpace, 0x00401000, 0x00401000)), errorSet);
+ }
+
+ @Test
+ public void testInstructionsMismatched() throws Exception {
+ createTrace();
+ createProgram(getSLEIGH_X86_64_LANGUAGE());
+
+ assertFalse(AllCopiers.INSTRUCTIONS.isAvailable(tb.trace.getProgramView(), program));
+ }
+
+ @Test
+ public void testInstructionsDepBytes() throws Exception {
+ DebuggerCopyPlan plan = new DebuggerCopyPlan();
+ JCheckBox cbInstructions = plan.getCheckBox(AllCopiers.INSTRUCTIONS);
+ JCheckBox cbBytes = plan.getCheckBox(AllCopiers.BYTES);
+ assertFalse(cbInstructions.isSelected());
+ assertFalse(cbBytes.isSelected());
+
+ cbInstructions.doClick();
+ assertTrue(cbInstructions.isSelected());
+ assertTrue(cbBytes.isSelected());
+
+ cbInstructions.doClick();
+ assertFalse(cbInstructions.isSelected());
+ assertTrue(cbBytes.isSelected());
+
+ cbInstructions.doClick();
+ assertTrue(cbInstructions.isSelected());
+ assertTrue(cbBytes.isSelected());
+
+ cbBytes.doClick();
+ assertFalse(cbInstructions.isSelected());
+ assertFalse(cbBytes.isSelected());
+
+ cbBytes.doClick();
+ assertFalse(cbInstructions.isSelected());
+ assertTrue(cbBytes.isSelected());
+ }
+
+ @Test
+ public void testInstructions() throws Exception {
+ createTrace();
+ createProgram();
+ AddressSpace stSpace = program.getAddressFactory().getDefaultAddressSpace();
+
+ DBTraceVariableSnapProgramView view = tb.trace.getProgramView();
+ assertTrue(AllCopiers.BYTES.isAvailable(view, program));
+ assertTrue(AllCopiers.INSTRUCTIONS.isAvailable(view, program));
+
+ AddressRange trng = tb.range(0x55550000, 0x5555ffff);
+ Assembler asm = Assemblers.getAssembler(view);
+ try (UndoableTransaction tid = tb.startTransaction()) {
+ DBTraceMemoryManager memory = tb.trace.getMemoryManager();
+ memory.createRegion(".text", 0, trng, TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
+ InstructionIterator iit = asm.assemble(tb.addr(0x55550000),
+ "imm r0, #1234",
+ "imm r1, #2045",
+ "add r0, r1");
+ assertTrue(iit.hasNext());
+ }
+
+ try (UndoableTransaction tid = UndoableTransaction.start(program, "Copy", true)) {
+ Address paddr = tb.addr(stSpace, 0x00400000);
+ program.getMemory()
+ .createInitializedBlock(".text", paddr, 0x10000, (byte) 0, TaskMonitor.DUMMY,
+ false);
+ AllCopiers.BYTES.copy(view, trng, program, paddr, TaskMonitor.DUMMY);
+ AllCopiers.INSTRUCTIONS.copy(view, trng, program, paddr, TaskMonitor.DUMMY);
+ }
+
+ List instructions = new ArrayList<>();
+ program.getListing().getInstructions(true).forEachRemaining(instructions::add);
+
+ assertEquals(3, instructions.size());
+ Instruction ins;
+
+ ins = instructions.get(0);
+ assertEquals(tb.addr(stSpace, 0x00400000), ins.getAddress());
+ assertEquals("imm r0,#0x4d2", ins.toString());
+ ins = instructions.get(1);
+ assertEquals(tb.addr(stSpace, 0x00400002), ins.getAddress());
+ assertEquals("imm r1,#0x7fd", ins.toString());
+ ins = instructions.get(2);
+ assertEquals(tb.addr(stSpace, 0x00400004), ins.getAddress());
+ assertEquals("add r0,r1", ins.toString());
+ }
+
+ @Test
+ public void testInstructionsWithDefaultContext() throws Exception {
+ createTrace("x86:LE:64:default");
+ createProgram(getSLEIGH_X86_64_LANGUAGE());
+ AddressSpace stSpace = program.getAddressFactory().getDefaultAddressSpace();
+
+ DBTraceVariableSnapProgramView view = tb.trace.getProgramView();
+ assertTrue(AllCopiers.BYTES.isAvailable(view, program));
+ assertTrue(AllCopiers.INSTRUCTIONS.isAvailable(view, program));
+
+ AddressRange trng = tb.range(0x55550000, 0x5555ffff);
+ Assembler asm = Assemblers.getAssembler(view);
+ try (UndoableTransaction tid = tb.startTransaction()) {
+ DBTraceMemoryManager memory = tb.trace.getMemoryManager();
+ memory.createRegion(".text", 0, trng, TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
+ InstructionIterator iit = asm.assemble(tb.addr(0x55550000),
+ "MOV RAX, 1234",
+ "MOV RCX, 2345",
+ "ADD RAX, RCX");
+ assertTrue(iit.hasNext());
+ }
+
+ try (UndoableTransaction tid = UndoableTransaction.start(program, "Copy", true)) {
+ Address paddr = tb.addr(stSpace, 0x00400000);
+ program.getMemory()
+ .createInitializedBlock(".text", paddr, 0x10000, (byte) 0, TaskMonitor.DUMMY,
+ false);
+ AllCopiers.BYTES.copy(view, trng, program, paddr, TaskMonitor.DUMMY);
+ AllCopiers.INSTRUCTIONS.copy(view, trng, program, paddr, TaskMonitor.DUMMY);
+ }
+
+ List instructions = new ArrayList<>();
+ program.getListing().getInstructions(true).forEachRemaining(instructions::add);
+
+ assertEquals(3, instructions.size());
+ Instruction ins;
+
+ ins = instructions.get(0);
+ assertEquals(tb.addr(stSpace, 0x00400000), ins.getAddress());
+ assertEquals("MOV RAX,0x4d2", ins.toString());
+ ins = instructions.get(1);
+ assertEquals(tb.addr(stSpace, 0x00400007), ins.getAddress());
+ assertEquals("MOV RCX,0x929", ins.toString());
+ ins = instructions.get(2);
+ assertEquals(tb.addr(stSpace, 0x0040000e), ins.getAddress());
+ assertEquals("ADD RAX,RCX", ins.toString());
+ }
+
+ @Test
+ public void testInstructionsWithContext() throws Exception {
+ createTrace("x86:LE:64:default");
+ createProgram(getSLEIGH_X86_64_LANGUAGE());
+ AddressSpace stSpace = program.getAddressFactory().getDefaultAddressSpace();
+
+ DBTraceVariableSnapProgramView view = tb.trace.getProgramView();
+ assertTrue(AllCopiers.BYTES.isAvailable(view, program));
+ assertTrue(AllCopiers.INSTRUCTIONS.isAvailable(view, program));
+
+ AddressRange trng = tb.range(0x55550000, 0x5555ffff);
+ // Assembler asm = Assemblers.getAssembler(view);
+
+ Register contextReg = tb.language.getContextBaseRegister();
+ Register longMode = tb.language.getRegister("longMode");
+ RegisterValue rv = tb.trace.getRegisterContextManager()
+ .getValueWithDefault(tb.language, contextReg, 0, tb.addr(0x55550000));
+ rv = rv.assign(longMode, BigInteger.ZERO);
+ Instruction checkCtx;
+ try (UndoableTransaction tid = tb.startTransaction()) {
+ DBTraceMemoryManager memory = tb.trace.getMemoryManager();
+ memory.createRegion(".text", 0, trng, TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
+ tb.trace.getRegisterContextManager().setValue(tb.language, rv, Range.atLeast(0L), trng);
+
+ // TODO: Once GP-1426 is resolved, use the assembler
+ /*
+ InstructionIterator iit = asm.assemble(tb.addr(0x55550000),
+ "MOV EAX, 1234",
+ "MOV ECX, 2345",
+ "ADD EAX, ECX");
+ checkCtx = iit.next();
+ */
+ memory.putBytes(0, tb.addr(0x55550000), tb.buf(
+ 0xb8, 0xd2, 0x04, 0x00, 0x00, // MOV EAX,1234
+ 0xb9, 0x29, 0x09, 0x00, 0x00, // MOV ECX,2345
+ 0x01, 0xc8 // ADD EAX,ECX
+ ));
+ Disassembler
+ .getDisassembler(view, TaskMonitor.DUMMY, DisassemblerMessageListener.IGNORE)
+ .disassemble(tb.addr(0x55550000), tb.set(tb.range(0x55550000, 0x5555000b)));
+ checkCtx = tb.trace.getCodeManager().instructions().getAt(0, tb.addr(0x55550000));
+ }
+ // Sanity pre-check
+ RegisterValue insCtx = checkCtx.getRegisterValue(contextReg);
+ assertFalse(insCtx.equals(tb.trace.getRegisterContextManager()
+ .getDefaultValue(tb.language, contextReg, checkCtx.getAddress())));
+
+ try (UndoableTransaction tid = UndoableTransaction.start(program, "Copy", true)) {
+ Address paddr = tb.addr(stSpace, 0x00400000);
+ program.getMemory()
+ .createInitializedBlock(".text", paddr, 0x10000, (byte) 0, TaskMonitor.DUMMY,
+ false);
+ AllCopiers.BYTES.copy(view, trng, program, paddr, TaskMonitor.DUMMY);
+ AllCopiers.INSTRUCTIONS.copy(view, trng, program, paddr, TaskMonitor.DUMMY);
+ }
+
+ List instructions = new ArrayList<>();
+ program.getListing().getInstructions(true).forEachRemaining(instructions::add);
+
+ assertEquals(3, instructions.size());
+ Instruction ins;
+
+ ins = instructions.get(0);
+ assertEquals(tb.addr(stSpace, 0x00400000), ins.getAddress());
+ assertEquals("MOV EAX,0x4d2", ins.toString());
+ ins = instructions.get(1);
+ assertEquals(tb.addr(stSpace, 0x00400005), ins.getAddress());
+ assertEquals("MOV ECX,0x929", ins.toString());
+ ins = instructions.get(2);
+ assertEquals(tb.addr(stSpace, 0x0040000a), ins.getAddress());
+ assertEquals("ADD EAX,ECX", ins.toString());
+ }
+
+ @Test
+ public void testDataMismatched() throws Exception {
+ createTrace();
+ createProgram(getSLEIGH_X86_64_LANGUAGE());
+
+ assertFalse(AllCopiers.DATA.isAvailable(tb.trace.getProgramView(), program));
+ }
+
+ @Test
+ public void testData() throws Exception {
+ createTrace();
+ createProgram();
+ AddressSpace stSpace = program.getAddressFactory().getDefaultAddressSpace();
+
+ DBTraceVariableSnapProgramView view = tb.trace.getProgramView();
+ assertTrue(AllCopiers.DATA.isAvailable(view, program));
+
+ AddressRange trng = tb.range(0x55560000, 0x5556ffff);
+ try (UndoableTransaction tid = tb.startTransaction()) {
+ DBTraceMemoryManager memory = tb.trace.getMemoryManager();
+ memory.createRegion(".data", 0, trng, TraceMemoryFlag.READ, TraceMemoryFlag.WRITE);
+ tb.addData(0, tb.addr(0x55560000), ByteDataType.dataType, tb.buf(0x12));
+ tb.addData(0, tb.addr(0x55560001), ShortDataType.dataType, tb.buf(0x12, 0x34));
+ tb.addData(0, tb.addr(0x55560003), IntegerDataType.dataType,
+ tb.buf(0x12, 0x34, 0x56, 0x78));
+ tb.addData(0, tb.addr(0x55560007), LongLongDataType.dataType,
+ tb.buf(0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0));
+ tb.addData(0, tb.addr(0x5556000f), TestDynamicDataType.dataType,
+ tb.buf(0x00, 0x03, 0x00, 0x01, 0x02));
+ }
+
+ try (UndoableTransaction tid = UndoableTransaction.start(program, "Copy", true)) {
+ Address paddr = tb.addr(stSpace, 0x00600000);
+ program.getMemory()
+ .createInitializedBlock(".data", paddr, 0x10000, (byte) 0, TaskMonitor.DUMMY,
+ false);
+ AllCopiers.DATA.copy(view, trng, program, paddr, TaskMonitor.DUMMY);
+ }
+
+ List data = new ArrayList<>();
+ program.getListing().getDefinedData(true).forEachRemaining(data::add);
+
+ // NB. Bytes were not copied. Dynamic omitted.
+ assertEquals(4, data.size());
+ Data dat;
+
+ dat = data.get(0);
+ assertEquals(tb.addr(stSpace, 0x00600000), dat.getAddress());
+ assertEquals("db 0h", dat.toString());
+ dat = data.get(1);
+ assertEquals(tb.addr(stSpace, 0x00600001), dat.getAddress());
+ assertEquals("short 0h", dat.toString());
+ dat = data.get(2);
+ assertEquals(tb.addr(stSpace, 0x00600003), dat.getAddress());
+ assertEquals("int 0h", dat.toString());
+ dat = data.get(3);
+ assertEquals(tb.addr(stSpace, 0x00600007), dat.getAddress());
+ assertEquals("longlong 0h", dat.toString());
+ }
+
+ @Test
+ public void testDynamicDataMismatched() throws Exception {
+ createTrace();
+ createProgram(getSLEIGH_X86_64_LANGUAGE());
+
+ assertFalse(AllCopiers.DYNAMIC_DATA.isAvailable(tb.trace.getProgramView(), program));
+ }
+
+ @Test
+ public void testDynamicData() throws Exception {
+ createTrace();
+ createProgram();
+ AddressSpace stSpace = program.getAddressFactory().getDefaultAddressSpace();
+
+ DBTraceVariableSnapProgramView view = tb.trace.getProgramView();
+ assertTrue(AllCopiers.DYNAMIC_DATA.isAvailable(view, program));
+
+ AddressRange trng = tb.range(0x55560000, 0x5556ffff);
+ try (UndoableTransaction tid = tb.startTransaction()) {
+ DBTraceMemoryManager memory = tb.trace.getMemoryManager();
+ memory.createRegion(".data", 0, trng, TraceMemoryFlag.READ, TraceMemoryFlag.WRITE);
+ tb.addData(0, tb.addr(0x55560000), ByteDataType.dataType, tb.buf(0x12));
+ tb.addData(0, tb.addr(0x55560001), ShortDataType.dataType, tb.buf(0x12, 0x34));
+ tb.addData(0, tb.addr(0x55560003), IntegerDataType.dataType,
+ tb.buf(0x12, 0x34, 0x56, 0x78));
+ tb.addData(0, tb.addr(0x55560007), LongLongDataType.dataType,
+ tb.buf(0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0));
+ tb.addData(0, tb.addr(0x5556000f), TestDynamicDataType.dataType,
+ tb.buf(0x00, 0x03, 0x00, 0x01, 0x02));
+ }
+
+ try (UndoableTransaction tid = UndoableTransaction.start(program, "Copy", true)) {
+ Address paddr = tb.addr(stSpace, 0x00600000);
+ program.getMemory()
+ .createInitializedBlock(".data", paddr, 0x10000, (byte) 0, TaskMonitor.DUMMY,
+ false);
+ AllCopiers.BYTES.copy(view, trng, program, paddr, TaskMonitor.DUMMY);
+ AllCopiers.DATA.copy(view, trng, program, paddr, TaskMonitor.DUMMY);
+ AllCopiers.DYNAMIC_DATA.copy(view, trng, program, paddr, TaskMonitor.DUMMY);
+ }
+
+ List data = new ArrayList<>();
+ program.getListing().getDefinedData(true).forEachRemaining(data::add);
+
+ // NB. Bytes were not copied. Dynamic omitted.
+ assertEquals(5, data.size());
+ Data dat;
+ Data cmp;
+
+ dat = data.get(0);
+ assertEquals(tb.addr(stSpace, 0x00600000), dat.getAddress());
+ assertEquals("db 12h", dat.toString());
+ dat = data.get(1);
+ assertEquals(tb.addr(stSpace, 0x00600001), dat.getAddress());
+ assertEquals("short 1234h", dat.toString());
+ dat = data.get(2);
+ assertEquals(tb.addr(stSpace, 0x00600003), dat.getAddress());
+ assertEquals("int 12345678h", dat.toString());
+ dat = data.get(3);
+ assertEquals(tb.addr(stSpace, 0x00600007), dat.getAddress());
+ assertEquals("longlong 123456789ABCDEF0h", dat.toString());
+
+ dat = data.get(4);
+ assertEquals(tb.addr(stSpace, 0x0060000f), dat.getAddress());
+ assertEquals("test_dyn ", dat.toString());
+ assertEquals(4, dat.getNumComponents()); // count + 3 elements
+ cmp = dat.getComponent(0);
+ assertEquals("short 3h", cmp.toString());
+ cmp = dat.getComponent(1);
+ assertEquals("db 0h", cmp.toString());
+ cmp = dat.getComponent(2);
+ assertEquals("db 1h", cmp.toString());
+ cmp = dat.getComponent(3);
+ assertEquals("db 2h", cmp.toString());
+ }
+
+ @Test
+ public void testLabels() throws Exception {
+ createTrace();
+ createProgram(getSLEIGH_X86_64_LANGUAGE());
+ AddressSpace stSpace = program.getAddressFactory().getDefaultAddressSpace();
+
+ DBTraceVariableSnapProgramView view = tb.trace.getProgramView();
+ assertTrue(AllCopiers.LABELS.isAvailable(view, program));
+
+ try (UndoableTransaction tid = tb.startTransaction()) {
+ DBTraceMemoryManager memory = tb.trace.getMemoryManager();
+ memory.createRegion(".text", 0, tb.range(0x55550000, 0x5555ffff),
+ TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
+ DBTraceNamespaceSymbol global = tb.trace.getSymbolManager().getGlobalNamespace();
+
+ DBTraceLabelSymbolView labels = tb.trace.getSymbolManager().labels();
+ labels.create(0, null, tb.addr(0x55550000), "test_label1", global, SourceType.IMPORTED);
+ labels.create(0, null, tb.addr(0x55550005), "test_label2", global,
+ SourceType.USER_DEFINED);
+ DBTraceNamespaceSymbolView namespaces = tb.trace.getSymbolManager().namespaces();
+ DBTraceNamespaceSymbol testNs = namespaces.add("test_ns", global, SourceType.ANALYSIS);
+ DBTraceNamespaceSymbol testNsChild =
+ namespaces.add("test_ns_child", testNs, SourceType.USER_DEFINED);
+ labels.create(0, null, tb.addr(0x55550800), "test_label3", testNsChild,
+ SourceType.ANALYSIS);
+ }
+
+ Address paddr = tb.addr(stSpace, 0x00400000);
+ try (UndoableTransaction tid = UndoableTransaction.start(program, "Copy", true)) {
+ program.getMemory()
+ .createInitializedBlock(".text", paddr, 0x10000, (byte) 0, TaskMonitor.DUMMY,
+ false);
+ AllCopiers.LABELS.copy(view, tb.range(0x55550000, 0x5555ffff), program, paddr,
+ TaskMonitor.DUMMY);
+ }
+
+ List symbols = new ArrayList<>();
+ program.getSymbolTable().getSymbolIterator(true).forEachRemaining(symbols::add);
+
+ assertEquals(3, symbols.size());
+ Symbol sym;
+ Namespace ns;
+
+ sym = symbols.get(0);
+ assertEquals("test_label1", sym.getName());
+ assertEquals(tb.addr(stSpace, 0x00400000), sym.getAddress());
+ assertEquals(SourceType.IMPORTED, sym.getSource());
+ assertTrue(sym.isGlobal());
+ sym = symbols.get(1);
+ assertEquals("test_label2", sym.getName());
+ assertEquals(tb.addr(stSpace, 0x00400005), sym.getAddress());
+ assertEquals(SourceType.USER_DEFINED, sym.getSource());
+ assertTrue(sym.isGlobal());
+
+ sym = symbols.get(2);
+ assertEquals("test_label3", sym.getName());
+ assertEquals(tb.addr(stSpace, 0x00400800), sym.getAddress());
+ assertEquals(SourceType.ANALYSIS, sym.getSource());
+ assertFalse(sym.isGlobal());
+ ns = sym.getParentNamespace();
+ assertEquals("test_ns_child", ns.getName());
+ assertEquals(SourceType.USER_DEFINED, ns.getSymbol().getSource());
+ assertFalse(ns.isGlobal());
+ ns = ns.getParentNamespace();
+ assertEquals("test_ns", ns.getName());
+ assertEquals(SourceType.ANALYSIS, ns.getSymbol().getSource());
+ assertFalse(ns.isGlobal());
+ ns = ns.getParentNamespace();
+ assertTrue(ns.isGlobal());
+ }
+
+ @Test
+ public void testBreakpoints() throws Exception {
+ createTrace();
+ createProgram(getSLEIGH_X86_64_LANGUAGE());
+ AddressSpace stSpace = program.getAddressFactory().getDefaultAddressSpace();
+
+ DBTraceVariableSnapProgramView view = tb.trace.getProgramView();
+ assertTrue(AllCopiers.BREAKPOINTS.isAvailable(view, program));
+
+ try (UndoableTransaction tid = tb.startTransaction()) {
+ DBTraceMemoryManager memory = tb.trace.getMemoryManager();
+ memory.createRegion(".text", 0, tb.range(0x55550000, 0x5555ffff),
+ TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
+
+ DBTraceBreakpointManager breakpoints = tb.trace.getBreakpointManager();
+ breakpoints.placeBreakpoint("[1]", 0, tb.addr(0x55550123), List.of(),
+ Set.of(TraceBreakpointKind.SW_EXECUTE), true, "Test-1");
+ breakpoints.placeBreakpoint("[2]", 0, tb.addr(0x55550321), List.of(),
+ Set.of(TraceBreakpointKind.SW_EXECUTE), false, "Test-2");
+ }
+
+ Address paddr = tb.addr(stSpace, 0x55550000);
+ try (UndoableTransaction tid = UndoableTransaction.start(program, "Init", true)) {
+ program.getMemory()
+ .createInitializedBlock(".text", paddr, 0x10000,
+ (byte) 0, TaskMonitor.DUMMY, false);
+ // Set up a collision. This is normal with relocations
+ program.getBookmarkManager()
+ .setBookmark(tb.addr(stSpace, 0x55550123), "BreakpointDisabled", "SW_EXECUTE;1",
+ "");
+
+ AllCopiers.BREAKPOINTS.copy(view, tb.range(0x55550000, 0x5555ffff), program, paddr,
+ TaskMonitor.DUMMY);
+ }
+
+ List bookmarks = new ArrayList<>();
+ program.getBookmarkManager().getBookmarksIterator().forEachRemaining(bookmarks::add);
+
+ assertEquals(2, bookmarks.size());
+ Collections.sort(bookmarks, Comparator.comparing(Bookmark::getAddress));
+ Bookmark bm;
+
+ bm = bookmarks.get(0);
+ assertEquals(tb.addr(stSpace, 0x55550123), bm.getAddress());
+ assertEquals("BreakpointEnabled", bm.getTypeString());
+ assertEquals("SW_EXECUTE;1", bm.getCategory());
+
+ bm = bookmarks.get(1);
+ assertEquals(tb.addr(stSpace, 0x55550321), bm.getAddress());
+ assertEquals("BreakpointDisabled", bm.getTypeString());
+ assertEquals("SW_EXECUTE;1", bm.getCategory());
+ }
+
+ @Test
+ public void testBookmarks() throws Exception {
+ createTrace();
+ createProgram(getSLEIGH_X86_64_LANGUAGE());
+ AddressSpace stSpace = program.getAddressFactory().getDefaultAddressSpace();
+
+ DBTraceVariableSnapProgramView view = tb.trace.getProgramView();
+ assertTrue(AllCopiers.BOOKMARKS.isAvailable(view, program));
+
+ try (UndoableTransaction tid = tb.startTransaction()) {
+ DBTraceMemoryManager memory = tb.trace.getMemoryManager();
+ memory.createRegion(".text", 0, tb.range(0x55550000, 0x5555ffff),
+ TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
+
+ BookmarkManager bookmarks = view.getBookmarkManager();
+ bookmarks.defineType("TestType", DebuggerResources.ICON_DEBUGGER, Color.BLUE, 1);
+ bookmarks.setBookmark(tb.addr(0x55550123), "TestType", "TestCategory", "Test Comment");
+ }
+
+ Address paddr = tb.addr(stSpace, 0x55550000);
+ try (UndoableTransaction tid = UndoableTransaction.start(program, "Init", true)) {
+ program.getMemory()
+ .createInitializedBlock(".text", paddr, 0x10000,
+ (byte) 0, TaskMonitor.DUMMY, false);
+
+ AllCopiers.BOOKMARKS.copy(view, tb.range(0x55550000, 0x5555ffff), program, paddr,
+ TaskMonitor.DUMMY);
+ }
+
+ List bookmarks = new ArrayList<>();
+ program.getBookmarkManager().getBookmarksIterator().forEachRemaining(bookmarks::add);
+
+ assertEquals(1, bookmarks.size());
+ Bookmark bm;
+
+ bm = bookmarks.get(0);
+ assertEquals(tb.addr(stSpace, 0x55550123), bm.getAddress());
+ BookmarkType type = program.getBookmarkManager().getBookmarkType("TestType");
+ assertNotNull(type);
+ assertEquals(type.getTypeString(), bm.getTypeString());
+ assertEquals("TestCategory", bm.getCategory());
+ assertEquals("Test Comment", bm.getComment());
+
+ assertEquals(DebuggerResources.ICON_DEBUGGER, type.getIcon());
+ assertEquals(Color.BLUE, type.getMarkerColor());
+ assertEquals(1, type.getMarkerPriority());
+ }
+
+ @Test
+ public void testReferences() throws Exception {
+ createTrace();
+ createProgram(getSLEIGH_X86_64_LANGUAGE());
+ AddressSpace stSpace = program.getAddressFactory().getDefaultAddressSpace();
+
+ DBTraceVariableSnapProgramView view = tb.trace.getProgramView();
+ assertTrue(AllCopiers.REFERENCES.isAvailable(view, program));
+
+ try (UndoableTransaction tid = tb.startTransaction()) {
+ DBTraceMemoryManager memory = tb.trace.getMemoryManager();
+ memory.createRegion(".text", 0, tb.range(0x55550000, 0x5555ffff),
+ TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
+ memory.createRegion(".data", 0, tb.range(0x55560000, 0x5556ffff),
+ TraceMemoryFlag.READ, TraceMemoryFlag.WRITE);
+
+ ReferenceManager references = view.getReferenceManager();
+ references.addMemoryReference(tb.addr(0x55550123),
+ tb.addr(0x55550321), RefType.COMPUTED_CALL, SourceType.USER_DEFINED, -1);
+ references.addMemoryReference(tb.addr(0x55550123),
+ tb.addr(0x55560321), RefType.READ, SourceType.USER_DEFINED, -1);
+ references.addMemoryReference(tb.addr(0x55560123),
+ tb.addr(0x55550321), RefType.PARAM, SourceType.USER_DEFINED, -1);
+ references.addMemoryReference(tb.addr(0x55560123),
+ tb.addr(0x55560321), RefType.DATA, SourceType.USER_DEFINED, -1);
+ }
+
+ Address paddr = tb.addr(stSpace, 0x55550000);
+ try (UndoableTransaction tid = UndoableTransaction.start(program, "Init", true)) {
+ program.getMemory()
+ .createInitializedBlock(".text", paddr, 0x10000,
+ (byte) 0, TaskMonitor.DUMMY, false);
+
+ AllCopiers.REFERENCES.copy(view, tb.range(0x55550000, 0x5555ffff), program, paddr,
+ TaskMonitor.DUMMY);
+ }
+
+ List references = new ArrayList<>();
+ program.getReferenceManager().getReferenceIterator(paddr).forEachRemaining(references::add);
+
+ assertEquals(1, references.size());
+ Reference ref;
+
+ ref = references.get(0);
+ assertEquals(tb.addr(stSpace, 0x55550123), ref.getFromAddress());
+ assertEquals(tb.addr(stSpace, 0x55550321), ref.getToAddress());
+ assertEquals(RefType.COMPUTED_CALL, ref.getReferenceType());
+ assertEquals(SourceType.USER_DEFINED, ref.getSource());
+ assertEquals(-1, ref.getOperandIndex());
+ }
+
+ @Test
+ public void testComments() throws Exception {
+ createTrace();
+ createProgram(getSLEIGH_X86_64_LANGUAGE());
+ AddressSpace stSpace = program.getAddressFactory().getDefaultAddressSpace();
+
+ DBTraceVariableSnapProgramView view = tb.trace.getProgramView();
+ assertTrue(AllCopiers.COMMENTS.isAvailable(view, program));
+
+ try (UndoableTransaction tid = tb.startTransaction()) {
+ DBTraceMemoryManager memory = tb.trace.getMemoryManager();
+ memory.createRegion(".text", 0, tb.range(0x55550000, 0x5555ffff),
+ TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
+
+ Listing listing = view.getListing();
+ listing.setComment(tb.addr(0x55550123), CodeUnit.EOL_COMMENT, "Test EOL Comment");
+ listing.setComment(tb.addr(0x55550321), CodeUnit.PLATE_COMMENT, "Test Plate Comment");
+ }
+
+ Address paddr = tb.addr(stSpace, 0x55550000);
+ try (UndoableTransaction tid = UndoableTransaction.start(program, "Init", true)) {
+ program.getMemory()
+ .createInitializedBlock(".text", paddr, 0x10000,
+ (byte) 0, TaskMonitor.DUMMY, false);
+
+ AllCopiers.COMMENTS.copy(view, tb.range(0x55550000, 0x5555ffff), program, paddr,
+ TaskMonitor.DUMMY);
+ }
+
+ Set addresses = new HashSet<>();
+ Listing listing = program.getListing();
+ listing.getCommentAddressIterator(program.getMemory(), true)
+ .forEachRemaining(addresses::add);
+
+ assertEquals(Set.of(tb.addr(stSpace, 0x55550123), tb.addr(stSpace, 0x55550321)), addresses);
+ assertEquals("Test EOL Comment",
+ listing.getComment(CodeUnit.EOL_COMMENT, tb.addr(stSpace, 0x55550123)));
+ assertEquals("Test Plate Comment",
+ listing.getComment(CodeUnit.PLATE_COMMENT, tb.addr(stSpace, 0x55550321)));
+ }
+}
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 0027466d0d..42bfe2da00 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
@@ -983,11 +983,11 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
@Test
@Ignore("TODO") // Needs attention, but low priority
- public void testActionCaptureSelectedMemory() throws Exception {
+ public void testActionReadSelectedMemory() throws Exception {
byte[] data = incBlock();
byte[] zero = new byte[data.length];
ByteBuffer buf = ByteBuffer.allocate(data.length);
- assertFalse(listingProvider.actionCaptureSelectedMemory.isEnabled());
+ assertFalse(listingProvider.actionReadSelectedMemory.isEnabled());
listingProvider.setAutoReadMemorySpec(readNone);
// To verify enabled requires live target
@@ -1002,12 +1002,12 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
traceManager.activateTrace(tb.trace);
waitForSwing();
// Still
- assertFalse(listingProvider.actionCaptureSelectedMemory.isEnabled());
+ assertFalse(listingProvider.actionReadSelectedMemory.isEnabled());
listingProvider.setSelection(sel);
waitForSwing();
// Still
- assertFalse(listingProvider.actionCaptureSelectedMemory.isEnabled());
+ assertFalse(listingProvider.actionReadSelectedMemory.isEnabled());
// Now, simulate the sequence that typically enables the action
createTestModel();
@@ -1024,12 +1024,12 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
// NOTE: recordTargetContainerAndOpenTrace has already activated the trace
// Action is still disabled, because it requires a selection
- assertFalse(listingProvider.actionCaptureSelectedMemory.isEnabled());
+ assertFalse(listingProvider.actionReadSelectedMemory.isEnabled());
listingProvider.setSelection(sel);
waitForSwing();
// Now, it should be enabled
- assertTrue(listingProvider.actionCaptureSelectedMemory.isEnabled());
+ assertTrue(listingProvider.actionReadSelectedMemory.isEnabled());
// First check nothing captured yet
buf.clear();
@@ -1038,7 +1038,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
assertArrayEquals(zero, buf.array());
// Verify that the action performs the expected task
- performAction(listingProvider.actionCaptureSelectedMemory);
+ performAction(listingProvider.actionReadSelectedMemory);
waitForBusyTool(tool);
waitForDomainObject(trace);
@@ -1053,28 +1053,28 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
// Verify that setting the memory inaccessible disables the action
mb.testProcess1.memory.setAccessible(false);
- waitForPass(() -> assertFalse(listingProvider.actionCaptureSelectedMemory.isEnabled()));
+ waitForPass(() -> assertFalse(listingProvider.actionReadSelectedMemory.isEnabled()));
// Verify that setting it accessible re-enables it (assuming we still have selection)
mb.testProcess1.memory.setAccessible(true);
- waitForPass(() -> assertTrue(listingProvider.actionCaptureSelectedMemory.isEnabled()));
+ waitForPass(() -> assertTrue(listingProvider.actionReadSelectedMemory.isEnabled()));
// Verify that moving into the past disables the action
TraceSnapshot forced = recorder.forceSnapshot();
waitForSwing(); // UI Wants to sync with new snap. Wait....
traceManager.activateSnap(forced.getKey() - 1);
waitForSwing();
- assertFalse(listingProvider.actionCaptureSelectedMemory.isEnabled());
+ assertFalse(listingProvider.actionReadSelectedMemory.isEnabled());
// Verify that advancing to the present enables the action (assuming a selection)
traceManager.activateSnap(forced.getKey());
waitForSwing();
- assertTrue(listingProvider.actionCaptureSelectedMemory.isEnabled());
+ assertTrue(listingProvider.actionReadSelectedMemory.isEnabled());
// Verify that stopping the recording disables the action
recorder.stopRecording();
waitForSwing();
- assertFalse(listingProvider.actionCaptureSelectedMemory.isEnabled());
+ assertFalse(listingProvider.actionReadSelectedMemory.isEnabled());
// TODO: When resume recording is implemented, verify action is enabled with selection
}
diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerMemoryBytesProviderTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerMemoryBytesProviderTest.java
index b2032f5619..011d92f4c7 100644
--- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerMemoryBytesProviderTest.java
+++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/gui/memory/DebuggerMemoryBytesProviderTest.java
@@ -742,11 +742,11 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge
@Test
@Ignore("TODO") // Needs attention, but low priority
// Accessibility listener does not seem to work
- public void testActionCaptureSelectedMemory() throws Exception {
+ public void testActionReadSelectedMemory() throws Exception {
byte[] data = incBlock();
byte[] zero = new byte[data.length];
ByteBuffer buf = ByteBuffer.allocate(data.length);
- assertFalse(memBytesProvider.actionCaptureSelectedMemory.isEnabled());
+ assertFalse(memBytesProvider.actionReadSelectedMemory.isEnabled());
memBytesProvider.setAutoReadMemorySpec(readNone);
// To verify enabled requires live target
@@ -761,12 +761,12 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge
traceManager.activateTrace(tb.trace);
waitForSwing();
// Still
- assertFalse(memBytesProvider.actionCaptureSelectedMemory.isEnabled());
+ assertFalse(memBytesProvider.actionReadSelectedMemory.isEnabled());
memBytesProvider.setSelection(sel);
waitForSwing();
// Still
- assertFalse(memBytesProvider.actionCaptureSelectedMemory.isEnabled());
+ assertFalse(memBytesProvider.actionReadSelectedMemory.isEnabled());
// Now, simulate the sequence that typically enables the action
createTestModel();
@@ -783,21 +783,21 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge
// NOTE: recordTargetContainerAndOpenTrace has already activated the trace
// Action is still disabled, because it requires a selection
- assertFalse(memBytesProvider.actionCaptureSelectedMemory.isEnabled());
+ assertFalse(memBytesProvider.actionReadSelectedMemory.isEnabled());
memBytesProvider.setSelection(sel);
waitForSwing();
// Now, it should be enabled
- assertTrue(memBytesProvider.actionCaptureSelectedMemory.isEnabled());
+ assertTrue(memBytesProvider.actionReadSelectedMemory.isEnabled());
- // First check nothing captured yet
+ // First check nothing recorded yet
buf.clear();
assertEquals(data.length,
trace.getMemoryManager().getBytes(recorder.getSnap(), addr(trace, 0x55550000), buf));
assertArrayEquals(zero, buf.array());
// Verify that the action performs the expected task
- performAction(memBytesProvider.actionCaptureSelectedMemory);
+ performAction(memBytesProvider.actionReadSelectedMemory);
waitForBusyTool(tool);
waitForDomainObject(trace);
@@ -812,28 +812,28 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge
// Verify that setting the memory inaccessible disables the action
mb.testProcess1.memory.setAccessible(false);
- waitForPass(() -> assertFalse(memBytesProvider.actionCaptureSelectedMemory.isEnabled()));
+ waitForPass(() -> assertFalse(memBytesProvider.actionReadSelectedMemory.isEnabled()));
// Verify that setting it accessible re-enables it (assuming we still have selection)
mb.testProcess1.memory.setAccessible(true);
- waitForPass(() -> assertTrue(memBytesProvider.actionCaptureSelectedMemory.isEnabled()));
+ waitForPass(() -> assertTrue(memBytesProvider.actionReadSelectedMemory.isEnabled()));
// Verify that moving into the past disables the action
TraceSnapshot forced = recorder.forceSnapshot();
waitForSwing(); // UI Wants to sync with new snap. Wait....
traceManager.activateSnap(forced.getKey() - 1);
waitForSwing();
- assertFalse(memBytesProvider.actionCaptureSelectedMemory.isEnabled());
+ assertFalse(memBytesProvider.actionReadSelectedMemory.isEnabled());
// Verify that advancing to the present enables the action (assuming a selection)
traceManager.activateSnap(forced.getKey());
waitForSwing();
- assertTrue(memBytesProvider.actionCaptureSelectedMemory.isEnabled());
+ assertTrue(memBytesProvider.actionReadSelectedMemory.isEnabled());
// Verify that stopping the recording disables the action
recorder.stopRecording();
waitForSwing();
- assertFalse(memBytesProvider.actionCaptureSelectedMemory.isEnabled());
+ assertFalse(memBytesProvider.actionReadSelectedMemory.isEnabled());
// TODO: When resume recording is implemented, verify action is enabled with selection
}
diff --git a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingServiceTest.java b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingServiceTest.java
index f42ff513f8..3434ff071a 100644
--- a/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingServiceTest.java
+++ b/Ghidra/Debug/Debugger/src/test/java/ghidra/app/plugin/core/debug/service/modules/DebuggerStaticMappingServiceTest.java
@@ -27,7 +27,7 @@ import com.google.common.collect.Range;
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest;
import ghidra.app.services.DebuggerStaticMappingService;
-import ghidra.app.services.DebuggerStaticMappingService.ShiftAndAddressSetView;
+import ghidra.app.services.DebuggerStaticMappingService.MappedAddressRange;
import ghidra.framework.model.DomainFile;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.Program;
@@ -339,7 +339,7 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
public void testAddMappingThenTranslateTraceViewToStaticEmpty() throws Exception {
addMapping();
- Map views =
+ Map> views =
mappingService.getOpenMappedViews(tb.trace, new AddressSet(), 0);
assertTrue(views.isEmpty());
}
@@ -360,18 +360,19 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
// After
set.add(dynSpace.getAddress(0xbadbadbadL), dynSpace.getAddress(0xbadbadbadL + 0xff));
- Map views =
+ Map> views =
mappingService.getOpenMappedViews(tb.trace, set, 0);
assertEquals(1, views.size());
- ShiftAndAddressSetView shifted = views.get(program);
- assertEquals(0x100000, shifted.getShift());
- AddressSetView inStatic = shifted.getAddressSetView();
- assertEquals(3, inStatic.getNumAddressRanges());
- AddressSet expected = new AddressSet();
- expected.add(stSpace.getAddress(0x00200000), stSpace.getAddress(0x002000ff));
- expected.add(stSpace.getAddress(0x00200c0d), stSpace.getAddress(0x00200ccc));
- expected.add(stSpace.getAddress(0x00201000 - 0x100), stSpace.getAddress(0x00200fff));
- assertEquals(expected, inStatic);
+ Collection mappedSet = views.get(program);
+
+ assertEquals(Set.of(
+ new MappedAddressRange(tb.range(0x00100000, 0x001000ff),
+ tb.range(stSpace, 0x00200000, 0x002000ff)),
+ new MappedAddressRange(tb.range(0x00100c0d, 0x00100ccc),
+ tb.range(stSpace, 0x00200c0d, 0x00200ccc)),
+ new MappedAddressRange(tb.range(0x00100f00, 0x00100fff),
+ tb.range(stSpace, 0x00200f00, 0x00200fff))),
+ mappedSet);
}
@Test
@@ -380,7 +381,7 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
copyTrace();
add2ndMapping();
- Map views =
+ Map> views =
mappingService.getOpenMappedViews(program, new AddressSet());
assertTrue(views.isEmpty());
}
@@ -403,30 +404,34 @@ public class DebuggerStaticMappingServiceTest extends AbstractGhidraHeadedDebugg
// After
set.add(stSpace.getAddress(0xbadbadbadL), stSpace.getAddress(0xbadbadbadL + 0xff));
- Map views =
+ Map> views =
mappingService.getOpenMappedViews(program, set);
Msg.info(this, views);
assertEquals(2, views.size());
- ShiftAndAddressSetView shifted1 = views.get(new DefaultTraceSnap(tb.trace, 0));
- assertEquals(-0x100000, shifted1.getShift());
- AddressSetView in1st = shifted1.getAddressSetView();
- assertEquals(5, in1st.getNumAddressRanges());
- AddressSetView in2nd = views.get(new DefaultTraceSnap(copy, 0)).getAddressSetView();
- assertEquals(3, in2nd.getNumAddressRanges());
+ Collection mappedSet1 = views.get(new DefaultTraceSnap(tb.trace, 0));
+ Collection mappedSet2 = views.get(new DefaultTraceSnap(copy, 0));
- AddressSet expectedIn1st = new AddressSet();
- AddressSet expectedIn2nd = new AddressSet();
- expectedIn1st.add(dynSpace.getAddress(0x00100000), dynSpace.getAddress(0x001000ff));
- expectedIn1st.add(dynSpace.getAddress(0x00100800 - 0x10),
- dynSpace.getAddress(0x00100800 + 0xf));
- expectedIn1st.add(dynSpace.getAddress(0x00101000 - 0x100), dynSpace.getAddress(0x00100fff));
- expectedIn2nd.add(expectedIn1st);
+ assertEquals(Set.of(
+ new MappedAddressRange(tb.range(stSpace, 0x00200000, 0x002000ff),
+ tb.range(0x00100000, 0x001000ff)),
+ new MappedAddressRange(tb.range(stSpace, 0x002007f0, 0x0020080f),
+ tb.range(0x001007f0, 0x0010080f)),
+ new MappedAddressRange(tb.range(stSpace, 0x00200f00, 0x00200fff),
+ tb.range(0x00100f00, 0x00100fff)),
+ new MappedAddressRange(tb.range(stSpace, 0x00200000, 0x002000ff),
+ tb.range(0x00102000, 0x001020ff)),
+ new MappedAddressRange(tb.range(stSpace, 0x002007f0, 0x002007ff),
+ tb.range(0x001027f0, 0x001027ff))),
+ mappedSet1);
- expectedIn1st.add(dynSpace.getAddress(0x00102000), dynSpace.getAddress(0x001020ff));
- expectedIn1st.add(dynSpace.getAddress(0x00102800 - 0x10), dynSpace.getAddress(0x001027ff));
-
- assertEquals(expectedIn1st, in1st);
- assertEquals(expectedIn2nd, in2nd);
+ assertEquals(Set.of(
+ new MappedAddressRange(tb.range(stSpace, 0x00200000, 0x002000ff),
+ tb.range(0x00100000, 0x001000ff)),
+ new MappedAddressRange(tb.range(stSpace, 0x002007f0, 0x0020080f),
+ tb.range(0x001007f0, 0x0010080f)),
+ new MappedAddressRange(tb.range(stSpace, 0x00200f00, 0x00200fff),
+ tb.range(0x00100f00, 0x00100fff))),
+ mappedSet2);
}
@Test
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/data/DBTraceDataTypeManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/data/DBTraceDataTypeManager.java
index c2e8c9ef56..5d5ab618d9 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/data/DBTraceDataTypeManager.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/data/DBTraceDataTypeManager.java
@@ -220,9 +220,7 @@ public class DBTraceDataTypeManager extends DataTypeManagerDB
@Override
public DataOrganization getDataOrganization() {
if (dataOrganization == null) {
- // TODO: Do I need to have a base compiler spec?
- dataOrganization =
- trace.getBaseLanguage().getDefaultCompilerSpec().getDataOrganization();
+ dataOrganization = trace.getBaseCompilerSpec().getDataOrganization();
}
return dataOrganization;
}
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceInstruction.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceInstruction.java
index 6812ecf3a5..83f32ce23e 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceInstruction.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceInstruction.java
@@ -30,6 +30,7 @@ import ghidra.program.model.mem.MemBuffer;
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.symbol.*;
import ghidra.trace.database.DBTraceUtils;
+import ghidra.trace.database.context.DBTraceRegisterContextManager;
import ghidra.trace.database.context.DBTraceRegisterContextSpace;
import ghidra.trace.database.language.DBTraceGuestLanguage;
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree;
@@ -621,13 +622,12 @@ public class DBTraceInstruction extends AbstractDBTraceCodeUnit lifespan, Address min, Address max,
- ProcessorContextView context) {
- Language language = space.baseLanguage;
- Register contextReg = language.getContextBaseRegister();
- if (contextReg == null) {
- return;
- }
- RegisterValue newValue = context.getRegisterValue(contextReg);
- DBTraceRegisterContextManager ctxMgr = space.trace.getRegisterContextManager();
- if (Objects.equals(ctxMgr.getDefaultValue(language, contextReg, min), newValue)) {
- DBTraceRegisterContextSpace ctxSpace = ctxMgr.get(space, false);
- if (ctxSpace == null) {
- return;
- }
- ctxSpace.setValue(language, null, lifespan, new AddressRangeImpl(min, max));
- return;
- }
- DBTraceRegisterContextSpace ctxSpace = ctxMgr.get(space, true);
- // TODO: Do not save non-flowing context beyond???
- ctxSpace.setValue(language, newValue, lifespan, new AddressRangeImpl(min, max));
- }
-
protected Instruction doCreateInstruction(Range lifespan, Address address,
InstructionPrototype prototype, Instruction protoInstr) {
try {
- doSetContexts(lifespan, address, address.addNoWrap(prototype.getLength() - 1),
- protoInstr);
-
Instruction created = doCreate(lifespan, address, prototype, protoInstr);
// copy override settings to replacement instruction
if (protoInstr.isFallThroughOverridden()) {
@@ -183,6 +159,27 @@ public class DBTraceInstructionsView extends AbstractBaseDBTraceDefinedUnitsView
super(space, space.instructionMapSpace);
}
+ protected void doSetContexts(TraceAddressSnapRange tasr, Language language,
+ ProcessorContextView context) {
+ Register contextReg = language.getContextBaseRegister();
+ if (contextReg == null || contextReg == Register.NO_CONTEXT) {
+ return;
+ }
+ RegisterValue newValue = context.getRegisterValue(contextReg);
+ DBTraceRegisterContextManager ctxMgr = space.trace.getRegisterContextManager();
+ if (Objects.equals(ctxMgr.getDefaultValue(language, contextReg, tasr.getX1()), newValue)) {
+ DBTraceRegisterContextSpace ctxSpace = ctxMgr.get(space, false);
+ if (ctxSpace == null) {
+ return;
+ }
+ ctxSpace.setValue(language, null, tasr.getLifespan(), tasr.getRange());
+ return;
+ }
+ DBTraceRegisterContextSpace ctxSpace = ctxMgr.get(space, true);
+ // TODO: Do not save non-flowing context beyond???
+ ctxSpace.setValue(language, newValue, tasr.getLifespan(), tasr.getRange());
+ }
+
protected DBTraceInstruction doCreate(Range lifespan, Address address,
InstructionPrototype prototype, ProcessorContextView context)
throws CodeUnitInsertionException, AddressOverflowException {
@@ -214,6 +211,8 @@ public class DBTraceInstructionsView extends AbstractBaseDBTraceDefinedUnitsView
throw new CodeUnitInsertionException("Code units cannot overlap");
}
+ doSetContexts(tasr, prototype.getLanguage(), context);
+
DBTraceInstruction created = space.instructionMapSpace.put(tasr, null);
created.set(prototype, context);
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewListing.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewListing.java
index 175372b5d2..5635c4dc1d 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewListing.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewListing.java
@@ -416,25 +416,33 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV
forward)));
}
+ protected AddressSetView getCommentAddresses(int commentType, AddressSetView addrSet) {
+ return new IntersectionAddressSetView(addrSet, program.viewport.unionedAddresses(
+ s -> program.trace.getCommentAdapter()
+ .getAddressSetView(Range.singleton(s), e -> e.getType() == commentType)));
+ }
+
+ protected AddressSetView getCommentAddresses(AddressSetView addrSet) {
+ return new IntersectionAddressSetView(addrSet, program.viewport.unionedAddresses(
+ s -> program.trace.getCommentAdapter()
+ .getAddressSetView(Range.singleton(s))));
+ }
+
@Override
public CodeUnitIterator getCommentCodeUnitIterator(int commentType, AddressSetView addrSet) {
- // TODO Auto-generated method stub
- return null;
+ return new WrappingCodeUnitIterator(
+ getCodeUnitIterator(getCommentAddresses(commentType, addrSet), true));
}
@Override
public AddressIterator getCommentAddressIterator(int commentType, AddressSetView addrSet,
boolean forward) {
- return new IntersectionAddressSetView(addrSet, program.viewport.unionedAddresses(
- s -> program.trace.getCommentAdapter()
- .getAddressSetView(Range.singleton(s), e -> e.getType() == commentType)))
- .getAddresses(forward);
+ return getCommentAddresses(commentType, addrSet).getAddresses(forward);
}
@Override
public AddressIterator getCommentAddressIterator(AddressSetView addrSet, boolean forward) {
- // TODO Auto-generated method stub
- return null;
+ return getCommentAddresses(addrSet).getAddresses(forward);
}
@Override
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewReferenceManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewReferenceManager.java
index 840c6c3096..cf58bdd146 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewReferenceManager.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewReferenceManager.java
@@ -25,6 +25,7 @@ import javax.help.UnsupportedOperationException;
import com.google.common.collect.Range;
+import generic.NestedIterator;
import ghidra.program.model.address.*;
import ghidra.program.model.lang.Register;
import ghidra.program.model.listing.Variable;
@@ -240,13 +241,22 @@ public abstract class AbstractDBTraceProgramViewReferenceManager implements Refe
: (r1, r2) -> -r1.getFromAddress().compareTo(r2.getFromAddress());
}
+ protected Iterator getReferenceIteratorForSnap(long snap, Address startAddr) {
+ AddressIterator addresses =
+ refs.getReferenceSources(Range.singleton(snap)).getAddresses(startAddr, true);
+ return NestedIterator.start(addresses, a -> {
+ return refs.getReferencesFrom(snap, a).iterator();
+ });
+ }
+
@Override
public ReferenceIterator getReferenceIterator(Address startAddr) {
if (refs(false) == null) {
return new ReferenceIteratorAdapter(Collections.emptyIterator());
}
+ // TODO: This will fail to occlude on equal (src,dst,opIndex) keys
return new ReferenceIteratorAdapter(
- program.viewport.mergedIterator(s -> refs.getReferencesFrom(s, startAddr).iterator(),
+ program.viewport.mergedIterator(s -> getReferenceIteratorForSnap(s, startAddr),
getReferenceFromComparator(true)));
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/ProgramMergeManagerPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/ProgramMergeManagerPlugin.java
index 73b89bac4d..f130ba0db2 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/ProgramMergeManagerPlugin.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/ProgramMergeManagerPlugin.java
@@ -50,6 +50,7 @@ public class ProgramMergeManagerPlugin extends MergeManagerPlugin implements Pro
/**
* Constructor for plugin that handles multi-user merge of programs.
+ *
* @param tool the tool with the active program to be merged
* @param mergeManager the merge manager that will control the merge process
* @param program the current program
@@ -61,7 +62,8 @@ public class ProgramMergeManagerPlugin extends MergeManagerPlugin implements Pro
@Override
public MergeManagerProvider createProvider() {
- return new MergeManagerProvider(this, "Merge Programs for " + currentDomainObject.getName());
+ return new MergeManagerProvider(this,
+ "Merge Programs for " + currentDomainObject.getName());
}
@Override
@@ -82,6 +84,7 @@ public class ProgramMergeManagerPlugin extends MergeManagerPlugin implements Pro
/**
* Gets the merge manager associated with this plug-in.
+ *
* @return the merge manager
*/
@Override
@@ -91,6 +94,7 @@ public class ProgramMergeManagerPlugin extends MergeManagerPlugin implements Pro
/**
* Defines and displays a component for resolving merge conflicts.
+ *
* @param component the component
* @param componentID the identifier for this component
*/
@@ -101,6 +105,7 @@ public class ProgramMergeManagerPlugin extends MergeManagerPlugin implements Pro
/**
* Sets the merge description at the top of the merge tool.
+ *
* @param mergeDescription the new description
*/
@Override
@@ -110,7 +115,9 @@ public class ProgramMergeManagerPlugin extends MergeManagerPlugin implements Pro
/**
* Sets the message below the progress meter in the current phase progress area.
- * @param progressDescription the new text message to display. If null, then the default message is displayed.
+ *
+ * @param progressDescription the new text message to display. If null, then the default message
+ * is displayed.
*/
@Override
void updateProgressDetails(String progressDescription) {
@@ -118,7 +125,9 @@ public class ProgramMergeManagerPlugin extends MergeManagerPlugin implements Pro
}
/**
- * Sets the percentage of the progress meter that is filled in for the current phase progress area.
+ * Sets the percentage of the progress meter that is filled in for the current phase progress
+ * area.
+ *
* @param currentPercentProgress the percentage of the progress bar to fill in from 0 to 100.
*/
@Override
@@ -135,8 +144,9 @@ public class ProgramMergeManagerPlugin extends MergeManagerPlugin implements Pro
}
/**
- * Enables/disables the Apply button at the bottom of the merge tool.
- * The Apply button is for applying conflicts.
+ * Enables/disables the Apply button at the bottom of the merge tool. The Apply button is for
+ * applying conflicts.
+ *
* @param state true means enable the button. false means disable it.
*/
@Override
@@ -146,6 +156,7 @@ public class ProgramMergeManagerPlugin extends MergeManagerPlugin implements Pro
/**
* Gets the provider for the merge.
+ *
* @return the provider
*/
@Override
@@ -153,22 +164,27 @@ public class ProgramMergeManagerPlugin extends MergeManagerPlugin implements Pro
return provider;
}
+ @Override
public boolean closeOtherPrograms(boolean ignoreChanges) {
return false;
}
+ @Override
public boolean closeAllPrograms(boolean ignoreChanges) {
return false;
}
+ @Override
public boolean closeProgram() {
return false;
}
+ @Override
public boolean closeProgram(Program program, boolean ignoreChanges) {
return false;
}
+ @Override
public Program[] getAllOpenPrograms() {
ProgramMultiUserMergeManager programMergeManager =
(ProgramMultiUserMergeManager) mergeManager;
@@ -178,10 +194,12 @@ public class ProgramMergeManagerPlugin extends MergeManagerPlugin implements Pro
programMergeManager.getProgram(MergeConstants.ORIGINAL) };
}
+ @Override
public Program getCurrentProgram() {
return (Program) currentDomainObject;
}
+ @Override
public Program getProgram(Address addr) {
return null;
}
@@ -190,6 +208,7 @@ public class ProgramMergeManagerPlugin extends MergeManagerPlugin implements Pro
return 0;
}
+ @Override
public boolean isVisible(Program program) {
return false;
}
@@ -199,6 +218,7 @@ public class ProgramMergeManagerPlugin extends MergeManagerPlugin implements Pro
return null;
}
+ @Override
public Program openProgram(DomainFile domainFile) {
return null;
}
@@ -208,29 +228,53 @@ public class ProgramMergeManagerPlugin extends MergeManagerPlugin implements Pro
return null;
}
+ @Override
public Program openProgram(DomainFile df, int version) {
return null;
}
+ @Override
public Program openProgram(DomainFile domainFile, int version, int state) {
return null;
}
+ @Override
public void openProgram(Program program) {
}
+ @Override
public void openProgram(Program program, boolean current) {
}
+ @Override
public void openProgram(Program program, int state) {
}
+ @Override
public void releaseProgram(Program program, Object persistentOwner) {
}
+ @Override
+ public void saveProgram() {
+ }
+
+ @Override
+ public void saveProgram(Program program) {
+ }
+
+ @Override
+ public void saveProgramAs() {
+ }
+
+ @Override
+ public void saveProgramAs(Program program) {
+ }
+
+ @Override
public void setCurrentProgram(Program p) {
}
+ @Override
public boolean setPersistentOwner(Program program, Object owner) {
return false;
}
@@ -238,10 +282,12 @@ public class ProgramMergeManagerPlugin extends MergeManagerPlugin implements Pro
public void setSearchPriority(Program p, int priority) {
}
+ @Override
public boolean isLocked() {
return false;
}
+ @Override
public void lockDown(boolean state) {
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/ProgramManagerPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/ProgramManagerPlugin.java
index 81b78ea51b..53a4e79bf3 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/ProgramManagerPlugin.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/progmgr/ProgramManagerPlugin.java
@@ -102,8 +102,7 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
/**
* Method called if the plugin supports this domain file.
*
- * @param data
- * the data to be used by the running tool
+ * @param data the data to be used by the running tool
* @return false if data is not a Program object.
*/
@Override
@@ -447,9 +446,9 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
}
/**
- * This method notifies listening plugins that a programs has been added to
- * the program manager. This is not used for actually opening a program from
- * the database and will act strangely if given a closed Program object.
+ * This method notifies listening plugins that a programs has been added to the program manager.
+ * This is not used for actually opening a program from the database and will act strangely if
+ * given a closed Program object.
*
* @see ghidra.app.services.ProgramManager#openProgram(ghidra.program.model.listing.Program)
*/
@@ -585,7 +584,7 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
/**
* Set the string chooser property editor on the property that is a filename.
*
- * @param options property list
+ * @param options property list
* @param filePropertyName name of the property that is a filename
*/
private void setPropertyEditor(Options options, String filePropertyName) {
@@ -597,8 +596,8 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
}
/**
- * Start a transaction if one has not been started; needed when program
- * properties are about to change from the options editor.
+ * Start a transaction if one has not been started; needed when program properties are about to
+ * change from the options editor.
*/
private void startTransaction(Program currentProgram) {
if (transactionID < 0) {
@@ -685,6 +684,26 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
return openProgram;
}
+ @Override
+ public void saveProgram() {
+ saveProgram(getCurrentProgram());
+ }
+
+ @Override
+ public void saveProgram(Program program) {
+ Swing.runIfSwingOrRunLater(() -> programSaveMgr.saveProgram(program));
+ }
+
+ @Override
+ public void saveProgramAs() {
+ saveProgramAs(getCurrentProgram());
+ }
+
+ @Override
+ public void saveProgramAs(Program program) {
+ Swing.runIfSwingOrRunLater(() -> programSaveMgr.saveAs(program));
+ }
+
/**
* Write out my data state.
*/
@@ -1040,13 +1059,4 @@ public class ProgramManagerPlugin extends Plugin implements ProgramManager {
public boolean isManaged(Program program) {
return programMgr.contains(program);
}
-
- public void saveProgram(Program program) {
- programSaveMgr.saveProgram(program);
- }
-
- public void saveProgramAs(Program program) {
- programSaveMgr.saveAs(program);
- }
-
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/services/ProgramManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/services/ProgramManager.java
index c7dea6e54e..1191106483 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/services/ProgramManager.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/services/ProgramManager.java
@@ -26,16 +26,17 @@ import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
/**
- * Service for managing programs. Multiple programs may be open in a tool, but only one is active
- * at any given time.
+ * Service for managing programs. Multiple programs may be open in a tool, but only one is active at
+ * any given time.
*/
-@ServiceInfo(defaultProvider = ProgramManagerPlugin.class, description = "Get the currently open program")
+@ServiceInfo(
+ defaultProvider = ProgramManagerPlugin.class,
+ description = "Get the currently open program")
public interface ProgramManager {
/**
- * Program will be open in a Hidden state if not already open.
- * This mode is generally used in conjunction with a persistent
- * program owner.
+ * Program will be open in a Hidden state if not already open. This mode is generally used in
+ * conjunction with a persistent program owner.
*/
public static final int OPEN_HIDDEN = 0;
@@ -45,20 +46,21 @@ public interface ProgramManager {
public static final int OPEN_CURRENT = 1;
/**
- * Program will be open within the tool but no change will be made
- * to the currently active program. If this is the only program
- * open, it will become the currently active program.
+ * Program will be open within the tool but no change will be made to the currently active
+ * program. If this is the only program open, it will become the currently active program.
*/
public static final int OPEN_VISIBLE = 2;
/**
* Return the program that is currently active.
+ *
* @return may return null if no program is open
*/
public Program getCurrentProgram();
/**
* Returns true if the specified program is open and considered visible to the user.
+ *
* @param program the program
* @return true if the specified program is open and considered visible to the user
*/
@@ -66,47 +68,51 @@ public interface ProgramManager {
/**
* Closes the currently active program
- * @return true if the close is successful.
- * false if the close fails or if there is no program currently active.
+ *
+ * @return true if the close is successful. false if the close fails or if there is no program
+ * currently active.
*/
public boolean closeProgram();
/**
- * Open the program corresponding to the given url.
+ * Open the program corresponding to the given url.
+ *
* @param ghidraURL valid server-based program URL
- * @param state initial open state (OPEN_HIDDEN, OPEN_CURRENT, OPEN_VISIBLE).
- * The visibility states will be ignored if the program is already open.
- * @return null if the user canceled the "open" for the new program or an error
- * occurred and was displayed.
+ * @param state initial open state (OPEN_HIDDEN, OPEN_CURRENT, OPEN_VISIBLE). The visibility
+ * states will be ignored if the program is already open.
+ * @return null if the user canceled the "open" for the new program or an error occurred and was
+ * displayed.
* @see GhidraURL
*/
public Program openProgram(URL ghidraURL, int state);
/**
- * Open the program for the given domainFile. Once open it will
- * become the active program.
+ * Open the program for the given domainFile. Once open it will become the active program.
+ *
* @param domainFile domain file that has the program
* @return null if the user canceled the "open" for the new program
*/
public Program openProgram(DomainFile domainFile);
/**
- * Open the program for the given domainFile. Once open it will become the active program.
+ * Open the program for the given domainFile. Once open it will become the active program.
*
- * Note: this method functions exactly as {@link #openProgram(DomainFile)}
+ *
+ * Note: this method functions exactly as {@link #openProgram(DomainFile)}
*
* @param domainFile domain file that has the program
* @param dialogParent unused
* @return the program
- * @deprecated deprecated for 10.1; removal for 10.3 or later; use {@link #openProgram(DomainFile)}
+ * @deprecated deprecated for 10.1; removal for 10.3 or later; use
+ * {@link #openProgram(DomainFile)}
*/
@Deprecated
public Program openProgram(DomainFile domainFile, Component dialogParent);
/**
- * Opens the specified version of the program represented by the given DomainFile. This
- * method should be used for shared DomainFiles. The newly opened file will be made the
- * active program.
+ * Opens the specified version of the program represented by the given DomainFile. This method
+ * should be used for shared DomainFiles. The newly opened file will be made the active program.
+ *
* @param df the DomainFile to open
* @param version the version of the Program to open
* @return the opened program or null if the given version does not exist.
@@ -115,29 +121,32 @@ public interface ProgramManager {
/**
* Open the program for the given domainFile
+ *
* @param domainFile domain file that has the program
- * @param version the version of the Program to open. Specify
- * DomainFile.DEFAULT_VERSION for file update mode.
- * @param state initial open state (OPEN_HIDDEN, OPEN_CURRENT, OPEN_VISIBLE).
- * The visibility states will be ignored if the program is already open.
- * @return null if the user canceled the "open" for the new program or an error
- * occurred and was displayed.
+ * @param version the version of the Program to open. Specify DomainFile.DEFAULT_VERSION for
+ * file update mode.
+ * @param state initial open state (OPEN_HIDDEN, OPEN_CURRENT, OPEN_VISIBLE). The visibility
+ * states will be ignored if the program is already open.
+ * @return null if the user canceled the "open" for the new program or an error occurred and was
+ * displayed.
*/
public Program openProgram(DomainFile domainFile, int version, int state);
/**
- * Opens the program to the tool. In this case the program is already open, but this tool
- * may not have it registered as open. The program is made the active program.
+ * Opens the program to the tool. In this case the program is already open, but this tool may
+ * not have it registered as open. The program is made the active program.
+ *
* @param program the program to register as open with the tool.
*/
public void openProgram(Program program);
/**
- * Opens the program to the tool. In this case the program is already open, but this tool
- * may not have it registered as open. The program is made the active program.
+ * Opens the program to the tool. In this case the program is already open, but this tool may
+ * not have it registered as open. The program is made the active program.
+ *
* @param program the program to register as open with the tool.
- * @param current if true, the program is made the current active program. If false, then
- * the program is made active only if it the first open program in the tool.
+ * @param current if true, the program is made the current active program. If false, then the
+ * program is made active only if it the first open program in the tool.
* @deprecated use openProgram(Program program, int state) instead.
*/
@Deprecated
@@ -145,19 +154,45 @@ public interface ProgramManager {
/**
* Open the specified program in the tool.
+ *
* @param program the program
- * @param state initial open state (OPEN_HIDDEN, OPEN_CURRENT, OPEN_VISIBLE).
- * The visibility states will be ignored if the program is already open.
+ * @param state initial open state (OPEN_HIDDEN, OPEN_CURRENT, OPEN_VISIBLE). The visibility
+ * states will be ignored if the program is already open.
*/
public void openProgram(Program program, int state);
/**
- * Establish a persistent owner on an open program. This will cause the program manager to
- * imply make a program hidden if it is closed.
+ * Saves the current program, possibly prompting the user for a new name.
+ */
+ public void saveProgram();
+
+ /**
+ * Saves the specified program, possibly prompting the user for a new name.
+ *
+ * @param program the program
+ */
+ public void saveProgram(Program program);
+
+ /**
+ * Prompts the user to save the current program to a selected file.
+ */
+ public void saveProgramAs();
+
+ /**
+ * Prompts the user to save the specified program to a selected file.
+ *
+ * @param program the program
+ */
+ public void saveProgramAs(Program program);
+
+ /**
+ * Establish a persistent owner on an open program. This will cause the program manager to imply
+ * make a program hidden if it is closed.
+ *
* @param program the program
* @param owner the owner
- * @return true if program is open and another object is not already the owner,
- * or the specified owner is already the owner.
+ * @return true if program is open and another object is not already the owner, or the specified
+ * owner is already the owner.
* @see #releaseProgram(Program, Object)
*/
public boolean setPersistentOwner(Program program, Object owner);
@@ -165,62 +200,67 @@ public interface ProgramManager {
/**
* Release the persistent ownership of a program.
*
- * The program will automatically be closed if it is hidden or was marked as temporary. If
- * any of these closures corresponds to a program with changes the user will be given an
- * opportunity to save or keep the program open.
+ * The program will automatically be closed if it is hidden or was marked as temporary. If any
+ * of these closures corresponds to a program with changes the user will be given an opportunity
+ * to save or keep the program open.
*
* If persistentOwner is not the correct owner, the method will have no affect.
+ *
* @param program the program
* @param persistentOwner the owner defined by {@link #setPersistentOwner(Program, Object)}
*/
public void releaseProgram(Program program, Object persistentOwner);
/**
- * Closes the given program with the option of saving any changes. The exact behavior of
- * this method depends on several factors. First of all, if any other tool has this program
- * open, then the program is closed for this tool only and the user is not prompted to
- * save the program regardless of the ignoreChanges flag. Otherwise, if ignoreChanges is
- * false and changes have been made, the user is prompted to save the program.
+ * Closes the given program with the option of saving any changes. The exact behavior of this
+ * method depends on several factors. First of all, if any other tool has this program open,
+ * then the program is closed for this tool only and the user is not prompted to save the
+ * program regardless of the ignoreChanges flag. Otherwise, if ignoreChanges is false and
+ * changes have been made, the user is prompted to save the program.
+ *
* @param program the program to close.
* @param ignoreChanges if true, the program is closed without saving any changes.
- * @return true if the program was closed. Returns false if the user canceled the close
- * while being prompted to save. Also returns false if the program passed in as a parameter
- * is null.
+ * @return true if the program was closed. Returns false if the user canceled the close while
+ * being prompted to save. Also returns false if the program passed in as a parameter is
+ * null.
*/
boolean closeProgram(Program program, boolean ignoreChanges);
/**
- * Closes all open programs in this tool except the current program.
- * If this tool is the only tool with a program open and that program has changes,
- * then the user will be prompted to close each such file.
- * (Providing the ignoreChanges flag is false)
+ * Closes all open programs in this tool except the current program. If this tool is the only
+ * tool with a program open and that program has changes, then the user will be prompted to
+ * close each such file. (Providing the ignoreChanges flag is false)
+ *
* @param ignoreChanges if true, the programs will be closed without saving changes.
* @return true if all other programs were closed. Returns false if the user canceled the close
- * while being prompted to save.
+ * while being prompted to save.
*/
public boolean closeOtherPrograms(boolean ignoreChanges);
/**
- * Closes all open programs in this tool. If this tool is the only tool with a program
- * open and that program has changes, then the user will be prompted to close each such file.
- * (Providing the ignoreChanges flag is false)
+ * Closes all open programs in this tool. If this tool is the only tool with a program open and
+ * that program has changes, then the user will be prompted to close each such file. (Providing
+ * the ignoreChanges flag is false)
+ *
* @param ignoreChanges if true, the programs will be closed without saving changes.
- * @return true if all programs were closed. Returns false if the user canceled the close
- * while being prompted to save.
+ * @return true if all programs were closed. Returns false if the user canceled the close while
+ * being prompted to save.
*/
public boolean closeAllPrograms(boolean ignoreChanges);
/**
* Sets the given program to be the current active program in the tool.
+ *
* @param p the program to make active.
*/
public void setCurrentProgram(Program p);
/**
* Returns the first program in the list of open programs that contains the given address.
- * Programs are searched in the order they were opened within a given priority.
- * Program are initially opened with the PRIORITY_NORMAL priority, but can be set to have
- * PRIORITY_HIGH or PRIORITY_LOW.
+ * Programs are searched in the order they were opened within a given priority. Program are
+ * initially opened with the PRIORITY_NORMAL priority, but can be set to have PRIORITY_HIGH or
+ * PRIORITY_LOW.
+ *
* @param addr the address for which to search.
* @return the first program that can be found to contain the given address.
*/
@@ -228,13 +268,15 @@ public interface ProgramManager {
/**
* Returns a list of all open program.
+ *
* @return the programs
*/
public Program[] getAllOpenPrograms();
/**
- * Allows program manager state to be locked/unlocked. While locked, the program manager will
+ * Allows program manager state to be locked/unlocked. While locked, the program manager will
* not support opening additional programs.
+ *
* @param state locked if true, unlocked if false
* @deprecated deprecated for 10.1; removal for 10.3 or later
*/
@@ -243,6 +285,7 @@ public interface ProgramManager {
/**
* Returns true if program manager is in the locked state
+ *
* @return true if program manager is in the locked state
* @deprecated deprecated for 10.1; removal for 10.3 or later
*/
diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/services/TestDummyProgramManager.java b/Ghidra/Features/Base/src/test/java/ghidra/app/services/TestDummyProgramManager.java
index 22c31fe08f..798502615a 100644
--- a/Ghidra/Features/Base/src/test/java/ghidra/app/services/TestDummyProgramManager.java
+++ b/Ghidra/Features/Base/src/test/java/ghidra/app/services/TestDummyProgramManager.java
@@ -23,8 +23,8 @@ import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
/**
- * A stub of the {@link ProgramManager} interface. This can be used to supply a test program
- * manager or to spy on system internals by overriding methods as needed.
+ * A stub of the {@link ProgramManager} interface. This can be used to supply a test program manager
+ * or to spy on system internals by overriding methods as needed.
*/
public class TestDummyProgramManager implements ProgramManager {
@@ -91,6 +91,26 @@ public class TestDummyProgramManager implements ProgramManager {
// stub
}
+ @Override
+ public void saveProgram() {
+ // stub
+ }
+
+ @Override
+ public void saveProgram(Program program) {
+ // stub
+ }
+
+ @Override
+ public void saveProgramAs() {
+ // stub
+ }
+
+ @Override
+ public void saveProgramAs(Program program) {
+ // stub
+ }
+
@Override
public boolean setPersistentOwner(Program program, Object owner) {
// stub
diff --git a/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/DiffProgramManager.java b/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/DiffProgramManager.java
index 49221b6816..4c73890b22 100644
--- a/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/DiffProgramManager.java
+++ b/Ghidra/Features/ProgramDiff/src/main/java/ghidra/app/plugin/core/diff/DiffProgramManager.java
@@ -24,8 +24,8 @@ import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
/**
- * A stubbed {@link ProgramManager} that used the 'second program' at the current program. This
- * is used to secondary views in order to install the right program.
+ * A stubbed {@link ProgramManager} that used the 'second program' at the current program. This is
+ * used to secondary views in order to install the right program.
*/
public class DiffProgramManager implements ProgramManager {
ProgramDiffPlugin programDiffPlugin;
@@ -119,6 +119,26 @@ public class DiffProgramManager implements ProgramManager {
// stub
}
+ @Override
+ public void saveProgram() {
+ // stub
+ }
+
+ @Override
+ public void saveProgram(Program program) {
+ // stub
+ }
+
+ @Override
+ public void saveProgramAs() {
+ // stub
+ }
+
+ @Override
+ public void saveProgramAs(Program program) {
+ // stub
+ }
+
@Override
public void setCurrentProgram(Program p) {
// stub
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/assembler/sleigh/SleighAssembler.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/assembler/sleigh/SleighAssembler.java
index c2b2c32487..ac4cb0c714 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/assembler/sleigh/SleighAssembler.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/assembler/sleigh/SleighAssembler.java
@@ -49,7 +49,6 @@ public class SleighAssembler implements Assembler {
protected Program program;
protected Listing listing;
protected Memory memory;
- protected Disassembler dis;
protected AssemblyParser parser;
protected AssemblyDefaultContext defaultContext;
protected AssemblyContextGraph ctxGraph;
@@ -71,8 +70,6 @@ public class SleighAssembler implements Assembler {
this.listing = program.getListing();
this.memory = program.getMemory();
- this.dis = Disassembler.getDisassembler(program, TaskMonitor.DUMMY,
- DisassemblerMessageListener.IGNORE);
}
/**
@@ -113,8 +110,12 @@ public class SleighAssembler implements Assembler {
Address end = at.add(insbytes.length - 1);
listing.clearCodeUnits(at, end, false);
memory.setBytes(at, insbytes);
- dis.disassemble(at, new AddressSet(at));
- return listing.getInstructions(new AddressSet(at, end), true);
+ AddressSet set = new AddressSet(at, end);
+ // Creating this at construction causes it to assess memory flags too early.
+ Disassembler dis = Disassembler.getDisassembler(program, TaskMonitor.DUMMY,
+ DisassemblerMessageListener.IGNORE);
+ dis.disassemble(at, set);
+ return listing.getInstructions(set, true);
}
@Override
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/assembler/sleigh/sem/AssemblyConstructorSemantic.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/assembler/sleigh/sem/AssemblyConstructorSemantic.java
index ac2c5e1350..38f4c5be69 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/assembler/sleigh/sem/AssemblyConstructorSemantic.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/assembler/sleigh/sem/AssemblyConstructorSemantic.java
@@ -46,9 +46,10 @@ public class AssemblyConstructorSemantic implements Comparable indices) {
this.cons = cons;
@@ -73,6 +74,7 @@ public class AssemblyConstructorSemantic implements Comparable getPatterns() {
@@ -92,6 +95,7 @@ public class AssemblyConstructorSemantic implements Comparable getOperandIndices() {
@@ -111,8 +116,9 @@ public class AssemblyConstructorSemantic implements Comparable getOperandIndexIterator() {
@@ -142,17 +148,17 @@ public class AssemblyConstructorSemantic implements ComparableallInitializedAddrSet and initializedLoadedAddrSet
- * with relevant initialized addresses from the specified memory block. If block is not
- * a mapped-block and it may be a source to existing mapped-blocks then
- * scanAllMappedBlocksIfNeeded
should be passed as true
unless
- * all mapped blocks will be processed separately.
+ * Update the allInitializedAddrSet
and initializedLoadedAddrSet
with
+ * relevant initialized addresses from the specified memory block. If block is not a
+ * mapped-block and it may be a source to existing mapped-blocks then
+ * scanAllMappedBlocksIfNeeded
should be passed as true
unless all
+ * mapped blocks will be processed separately.
+ *
* @param block memory block
- * @param scanAllMappedBlocksIfNeeded if true and block is initialized and not a mapped block all
- * mapped blocks will be processed for possible introduction of newly initialized mapped regions.
+ * @param scanAllMappedBlocksIfNeeded if true and block is initialized and not a mapped block
+ * all mapped blocks will be processed for possible introduction of newly initialized
+ * mapped regions.
*/
private void addBlockAddresses(MemoryBlockDB block, boolean scanAllMappedBlocksIfNeeded) {
AddressSet blockSet = new AddressSet(block.getStart(), block.getEnd());
@@ -193,11 +196,12 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
}
/**
- * Update initialized address set for those mapped blocks which map onto the
- * specified block which has just completed a transition of its' initialized state.
+ * Update initialized address set for those mapped blocks which map onto the specified block
+ * which has just completed a transition of its' initialized state.
+ *
* @param block block whose initialized state has changed
- * @param isInitialized true if block transitioned from uninitialized to initialized,
- * else transition is from initialized to uninitialized.
+ * @param isInitialized true if block transitioned from uninitialized to initialized, else
+ * transition is from initialized to uninitialized.
*/
private void updateMappedAddresses(MemoryBlockDB block, boolean isInitialized) {
@@ -285,6 +289,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
/**
* Returns the address factory for the program.
+ *
* @return program address factory
*/
AddressFactory getAddressFactory() {
@@ -293,6 +298,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
/**
* Returns the AddressMap from the program.
+ *
* @return program address map
*/
AddressMapDB getAddressMap() {
@@ -331,7 +337,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
throw new MemoryAccessException(block.getName() + " does not contain range " +
start.toString(true) + "-" + endAddr);
}
-
+
if (block.isMapped()) {
checkMemoryWriteMappedBlock(block, start, endAddr);
}
@@ -368,7 +374,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
mappedEndAddress =
byteMappingScheme.getMappedSourceAddress(mappedRangeMinAddr, endOffset);
}
-
+
for (MemoryBlockDB b : getBlocks(mappedStartAddress, mappedEndAddress)) {
Address minAddr = Address.min(b.getEnd(), mappedEndAddress);
Address maxAddr = Address.max(b.getStart(), mappedStartAddress);
@@ -381,9 +387,9 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
throws MemoryAccessException {
// TODO: could contain uninitialized region which is illegal to write to although block.isInitialized
// may not be of much help since it reflects the first sub-block only - seems like mixing is a bad idea
-
+
checkRangeForInstructions(start, endAddr);
-
+
// Check all mapped-block address ranges which map onto the range to be modified
Collection mappedBlocks = nonMappedBlock.getMappedBlocks();
if (mappedBlocks != null) {
@@ -480,8 +486,9 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
}
/**
- * Two blocks have been joined producing newBlock. The block which was
- * eliminated can be identified using the oldBlockStartAddr.
+ * Two blocks have been joined producing newBlock. The block which was eliminated can be
+ * identified using the oldBlockStartAddr.
+ *
* @param newBlock new joined memory block
* @param oldBlockStartAddr original start address of affected block
*/
@@ -798,6 +805,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
/**
* Check new block name for validity
+ *
* @param name new block name
* @throws IllegalArgumentException if invalid block name specified
*/
@@ -1246,25 +1254,19 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
}
/**
- * Tests if the memory contains a sequence of contiguous bytes that match the
- * given byte array at all bit positions where the mask contains an "on" bit.
- * The test will be something like
+ * Tests if the memory contains a sequence of contiguous bytes that match the given byte array
+ * at all bit positions where the mask contains an "on" bit. The test will be something like
*
- * for(int i=0;i= n) {
break;
}
+ n -= advanced;
try {
addr = block.getEnd().addNoWrap(1);
}
@@ -1879,8 +1882,9 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
}
/**
- * Tests if the given addressSpace (overlay space) is used by any blocks. If not, it
- * removes the space.
+ * Tests if the given addressSpace (overlay space) is used by any blocks. If not, it removes the
+ * space.
+ *
* @param addressSpace overlay address space to be removed
*/
private void checkRemoveAddressSpace(AddressSpace addressSpace) {
@@ -1930,8 +1934,8 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
}
/**
- * Gets the intersected set of addresses between a mapped memory block, and some other
- * address set.
+ * Gets the intersected set of addresses between a mapped memory block, and some other address
+ * set.
*
* @param mappedBlock The mapped memory block to use in the intersection.
* @param set Some other address set to use in the intersection.
@@ -1954,9 +1958,10 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
}
/**
- * Converts the given address range back from the source range back to the mapped range.
- * NOTE: It is important that the specified mappedSourceRange is restricted to the
- * mapped source area of the specified mappedBlock.
+ * Converts the given address range back from the source range back to the mapped range. NOTE:
+ * It is important that the specified mappedSourceRange is restricted to the mapped source area
+ * of the specified mappedBlock.
+ *
* @param mappedBlock mapped memory block
* @param mappedSourceRange source range which maps into mappedBlock.
* @return mapped range or null if source range not mapped to block
@@ -2225,9 +2230,10 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
/**
* Returns a list of all memory blocks that contain any addresses in the given range
+ *
* @param start the start address
* @param end the end address
- * @return a list of all memory blocks that contain any addresses in the given range
+ * @return a list of all memory blocks that contain any addresses in the given range
*/
List getBlocks(Address start, Address end) {
List list = new ArrayList<>();