mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-02-16 15:40:14 +00:00
GP-0: Fix javodocs. Fix tests. Fix streamSub.
This commit is contained in:
parent
c2bb47d45a
commit
ddea132049
@ -22,7 +22,6 @@ import db.Transaction;
|
||||
import ghidra.async.AsyncUtils;
|
||||
import ghidra.dbg.target.*;
|
||||
import ghidra.dbg.util.PathMatcher;
|
||||
import ghidra.dbg.util.PathPattern;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.trace.model.Lifespan;
|
||||
import ghidra.trace.model.Trace;
|
||||
|
@ -98,7 +98,7 @@ class TraceBreakpointSet {
|
||||
/**
|
||||
* Get the trace
|
||||
*
|
||||
* @return
|
||||
* @return the trace
|
||||
*/
|
||||
public Trace getTrace() {
|
||||
return trace;
|
||||
@ -237,7 +237,7 @@ class TraceBreakpointSet {
|
||||
* The caller should first call {@link #canMerge(TraceBreakpoint)} to check if the breakpoint
|
||||
* "fits."
|
||||
*
|
||||
* @param bpt
|
||||
* @param bpt the breakpoint
|
||||
* @return true if the set actually changed as a result
|
||||
*/
|
||||
public boolean add(TraceBreakpoint bpt) {
|
||||
|
@ -408,7 +408,7 @@ public class DBTraceBreakpoint
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(long snap) {
|
||||
// NB. Only object mode support per-snap enablement
|
||||
// NB. Only object mode supports per-snap enablement
|
||||
try (LockHold hold = LockHold.lock(space.lock.readLock())) {
|
||||
return enabled;
|
||||
}
|
||||
@ -491,4 +491,11 @@ public class DBTraceBreakpoint
|
||||
public void delete() {
|
||||
space.deleteBreakpoint(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(long snap) {
|
||||
try (LockHold hold = LockHold.lock(space.lock.readLock())) {
|
||||
return lifespan.contains(snap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -369,6 +369,11 @@ public class DBTraceObjectBreakpointLocation
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(long snap) {
|
||||
return object.getCanonicalParent(snap) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceObject getObject() {
|
||||
return object;
|
||||
|
@ -223,6 +223,11 @@ public class DBTraceObjectBreakpointSpec
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(long snap) {
|
||||
return object.getCanonicalParent(snap) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceObject getObject() {
|
||||
return object;
|
||||
|
@ -307,4 +307,11 @@ public class DBTraceMemoryRegion
|
||||
public void delete() {
|
||||
space.deleteRegion(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(long snap) {
|
||||
try (LockHold hold = LockHold.lock(space.lock.readLock())) {
|
||||
return lifespan.contains(snap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -386,6 +386,11 @@ public class DBTraceObjectMemoryRegion implements TraceObjectMemoryRegion, DBTra
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(long snap) {
|
||||
return object.getCanonicalParent(snap) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceObject getObject() {
|
||||
return object;
|
||||
|
@ -16,6 +16,7 @@
|
||||
package ghidra.trace.database.target;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
@ -210,11 +211,15 @@ class DBTraceObjectValueWriteBehindCache {
|
||||
|
||||
private Stream<DBTraceObjectValueBehind> streamSub(
|
||||
NavigableMap<Long, DBTraceObjectValueBehind> map, Lifespan span, boolean forward) {
|
||||
Long floor = map.floorKey(span.min());
|
||||
if (floor == null) {
|
||||
floor = span.min();
|
||||
long min;
|
||||
Entry<Long, DBTraceObjectValueBehind> floor = map.floorEntry(span.min());
|
||||
if (floor != null && floor.getValue().getLifespan().contains(span.min())) {
|
||||
min = floor.getKey();
|
||||
}
|
||||
var sub = map.subMap(floor, true, span.max(), true);
|
||||
else {
|
||||
min = span.min();
|
||||
}
|
||||
var sub = map.subMap(min, true, span.max(), true);
|
||||
if (!forward) {
|
||||
sub = sub.descendingMap();
|
||||
}
|
||||
|
@ -175,6 +175,11 @@ public class DBTraceObjectThread implements TraceObjectThread, DBTraceObjectInte
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(long snap) {
|
||||
return object.getCanonicalParent(snap) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceChangeRecord<?, ?> translateEvent(TraceChangeRecord<?, ?> rec) {
|
||||
return translator.translate(rec);
|
||||
|
@ -184,4 +184,11 @@ public class DBTraceThread extends DBAnnotatedObject implements TraceThread {
|
||||
public void delete() {
|
||||
manager.deleteThread(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(long snap) {
|
||||
try (LockHold hold = LockHold.lock(manager.lock.readLock())) {
|
||||
return lifespan.contains(snap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,8 @@ package ghidra.trace.model.breakpoint;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import ghidra.pcode.emu.DefaultPcodeThread.PcodeEmulationLibrary;
|
||||
import ghidra.pcode.exec.SleighUtils;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressRange;
|
||||
import ghidra.trace.model.*;
|
||||
@ -51,6 +53,8 @@ public interface TraceBreakpoint extends TraceUniqueObject {
|
||||
*
|
||||
* <p>
|
||||
* This should be a name suitable for display on the screen
|
||||
*
|
||||
* @param name the new name
|
||||
*/
|
||||
void setName(String name);
|
||||
|
||||
@ -75,12 +79,18 @@ public interface TraceBreakpoint extends TraceUniqueObject {
|
||||
AddressRange getRange();
|
||||
|
||||
/**
|
||||
* Get the minimum address in this breakpoint's range
|
||||
*
|
||||
* @see #getRange()
|
||||
* @return the minimum address
|
||||
*/
|
||||
Address getMinAddress();
|
||||
|
||||
/**
|
||||
* Get the maximum address in this breakpoint's range
|
||||
*
|
||||
* @see #getRange()
|
||||
* @return the maximum address
|
||||
*/
|
||||
Address getMaxAddress();
|
||||
|
||||
@ -109,6 +119,7 @@ public interface TraceBreakpoint extends TraceUniqueObject {
|
||||
* Set the cleared snap of this breakpoint
|
||||
*
|
||||
* @param clearedSnap the cleared snap, or {@link Long#MAX_VALUE} for "to the end of time"
|
||||
* @throws DuplicateNameException if extending the lifespan would cause a naming collision
|
||||
*/
|
||||
void setClearedSnap(long clearedSnap) throws DuplicateNameException;
|
||||
|
||||
@ -236,21 +247,27 @@ public interface TraceBreakpoint extends TraceUniqueObject {
|
||||
* Set Sleigh source to replace the breakpointed instruction in emulation
|
||||
*
|
||||
* <p>
|
||||
* The default is simply "<code>{@link PcodeEmulationLibrary#emu_swi() emu_swi()};
|
||||
* {@link PcodeEmulationLibrary#emu_exec_decoded() emu_exec_decoded()};</code>", effectively a
|
||||
* non-conditional breakpoint followed by execution of the actual instruction. Modifying this
|
||||
* allows clients to create conditional breakpoints or simply override or inject additional
|
||||
* logic into an emulated target.
|
||||
* The default is simply:
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* {@link PcodeEmulationLibrary#emu_swi() emu_swi()};
|
||||
* {@link PcodeEmulationLibrary#emu_exec_decoded() emu_exec_decoded()};
|
||||
* </pre>
|
||||
* <p>
|
||||
* That is effectively a non-conditional breakpoint followed by execution of the actual
|
||||
* instruction. Modifying this allows clients to create conditional breakpoints or simply
|
||||
* override or inject additional logic into an emulated target.
|
||||
*
|
||||
* <p>
|
||||
* <b>NOTE:</b> This current has no effect on access breakpoints, but only execution
|
||||
* <b>NOTE:</b> This currently has no effect on access breakpoints, but only execution
|
||||
* breakpoints.
|
||||
*
|
||||
* <p>
|
||||
* If the specified source fails to compile during emulator set-up, this will fall back to
|
||||
* {@link PcodeEmulationLibrary#emu_err
|
||||
* {@link PcodeEmulationLibrary#emu_swi()}
|
||||
*
|
||||
* @see #DEFAULT_SLEIGH
|
||||
* @see SleighUtils#UNCONDITIONAL_BREAK
|
||||
* @param sleigh the Sleigh source
|
||||
*/
|
||||
void setEmuSleigh(String sleigh);
|
||||
@ -266,4 +283,18 @@ public interface TraceBreakpoint extends TraceUniqueObject {
|
||||
* Delete this breakpoint from the trace
|
||||
*/
|
||||
void delete();
|
||||
|
||||
/**
|
||||
* Check if the breakpoint is valid at the given snapshot
|
||||
*
|
||||
* <p>
|
||||
* In object mode, a breakpoint's life may be disjoint, so checking if the snap occurs between
|
||||
* creation and destruction is not quite sufficient. This method encapsulates validity. In
|
||||
* object mode, it checks that the breakpoint object has a canonical parent at the given
|
||||
* snapshot. In table mode, it checks that the lifespan contains the snap.
|
||||
*
|
||||
* @param snap the snapshot key
|
||||
* @return true if valid, false if not
|
||||
*/
|
||||
boolean isValid(long snap);
|
||||
}
|
||||
|
@ -89,6 +89,9 @@ public interface TraceMemoryRegion extends TraceUniqueObject {
|
||||
*
|
||||
* @param creationSnap the creation snap, or {@link Long#MIN_VALUE} for "since the beginning of
|
||||
* time"
|
||||
* @throws DuplicateNameException if extending the region would cause a naming conflict
|
||||
* @throws TraceOverlappedRegionException if extending the region would cause it to overlap
|
||||
* another
|
||||
*/
|
||||
void setCreationSnap(long creationSnap)
|
||||
throws DuplicateNameException, TraceOverlappedRegionException;
|
||||
@ -105,6 +108,9 @@ public interface TraceMemoryRegion extends TraceUniqueObject {
|
||||
*
|
||||
* @param destructionSnap the destruction snap, or {@link Long#MAX_VALUE} for "to the end of
|
||||
* time"
|
||||
* @throws DuplicateNameException if extending the region would cause a naming conflict
|
||||
* @throws TraceOverlappedRegionException if extending the region would cause it to overlap
|
||||
* another
|
||||
*/
|
||||
void setDestructionSnap(long destructionSnap)
|
||||
throws DuplicateNameException, TraceOverlappedRegionException;
|
||||
@ -138,22 +144,38 @@ public interface TraceMemoryRegion extends TraceUniqueObject {
|
||||
AddressRange getRange();
|
||||
|
||||
/**
|
||||
* Set the minimum address of the range
|
||||
*
|
||||
* @see #setRange(AddressRange)
|
||||
* @param min the new minimum
|
||||
* @throws TraceOverlappedRegionException if extending the region would cause it to overlap
|
||||
* another
|
||||
*/
|
||||
void setMinAddress(Address min) throws TraceOverlappedRegionException;
|
||||
|
||||
/**
|
||||
* Get the minimum address of the range
|
||||
*
|
||||
* @see #getRange()
|
||||
* @return the minimum address
|
||||
*/
|
||||
Address getMinAddress();
|
||||
|
||||
/**
|
||||
* Set the maximum address of the range
|
||||
*
|
||||
* @see #setRange(AddressRange)
|
||||
* @param max the new minimum
|
||||
* @throws TraceOverlappedRegionException if extending the region would cause it to overlap
|
||||
* another
|
||||
*/
|
||||
void setMaxAddress(Address max) throws TraceOverlappedRegionException;
|
||||
|
||||
/**
|
||||
* Get the maximum address of the range
|
||||
*
|
||||
* @see #getRange()
|
||||
* @return the maximum address
|
||||
*/
|
||||
Address getMaxAddress();
|
||||
|
||||
@ -164,6 +186,11 @@ public interface TraceMemoryRegion extends TraceUniqueObject {
|
||||
* This adjusts the max address of the range so that its length becomes that given
|
||||
*
|
||||
* @see #setRange(AddressRange)
|
||||
* @param length the desired length of the range
|
||||
* @throws AddressOverflowException if extending the range would cause the max address to
|
||||
* overflow
|
||||
* @throws TraceOverlappedRegionException if extending the region would cause it to overlap
|
||||
* another
|
||||
*/
|
||||
void setLength(long length) throws AddressOverflowException, TraceOverlappedRegionException;
|
||||
|
||||
@ -182,7 +209,9 @@ public interface TraceMemoryRegion extends TraceUniqueObject {
|
||||
void setFlags(Collection<TraceMemoryFlag> flags);
|
||||
|
||||
/**
|
||||
* @see #setFlags(Collection)
|
||||
* Set the flags, e.g., permissions, of this region
|
||||
*
|
||||
* @param flags the flags
|
||||
*/
|
||||
default void setFlags(TraceMemoryFlag... flags) {
|
||||
setFlags(Arrays.asList(flags));
|
||||
@ -191,12 +220,14 @@ public interface TraceMemoryRegion extends TraceUniqueObject {
|
||||
/**
|
||||
* Add the given flags, e.g., permissions, to this region
|
||||
*
|
||||
* @see #setFlags(Collection)
|
||||
* @param flags the flags
|
||||
*/
|
||||
void addFlags(Collection<TraceMemoryFlag> flags);
|
||||
|
||||
/**
|
||||
* @see #addFlags(Collection)
|
||||
* Add the given flags, e.g., permissions, to this region
|
||||
*
|
||||
* @param flags the flags
|
||||
*/
|
||||
default void addFlags(TraceMemoryFlag... flags) {
|
||||
addFlags(Arrays.asList(flags));
|
||||
@ -205,12 +236,14 @@ public interface TraceMemoryRegion extends TraceUniqueObject {
|
||||
/**
|
||||
* Remove the given flags, e.g., permissions, from this region
|
||||
*
|
||||
* @see #setFlags(Collection)
|
||||
* @param flags the flags
|
||||
*/
|
||||
void clearFlags(Collection<TraceMemoryFlag> flags);
|
||||
|
||||
/**
|
||||
* @see #clearFlags(Collection)
|
||||
* Remove the given flags, e.g., permissions, from this region
|
||||
*
|
||||
* @param flags the flags
|
||||
*/
|
||||
default void clearFlags(TraceMemoryFlag... flags) {
|
||||
clearFlags(Arrays.asList(flags));
|
||||
@ -249,7 +282,7 @@ public interface TraceMemoryRegion extends TraceUniqueObject {
|
||||
/**
|
||||
* Add or clear the {@link TraceMemoryFlag#WRITE} flag
|
||||
*
|
||||
* @param read true to add, false to clear
|
||||
* @param write true to add, false to clear
|
||||
*/
|
||||
default void setWrite(boolean write) {
|
||||
if (write) {
|
||||
@ -272,7 +305,7 @@ public interface TraceMemoryRegion extends TraceUniqueObject {
|
||||
/**
|
||||
* Add or clear the {@link TraceMemoryFlag#EXECUTE} flag
|
||||
*
|
||||
* @param read true to add, false to clear
|
||||
* @param execute true to add, false to clear
|
||||
*/
|
||||
default void setExecute(boolean execute) {
|
||||
if (execute) {
|
||||
@ -295,7 +328,7 @@ public interface TraceMemoryRegion extends TraceUniqueObject {
|
||||
/**
|
||||
* Add or clear the {@link TraceMemoryFlag#VOLATILE} flag
|
||||
*
|
||||
* @param read true to add, false to clear
|
||||
* @param vol true to add, false to clear
|
||||
*/
|
||||
default void setVolatile(boolean vol) {
|
||||
if (vol) {
|
||||
@ -319,4 +352,18 @@ public interface TraceMemoryRegion extends TraceUniqueObject {
|
||||
* Delete this region from the trace
|
||||
*/
|
||||
void delete();
|
||||
|
||||
/**
|
||||
* Check if the region is valid at the given snapshot
|
||||
*
|
||||
* <p>
|
||||
* In object mode, a region's life may be disjoint, so checking if the snap occurs between
|
||||
* creation and destruction is not quite sufficient. This method encapsulates validity. In
|
||||
* object mode, it checks that the region object has a canonical parent at the given snapshot.
|
||||
* In table mode, it checks that the lifespan contains the snap.
|
||||
*
|
||||
* @param snap the snapshot key
|
||||
* @return true if valid, false if not
|
||||
*/
|
||||
boolean isValid(long snap);
|
||||
}
|
||||
|
@ -66,6 +66,7 @@ public interface TraceThread extends TraceUniqueObject {
|
||||
*
|
||||
* @param creationSnap the creation snap, or {@link Long#MIN_VALUE} for "since the beginning of
|
||||
* time"
|
||||
* @throws DuplicateNameException if extending the thread's life would cause a naming conflict
|
||||
*/
|
||||
void setCreationSnap(long creationSnap) throws DuplicateNameException;
|
||||
|
||||
@ -81,6 +82,7 @@ public interface TraceThread extends TraceUniqueObject {
|
||||
*
|
||||
* @param destructionSnap the destruction snap, or {@link Long#MAX_VALUE} for "to the end of
|
||||
* time"
|
||||
* @throws DuplicateNameException if extending the thread's life would cause a naming conflict
|
||||
*/
|
||||
void setDestructionSnap(long destructionSnap) throws DuplicateNameException;
|
||||
|
||||
@ -144,4 +146,18 @@ public interface TraceThread extends TraceUniqueObject {
|
||||
* Delete this thread from the trace
|
||||
*/
|
||||
void delete();
|
||||
|
||||
/**
|
||||
* Check if the thread is valid at the given snapshot
|
||||
*
|
||||
* <p>
|
||||
* In object mode, a thread's life may be disjoint, so checking if the snap occurs between
|
||||
* creation and destruction is not quite sufficient. This method encapsulates validity. In
|
||||
* object mode, it checks that the thread object has a canonical parent at the given snapshot.
|
||||
* In table mode, it checks that the lifespan contains the snap.
|
||||
*
|
||||
* @param snap the snapshot key
|
||||
* @return true if valid, false if not
|
||||
*/
|
||||
boolean isValid(long snap);
|
||||
}
|
||||
|
@ -20,6 +20,8 @@ import static org.junit.Assert.*;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hamcrest.BaseMatcher;
|
||||
import org.hamcrest.Description;
|
||||
import org.junit.*;
|
||||
|
||||
import db.Transaction;
|
||||
@ -257,14 +259,38 @@ public class DBTraceBreakpointManagerTest extends AbstractGhidraHeadlessIntegrat
|
||||
assertEquals("WinMain", breakMain.getComment());
|
||||
}
|
||||
|
||||
protected static class InvalidBreakpointMatcher extends BaseMatcher<TraceBreakpoint> {
|
||||
private final long snap;
|
||||
|
||||
public InvalidBreakpointMatcher(long snap) {
|
||||
this.snap = snap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Object actual) {
|
||||
return actual == null || actual instanceof TraceBreakpoint bpt && !bpt.isValid(snap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("An invalid or null breakpoint");
|
||||
}
|
||||
}
|
||||
|
||||
protected static InvalidBreakpointMatcher invalidBreakpoint(long snap) {
|
||||
return new InvalidBreakpointMatcher(snap);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDelete() throws Exception {
|
||||
addBreakpoints();
|
||||
assertEquals(breakMain, breakpointManager.getPlacedBreakpointByPath(0, "Breakpoints[0]"));
|
||||
try (Transaction tx = b.startTransaction()) {
|
||||
breakMain.delete();
|
||||
assertNull(breakpointManager.getPlacedBreakpointByPath(0, "Breakpoints[0]"));
|
||||
assertThat(breakpointManager.getPlacedBreakpointByPath(0, "Breakpoints[0]"),
|
||||
invalidBreakpoint(0));
|
||||
}
|
||||
assertNull(breakpointManager.getPlacedBreakpointByPath(0, "Breakpoints[0]"));
|
||||
assertThat(breakpointManager.getPlacedBreakpointByPath(0, "Breakpoints[0]"),
|
||||
invalidBreakpoint(0));
|
||||
}
|
||||
}
|
||||
|
@ -15,12 +15,13 @@
|
||||
*/
|
||||
package ghidra.trace.database.memory;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hamcrest.BaseMatcher;
|
||||
import org.hamcrest.Description;
|
||||
import org.junit.*;
|
||||
|
||||
import db.Transaction;
|
||||
@ -79,6 +80,29 @@ public abstract class AbstractDBTraceMemoryManagerRegionsTest
|
||||
assertEquals(Set.of(region), Set.copyOf(memory.getAllRegions()));
|
||||
}
|
||||
|
||||
protected static class InvalidRegionMatcher extends BaseMatcher<TraceMemoryRegion> {
|
||||
private final long snap;
|
||||
|
||||
public InvalidRegionMatcher(long snap) {
|
||||
this.snap = snap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Object actual) {
|
||||
return actual == null ||
|
||||
actual instanceof TraceMemoryRegion region && !region.isValid(snap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("An invalid or null region");
|
||||
}
|
||||
}
|
||||
|
||||
protected static InvalidRegionMatcher invalidRegion(long snap) {
|
||||
return new InvalidRegionMatcher(snap);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetLiveRegionByPath() throws Exception {
|
||||
assertNull(memory.getLiveRegionByPath(0, "Regions[0x1000]"));
|
||||
@ -90,8 +114,8 @@ public abstract class AbstractDBTraceMemoryManagerRegionsTest
|
||||
}
|
||||
|
||||
assertEquals(region, memory.getLiveRegionByPath(0, "Regions[0x1000]"));
|
||||
assertNull(memory.getLiveRegionByPath(0, "Regions[0x1001]"));
|
||||
assertNull(memory.getLiveRegionByPath(-1, "Regions[0x1000]"));
|
||||
assertThat(memory.getLiveRegionByPath(0, "Regions[0x1001]"), invalidRegion(0));
|
||||
assertThat(memory.getLiveRegionByPath(-1, "Regions[0x1000]"), invalidRegion(-1));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -19,6 +19,8 @@ import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.hamcrest.BaseMatcher;
|
||||
import org.hamcrest.Description;
|
||||
import org.junit.*;
|
||||
|
||||
import db.Transaction;
|
||||
@ -86,6 +88,28 @@ public class DBTraceThreadManagerTest extends AbstractGhidraHeadlessIntegrationT
|
||||
assertEquals(Set.of(thread2), Set.copyOf(threadManager.getThreadsByPath("Threads[2]")));
|
||||
}
|
||||
|
||||
protected static class InvalidThreadMatcher extends BaseMatcher<TraceThread> {
|
||||
private final long snap;
|
||||
|
||||
public InvalidThreadMatcher(long snap) {
|
||||
this.snap = snap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Object actual) {
|
||||
return actual == null || actual instanceof TraceThread thread && !thread.isValid(snap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("An invalid or null thread");
|
||||
}
|
||||
}
|
||||
|
||||
protected static InvalidThreadMatcher invalidThread(long snap) {
|
||||
return new InvalidThreadMatcher(snap);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLiveThreadByPath() throws Exception {
|
||||
assertNull(threadManager.getLiveThreadByPath(0, "Threads[1]"));
|
||||
@ -95,8 +119,8 @@ public class DBTraceThreadManagerTest extends AbstractGhidraHeadlessIntegrationT
|
||||
assertEquals(thread2, threadManager.getLiveThreadByPath(0, "Threads[2]"));
|
||||
assertEquals(thread2, threadManager.getLiveThreadByPath(10, "Threads[2]"));
|
||||
assertNull(threadManager.getLiveThreadByPath(0, "Threads[3]"));
|
||||
assertNull(threadManager.getLiveThreadByPath(-1, "Threads[2]"));
|
||||
assertNull(threadManager.getLiveThreadByPath(11, "Threads[2]"));
|
||||
assertThat(threadManager.getLiveThreadByPath(-1, "Threads[2]"), invalidThread(-1));
|
||||
assertThat(threadManager.getLiveThreadByPath(11, "Threads[2]"), invalidThread(11));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -38,6 +38,8 @@ import ghidra.util.classfinder.ClassSearcher;
|
||||
* <p>
|
||||
* For a complete example of a p-code emulator, see {@link PcodeEmulator}. For an alternative
|
||||
* implementation incorporating an abstract piece, see the Taint Analyzer.
|
||||
*
|
||||
* @param <T> the type of objects in the machine's state
|
||||
*/
|
||||
public abstract class AbstractPcodeMachine<T> implements PcodeMachine<T> {
|
||||
|
||||
|
@ -198,7 +198,12 @@ public interface PcodeMachine<T> {
|
||||
/**
|
||||
* Set the suspension state of the machine
|
||||
*
|
||||
* <p>
|
||||
* This does not simply suspend all threads, but sets a machine-wide flag. A thread is suspended
|
||||
* if either the thread's flag is set, or the machine's flag is set.
|
||||
*
|
||||
* @see PcodeThread#setSuspended(boolean)
|
||||
* @param suspended true to suspend the machine, false to let it run
|
||||
*/
|
||||
void setSuspended(boolean suspended);
|
||||
|
||||
@ -206,6 +211,7 @@ public interface PcodeMachine<T> {
|
||||
* Check the suspension state of the machine
|
||||
*
|
||||
* @see PcodeThread#isSuspended()
|
||||
* @return true if suspended
|
||||
*/
|
||||
boolean isSuspended();
|
||||
|
||||
|
@ -15,8 +15,6 @@
|
||||
*/
|
||||
package ghidra.pcode.emu;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
||||
import ghidra.pcode.emu.DefaultPcodeThread.PcodeEmulationLibrary;
|
||||
import ghidra.pcode.exec.*;
|
||||
@ -289,6 +287,9 @@ public interface PcodeThread<T> {
|
||||
* reliable way to halt execution. Note the emulator may halt mid instruction. If this is not
|
||||
* desired, then upon catching the exception, un-suspend the p-code thread and call
|
||||
* {@link #finishInstruction()} or {@link #dropInstruction()}.
|
||||
*
|
||||
* @see PcodeMachine#setSuspended(boolean)
|
||||
* @param suspended true to suspend the machine, false to let it run
|
||||
*/
|
||||
void setSuspended(boolean suspended);
|
||||
|
||||
@ -341,6 +342,7 @@ public interface PcodeThread<T> {
|
||||
* The memory part of this state is shared among all threads in the same machine. See
|
||||
* {@link PcodeMachine#getSharedState()}.
|
||||
*
|
||||
* @return the state
|
||||
*/
|
||||
ThreadPcodeExecutorState<T> getState();
|
||||
|
||||
|
@ -40,6 +40,11 @@ public enum SleighUtils {
|
||||
|
||||
/**
|
||||
* A Sleigh parsing error
|
||||
*
|
||||
* @param header the header / title for the message
|
||||
* @param message the detail message
|
||||
* @param start the character position where the syntax error starts
|
||||
* @param stop the character position where the syntax error ends
|
||||
*/
|
||||
public record SleighParseErrorEntry(String header, String message, int start, int stop) {
|
||||
public String fullMessage() {
|
||||
|
Loading…
Reference in New Issue
Block a user