diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/breakpoint/DBTraceBreakpoint.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/breakpoint/DBTraceBreakpoint.java index 832588ff53..b71f895264 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/breakpoint/DBTraceBreakpoint.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/breakpoint/DBTraceBreakpoint.java @@ -207,6 +207,7 @@ public class DBTraceBreakpoint Msg.warn(this, "Thread " + threadKeys[i] + " has been deleted since creating this breakpoint."); } + threads.add(t); } return Collections.unmodifiableSet(threads); } @@ -287,32 +288,41 @@ public class DBTraceBreakpoint public DBTraceBreakpoint splitAndSet(long snap, boolean en, Collection kinds) { DBTraceBreakpoint that; - Range oldLifespan; - Range newLifespan; + Range oldLifespan = null; + Range newLifespan = null; try (LockHold hold = LockHold.lock(space.lock.writeLock())) { if (!lifespan.contains(snap)) { throw new IllegalArgumentException("snap = " + snap); } - if (flagsByte == computeFlagsByte(enabled, kinds)) { + if (flagsByte == computeFlagsByte(en, kinds)) { return this; } if (snap == getPlacedSnap()) { - setEnabled(en); - return this; + this.doSetFlags(en, kinds); + that = this; + } + else { + that = doCopy(); + that.doSetLifespan(DBTraceUtils.toRange(snap, getClearedSnap())); + that.doSetFlags(en, kinds); + oldLifespan = lifespan; + newLifespan = DBTraceUtils.toRange(getPlacedSnap(), snap - 1); + this.doSetLifespan(newLifespan); } - - that = doCopy(); - that.doSetLifespan(DBTraceUtils.toRange(snap, getClearedSnap())); - that.doSetFlags(en, kinds); - oldLifespan = lifespan; - newLifespan = DBTraceUtils.toRange(getPlacedSnap(), snap - 1); - this.doSetLifespan(newLifespan); } - // Yes, issue ADDED, before LIFESPAN_CHANGED, as noted in docs - space.trace.setChanged( - new TraceChangeRecord<>(TraceBreakpointChangeType.ADDED, space, that)); - space.trace.setChanged(new TraceChangeRecord<>(TraceBreakpointChangeType.LIFESPAN_CHANGED, - space, this, oldLifespan, newLifespan)); + if (that == this) { + space.trace.setChanged( + new TraceChangeRecord<>(TraceBreakpointChangeType.CHANGED, space, this)); + } + else { + // Yes, issue ADDED, before LIFESPAN_CHANGED, as noted in docs + space.trace.setChanged( + new TraceChangeRecord<>(TraceBreakpointChangeType.ADDED, space, that)); + space.trace.setChanged( + new TraceChangeRecord<>(TraceBreakpointChangeType.LIFESPAN_CHANGED, + space, this, Objects.requireNonNull(oldLifespan), + Objects.requireNonNull(newLifespan))); + } return that; } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/breakpoint/DBTraceBreakpointManagerTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/breakpoint/DBTraceBreakpointManagerTest.java index 051525ae9c..fc1ef72606 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/breakpoint/DBTraceBreakpointManagerTest.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/breakpoint/DBTraceBreakpointManagerTest.java @@ -15,117 +15,252 @@ */ package ghidra.trace.database.breakpoint; -import static ghidra.lifecycle.Unfinished.TODO; +import static org.junit.Assert.*; -import org.junit.Ignore; -import org.junit.Test; +import java.util.Set; + +import org.junit.*; + +import com.google.common.collect.Range; + +import ghidra.test.AbstractGhidraHeadlessIntegrationTest; +import ghidra.trace.database.ToyDBTraceBuilder; +import ghidra.trace.model.breakpoint.TraceBreakpoint; +import ghidra.trace.model.breakpoint.TraceBreakpointKind; +import ghidra.trace.model.thread.TraceThread; +import ghidra.util.database.UndoableTransaction; +import ghidra.util.exception.DuplicateNameException; + +public class DBTraceBreakpointManagerTest extends AbstractGhidraHeadlessIntegrationTest { + + ToyDBTraceBuilder b; + DBTraceBreakpointManager breakpointManager; + + TraceThread thread; + TraceBreakpoint breakMain; + TraceBreakpoint breakVarA; + TraceBreakpoint breakVarB; + + @Before + public void setUpBreakpointManagerTest() throws Exception { + b = new ToyDBTraceBuilder("Testing", "Toy:BE:64:default"); + breakpointManager = b.trace.getBreakpointManager(); + } + + @After + public void tearDownBreakpointManagerTest() throws Exception { + b.close(); + } -@Ignore("TODO") -public class DBTraceBreakpointManagerTest { @Test public void testAddBreakpoint() throws Exception { - TODO(); + try (UndoableTransaction tid = b.startTransaction()) { + breakpointManager.addBreakpoint("Breaks[0]", Range.closed(0L, 10L), b.addr(0x00400000), + Set.of(), Set.of(TraceBreakpointKind.SW_EXECUTE), true, "main"); + } + + try (UndoableTransaction tid = b.startTransaction()) { + breakpointManager.addBreakpoint("Breaks[0]", Range.closed(0L, 10L), + b.range(0x00400000, 0x00400003), Set.of(), Set.of(), false, "duplicate"); + } + catch (DuplicateNameException e) { + // pass + } + + assertEquals(1, breakpointManager.getBreakpointsByPath("Breaks[0]").size()); + } + + protected void addBreakpoints() throws Exception { + try (UndoableTransaction tid = b.startTransaction()) { + thread = b.getOrAddThread("Thread1", 0); + breakMain = breakpointManager.addBreakpoint("Breaks[0]", Range.closed(0L, 10L), + b.addr(0x00400000), + Set.of(), Set.of(TraceBreakpointKind.SW_EXECUTE), true, "main"); + breakVarA = breakpointManager.addBreakpoint("Breaks[1]", Range.closed(0L, 10L), + b.range(0x00600010, 0x00600013), + Set.of(), Set.of(TraceBreakpointKind.WRITE), false, "varA"); + breakVarB = breakpointManager.addBreakpoint("Breaks[1]", Range.closed(11L, 20L), + b.range(0x00600020, 0x00600023), + Set.of(thread), Set.of(TraceBreakpointKind.WRITE), false, "varB"); + } } @Test public void testGetAllBreakpoints() throws Exception { - TODO(); + addBreakpoints(); + assertEquals(Set.of(breakMain, breakVarA, breakVarB), + Set.copyOf(breakpointManager.getAllBreakpoints())); } @Test public void testBreakpointsByPath() throws Exception { - TODO(); + addBreakpoints(); + assertEquals(Set.of(breakMain), + Set.copyOf(breakpointManager.getBreakpointsByPath("Breaks[0]"))); + assertEquals(Set.of(breakVarA, breakVarB), + Set.copyOf(breakpointManager.getBreakpointsByPath("Breaks[1]"))); + } + + @Test + public void testBreakpointPlacedByPath() throws Exception { + addBreakpoints(); + assertEquals(breakVarA, breakpointManager.getPlacedBreakpointByPath(0, "Breaks[1]")); + assertEquals(breakVarB, breakpointManager.getPlacedBreakpointByPath(11, "Breaks[1]")); } @Test public void testBreakpointsAt() throws Exception { - TODO(); + addBreakpoints(); + assertEquals(Set.of(breakMain), + Set.copyOf(breakpointManager.getBreakpointsAt(0, b.addr(0x00400000)))); + assertEquals(Set.of(breakVarA), + Set.copyOf(breakpointManager.getBreakpointsAt(0, b.addr(0x00600010)))); } @Test public void testBreakpointsIntersecting() throws Exception { - TODO(); + addBreakpoints(); + assertEquals(Set.of(breakMain, breakVarA), + Set.copyOf(breakpointManager.getBreakpointsIntersecting(Range.singleton(0L), + b.range(0x00400000, 0x00600010)))); + assertEquals(Set.of(breakMain), + Set.copyOf(breakpointManager.getBreakpointsIntersecting(Range.singleton(0L), + b.range(0x00400000, 0x00400010)))); + assertEquals(Set.of(breakVarA), + Set.copyOf(breakpointManager.getBreakpointsIntersecting(Range.singleton(0L), + b.range(0x00600000, 0x00600010)))); } @Test public void testGetTrace() throws Exception { - TODO(); + addBreakpoints(); + assertEquals(b.trace, breakMain.getTrace()); } @Test public void testGetPath() throws Exception { - TODO(); + addBreakpoints(); + assertEquals("Breaks[0]", breakMain.getPath()); } @Test - public void testSetName() throws Exception { - TODO(); - } - - @Test - public void testGetName() throws Exception { - TODO(); - } - - @Test - public void testGetRange() throws Exception { - TODO(); - // include min,max address, length - } - - @Test - public void testGetLifespan() throws Exception { - TODO(); - // include placed,cleared, - } - - @Test - public void testSetCleared() throws Exception { - TODO(); - } - - @Test - public void testSplit() throws Exception { - TODO(); - } - - @Test - public void testSetEnabled() throws Exception { - TODO(); - } - - @Test - public void testIsEnabled() throws Exception { - TODO(); - } - - @Test - public void testSplitWithEnabled() throws Exception { - TODO(); - } - - @Test - public void testGetKinds() throws Exception { - TODO(); + public void testSetGetName() throws Exception { + addBreakpoints(); + assertEquals("Breaks[0]", breakMain.getName()); + try (UndoableTransaction tid = b.startTransaction()) { + breakMain.setName("bpt 0"); + assertEquals("bpt 0", breakMain.getName()); + } + assertEquals("bpt 0", breakMain.getName()); } @Test public void testGetThreads() throws Exception { - TODO(); + addBreakpoints(); + assertEquals(Set.of(), Set.copyOf(breakMain.getThreads())); + assertEquals(Set.of(thread), Set.copyOf(breakVarB.getThreads())); } @Test - public void testSetComment() throws Exception { - TODO(); + public void testGetRange() throws Exception { + addBreakpoints(); + assertEquals(b.addr(0x00400000), breakMain.getMinAddress()); + assertEquals(b.addr(0x00400000), breakMain.getMaxAddress()); + assertEquals(b.range(0x00400000, 0x00400000), breakMain.getRange()); + assertEquals(1, breakMain.getLength()); } @Test - public void testGetComment() throws Exception { - TODO(); + public void testGetLifespan() throws Exception { + addBreakpoints(); + assertEquals(0, breakMain.getPlacedSnap()); + assertEquals(10, breakMain.getClearedSnap()); + assertEquals(Range.closed(0L, 10L), breakMain.getLifespan()); + } + + @Test + public void testSetCleared() throws Exception { + addBreakpoints(); + try (UndoableTransaction tid = b.startTransaction()) { + breakMain.setClearedSnap(5); + assertEquals(5, breakMain.getClearedSnap()); + } + assertEquals(0, breakMain.getPlacedSnap()); + assertEquals(5, breakMain.getClearedSnap()); + assertEquals(Range.closed(0L, 5L), breakMain.getLifespan()); + } + + @Test + public void testSplitAndSet() throws Exception { + addBreakpoints(); + + TraceBreakpoint disMain; + try (UndoableTransaction tid = b.startTransaction()) { + TraceBreakpoint oopsMain = + breakMain.splitAndSet(0, true, Set.of(TraceBreakpointKind.HW_EXECUTE)); + assertSame(breakMain, oopsMain); + disMain = + breakMain.splitAndSet(6, false, Set.of(TraceBreakpointKind.HW_EXECUTE)); + assertNotSame(breakMain, disMain); + TraceBreakpoint sameDis = + disMain.splitAndSet(8, false, Set.of(TraceBreakpointKind.HW_EXECUTE)); + assertSame(disMain, sameDis); + } + + assertTrue(breakMain.isEnabled()); + assertEquals(Set.of(TraceBreakpointKind.HW_EXECUTE), Set.copyOf(breakMain.getKinds())); + + assertFalse(disMain.isEnabled()); + assertEquals(Set.of(TraceBreakpointKind.HW_EXECUTE), Set.copyOf(disMain.getKinds())); + } + + @Test + public void testSetIsEnabled() throws Exception { + addBreakpoints(); + assertTrue(breakMain.isEnabled()); + try (UndoableTransaction tid = b.startTransaction()) { + breakMain.setEnabled(false); + assertFalse(breakMain.isEnabled()); + } + assertFalse(breakMain.isEnabled()); + try (UndoableTransaction tid = b.startTransaction()) { + breakMain.setEnabled(true); + assertTrue(breakMain.isEnabled()); + } + assertTrue(breakMain.isEnabled()); + } + + @Test + public void testSetGetKinds() throws Exception { + addBreakpoints(); + assertEquals(Set.of(TraceBreakpointKind.SW_EXECUTE), Set.copyOf(breakMain.getKinds())); + try (UndoableTransaction tid = b.startTransaction()) { + breakMain.setKinds(Set.of(TraceBreakpointKind.HW_EXECUTE)); + assertEquals(Set.of(TraceBreakpointKind.HW_EXECUTE), Set.copyOf(breakMain.getKinds())); + } + assertEquals(Set.of(TraceBreakpointKind.HW_EXECUTE), Set.copyOf(breakMain.getKinds())); + } + + @Test + public void testSetGetComment() throws Exception { + addBreakpoints(); + assertEquals("main", breakMain.getComment()); + try (UndoableTransaction tid = b.startTransaction()) { + breakMain.setComment("WinMain"); + assertEquals("WinMain", breakMain.getComment()); + } + assertEquals("WinMain", breakMain.getComment()); } @Test public void testDelete() throws Exception { - TODO(); + addBreakpoints(); + assertEquals(Set.of(breakMain), + Set.copyOf(breakpointManager.getBreakpointsByPath("Breaks[0]"))); + try (UndoableTransaction tid = b.startTransaction()) { + breakMain.delete(); + assertEquals(Set.of(), Set.copyOf(breakpointManager.getBreakpointsByPath("Breaks[0]"))); + } + assertEquals(Set.of(), Set.copyOf(breakpointManager.getBreakpointsByPath("Breaks[0]"))); } }