diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceProgramViewListingTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceProgramViewListingTest.java index b1e77af6f1..fc14824c86 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceProgramViewListingTest.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceProgramViewListingTest.java @@ -15,7 +15,7 @@ */ package ghidra.trace.database.program; -import static ghidra.lifecycle.Unfinished.*; +import static ghidra.lifecycle.Unfinished.TODO; import static org.junit.Assert.*; import java.io.IOException; @@ -42,8 +42,8 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra ToyDBTraceBuilder b; - DBTraceProgramView view; - DBTraceProgramViewListing listing; // TODO: Do I want to expose the internal types? + DBTraceVariableSnapProgramView view; + DBTraceProgramViewListing listing; DBTraceMemoryManager memory; DBTraceCodeManager code; @@ -878,4 +878,22 @@ public class DBTraceProgramViewListingTest extends AbstractGhidraHeadlessIntegra assertEquals(i4005, listing.getDefinedCodeUnitBefore(b.addr(0x4006))); assertEquals(d4000, listing.getDefinedCodeUnitBefore(b.addr(0x4005))); } + + @Test + public void testGetCodeUnitsInTwoViews() throws Throwable { + try (Transaction tx = b.startTransaction()) { + memory.putBytes(0, b.addr(0x00400000), b.buf(1, 2, 3, 4, 5, 6, 7, 8)); + memory.putBytes(1, b.addr(0x00400000), b.buf(8, 7, 6, 5, 4, 3, 2, 1)); + } + + view.setSnap(1); + DBTraceProgramView view0 = b.trace.getFixedProgramView(0); + DBTraceProgramViewListing listing0 = view0.getListing(); + + CodeUnit cu0 = listing0.getCodeUnitAt(b.addr(0x00400000)); + CodeUnit cu1 = listing.getCodeUnitAt(b.addr(0x00400000)); + + assertArrayEquals(b.arr(1), cu0.getBytes()); + assertArrayEquals(b.arr(8), cu1.getBytes()); + } } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceProgramViewMemoryTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceProgramViewMemoryTest.java index 1634f99b30..34c21ce57a 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceProgramViewMemoryTest.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/program/DBTraceProgramViewMemoryTest.java @@ -23,7 +23,8 @@ import org.junit.*; import db.Transaction; import ghidra.program.database.ProgramBuilder; -import ghidra.program.model.address.*; +import ghidra.program.model.address.AddressSet; +import ghidra.program.model.address.AddressSpace; import ghidra.program.model.lang.LanguageNotFoundException; import ghidra.program.model.mem.MemoryBlock; import ghidra.test.AbstractGhidraHeadlessIntegrationTest; @@ -31,50 +32,47 @@ import ghidra.trace.database.ToyDBTraceBuilder; import ghidra.trace.database.memory.DBTraceMemoryManager; import ghidra.trace.database.memory.DBTraceMemoryRegion; import ghidra.trace.model.memory.TraceMemoryFlag; -import ghidra.trace.model.memory.TraceOverlappedRegionException; -import ghidra.util.exception.DuplicateNameException; public class DBTraceProgramViewMemoryTest extends AbstractGhidraHeadlessIntegrationTest { - ToyDBTraceBuilder b; + ToyDBTraceBuilder tb; - DBTraceProgramView view; + DBTraceVariableSnapProgramView view; DBTraceProgramViewMemory vmem; DBTraceMemoryManager memory; @Before public void setUpTraceProgramViewMemoryTest() throws LanguageNotFoundException, IOException { - b = new ToyDBTraceBuilder("Testing", ProgramBuilder._TOY64_BE); - try (Transaction tx = b.startTransaction()) { - b.trace.getTimeManager().createSnapshot("Created"); + tb = new ToyDBTraceBuilder("Testing", ProgramBuilder._TOY64_BE); + try (Transaction tx = tb.startTransaction()) { + tb.trace.getTimeManager().createSnapshot("Created"); } - memory = b.trace.getMemoryManager(); + memory = tb.trace.getMemoryManager(); // NOTE: First snap has to exist first - view = b.trace.getProgramView(); + view = tb.trace.getProgramView(); vmem = view.getMemory(); } @After public void tearDownTraceProgramViewListingTest() { - if (b != null) { - b.close(); + if (tb != null) { + tb.close(); } } @Test - public void testBlockInOverlay() throws DuplicateNameException, TraceOverlappedRegionException, - AddressOutOfBoundsException { + public void testBlockInOverlay() throws Throwable { AddressSpace os; DBTraceMemoryRegion io; - try (Transaction tx = b.startTransaction()) { + try (Transaction tx = tb.startTransaction()) { os = memory.createOverlayAddressSpace("test", - b.trace.getBaseAddressFactory().getDefaultAddressSpace()); - io = (DBTraceMemoryRegion) memory.createRegion(".io", 0, b.range(os, 0x1000, 0x1fff), + tb.trace.getBaseAddressFactory().getDefaultAddressSpace()); + io = (DBTraceMemoryRegion) memory.createRegion(".io", 0, tb.range(os, 0x1000, 0x1fff), TraceMemoryFlag.READ, TraceMemoryFlag.WRITE, TraceMemoryFlag.VOLATILE); } AddressSet asSet = new AddressSet(vmem); - assertEquals(b.set(b.range(os, 0x1000, 0x1fff)), asSet); + assertEquals(tb.set(tb.range(os, 0x1000, 0x1fff)), asSet); MemoryBlock[] blocks = vmem.getBlocks(); assertEquals(1, blocks.length); @@ -82,7 +80,26 @@ public class DBTraceProgramViewMemoryTest extends AbstractGhidraHeadlessIntegrat MemoryBlock blk = blocks[0]; assertSame(blk, vmem.getRegionBlock(io)); assertEquals(".io", blk.getName()); - assertEquals(b.addr(os, 0x1000), blk.getStart()); - assertEquals(b.addr(os, 0x1fff), blk.getEnd()); + assertEquals(tb.addr(os, 0x1000), blk.getStart()); + assertEquals(tb.addr(os, 0x1fff), blk.getEnd()); + } + + @Test + public void testBytesInTwoViews() throws Throwable { + try (Transaction tx = tb.startTransaction()) { + memory.putBytes(0, tb.addr(0x00400000), tb.buf(1, 2, 3, 4, 5, 6, 7, 8)); + memory.putBytes(1, tb.addr(0x00400000), tb.buf(8, 7, 6, 5, 4, 3, 2, 1)); + } + + view.setSnap(1); + DBTraceProgramView view0 = tb.trace.getFixedProgramView(0); + + byte[] actual = new byte[8]; + + view0.getMemory().getBytes(tb.addr(0x00400000), actual); + assertArrayEquals(tb.arr(1, 2, 3, 4, 5, 6, 7, 8), actual); + + view.getMemory().getBytes(tb.addr(0x00400000), actual); + assertArrayEquals(tb.arr(8, 7, 6, 5, 4, 3, 2, 1), actual); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/BytesFieldFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/BytesFieldFactory.java index 03f19213b4..d29daa81f2 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/BytesFieldFactory.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/viewer/field/BytesFieldFactory.java @@ -24,6 +24,8 @@ package ghidra.app.util.viewer.field; import java.awt.Color; import java.math.BigInteger; +import org.apache.commons.lang3.ArrayUtils; + import docking.widgets.fieldpanel.field.*; import docking.widgets.fieldpanel.support.FieldLocation; import docking.widgets.fieldpanel.support.RowColLocation; @@ -35,8 +37,6 @@ import ghidra.framework.options.ToolOptions; import ghidra.program.model.data.DataType; import ghidra.program.model.data.Structure; import ghidra.program.model.listing.*; -import ghidra.program.model.mem.Memory; -import ghidra.program.model.mem.MemoryAccessException; import ghidra.program.util.BytesFieldLocation; import ghidra.program.util.ProgramLocation; import ghidra.util.HelpLocation; @@ -168,45 +168,25 @@ public class BytesFieldFactory extends FieldFactory { @Override public ListingField getField(ProxyObj proxy, int varWidth) { - Object obj = proxy.getObject(); - if (!enabled || !(obj instanceof CodeUnit)) { + if (!enabled || !(proxy.getObject() instanceof CodeUnit cu)) { return null; } - CodeUnit cu = (CodeUnit) obj; - int length; - // Instructions: use prototype length so we display all bytes for length-override case - if (cu instanceof Instruction) { - // Consider all parsed bytes even if the overlap the next instruction due to the - // use of an instruction length-override. - length = ((Instruction) cu).getParsedLength(); - } - else { - length = Math.min(cu.getLength(), 100); - } + // Consider all parsed bytes even if the overlap the next instruction due to the + // use of an instruction length-override. + final int arrLength = + cu instanceof Instruction ins ? ins.getParsedLength() : Math.min(cu.getLength(), 100); - byte[] bytes = new byte[length]; - Memory memory = cu.getProgram().getMemory(); - try { - length = memory.getBytes(cu.getAddress(), bytes); - } - catch (MemoryAccessException e) { - return null; - } + byte[] bytes = new byte[arrLength]; + final int length = cu.getBytes(bytes, 0); if (length == 0) { return null; } - if ((cu instanceof Instruction) && reverseInstByteOrdering && !memory.isBigEndian()) { - int i = 0; - int j = length - 1; - while (j > i) { - byte b = bytes[i]; - bytes[i++] = bytes[j]; - bytes[j--] = b; - } + if ((cu instanceof Instruction) && reverseInstByteOrdering && !cu.isBigEndian()) { + ArrayUtils.reverse(bytes); } int groupLength = length / byteGroupSize; diff --git a/Ghidra/Test/DebuggerIntegrationTest/src/screen/java/ghidraclass/debugger/screenshot/TutorialDebuggerScreenShots.java b/Ghidra/Test/DebuggerIntegrationTest/src/screen/java/ghidraclass/debugger/screenshot/TutorialDebuggerScreenShots.java index 168d6078de..fe8982df4d 100644 --- a/Ghidra/Test/DebuggerIntegrationTest/src/screen/java/ghidraclass/debugger/screenshot/TutorialDebuggerScreenShots.java +++ b/Ghidra/Test/DebuggerIntegrationTest/src/screen/java/ghidraclass/debugger/screenshot/TutorialDebuggerScreenShots.java @@ -691,7 +691,7 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator }); waitForCondition(() -> actionNextDiff.isEnabled()); flatDbg.goToDynamic(secTermminesData.getStart()); - // Because auto-strack is a little broken right now + // Because auto-track is a little broken right now Thread.sleep(500); flatDbg.goToDynamic(secTermminesData.getStart()); diff --git a/GhidraDocs/GhidraClass/Debugger/images/Navigation_CompareTimes.png b/GhidraDocs/GhidraClass/Debugger/images/Navigation_CompareTimes.png index c07f48cff7..6ce0e54c9d 100644 Binary files a/GhidraDocs/GhidraClass/Debugger/images/Navigation_CompareTimes.png and b/GhidraDocs/GhidraClass/Debugger/images/Navigation_CompareTimes.png differ