mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 10:49:34 +02:00
Merge remote-tracking branch 'origin/patch'
This commit is contained in:
commit
d9f13840de
13 changed files with 145 additions and 115 deletions
|
@ -75,6 +75,10 @@ public enum DBTraceUtils {
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(offset, snap);
|
return Objects.hash(offset, snap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isScratch() {
|
||||||
|
return DBTraceUtils.isScratch(snap);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Should this be in by default?
|
// TODO: Should this be in by default?
|
||||||
|
@ -460,6 +464,10 @@ public enum DBTraceUtils {
|
||||||
return a.isConnected(b) && !a.intersection(b).isEmpty();
|
return a.isConnected(b) && !a.intersection(b).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isScratch(long snap) {
|
||||||
|
return snap < 0;
|
||||||
|
}
|
||||||
|
|
||||||
public static <C extends Comparable<C>> int compareRanges(Range<C> a, Range<C> b) {
|
public static <C extends Comparable<C>> int compareRanges(Range<C> a, Range<C> b) {
|
||||||
int result;
|
int result;
|
||||||
if (!a.hasLowerBound() && b.hasLowerBound()) {
|
if (!a.hasLowerBound() && b.hasLowerBound()) {
|
||||||
|
@ -516,6 +524,7 @@ public enum DBTraceUtils {
|
||||||
/**
|
/**
|
||||||
* TODO: Document me
|
* TODO: Document me
|
||||||
*
|
*
|
||||||
|
* <p>
|
||||||
* Only call this method for entries which definitely intersect the given span
|
* Only call this method for entries which definitely intersect the given span
|
||||||
*
|
*
|
||||||
* @param data
|
* @param data
|
||||||
|
|
|
@ -45,7 +45,10 @@ class DBTraceMemoryBlockEntry extends DBAnnotatedObject {
|
||||||
return DBTraceUtils.tableName(TABLE_NAME, space, threadKey, frameLevel);
|
return DBTraceUtils.tableName(TABLE_NAME, space, threadKey, frameLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@DBAnnotatedField(column = LOCATION_COLUMN_NAME, indexed = true, codec = OffsetThenSnapDBFieldCodec.class)
|
@DBAnnotatedField(
|
||||||
|
column = LOCATION_COLUMN_NAME,
|
||||||
|
indexed = true,
|
||||||
|
codec = OffsetThenSnapDBFieldCodec.class)
|
||||||
private OffsetSnap location;
|
private OffsetSnap location;
|
||||||
@DBAnnotatedField(column = BUFFER_COLUMN_NAME)
|
@DBAnnotatedField(column = BUFFER_COLUMN_NAME)
|
||||||
private long bufferKey = -1;
|
private long bufferKey = -1;
|
||||||
|
@ -73,6 +76,10 @@ class DBTraceMemoryBlockEntry extends DBAnnotatedObject {
|
||||||
return location.snap;
|
return location.snap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isScratch() {
|
||||||
|
return DBTraceUtils.isScratch(location.snap);
|
||||||
|
}
|
||||||
|
|
||||||
private int getBlockNumber() {
|
private int getBlockNumber() {
|
||||||
return Byte.toUnsignedInt(blockNum);
|
return Byte.toUnsignedInt(blockNum);
|
||||||
}
|
}
|
||||||
|
@ -82,6 +89,8 @@ class DBTraceMemoryBlockEntry extends DBAnnotatedObject {
|
||||||
assert loc.snap > location.snap;
|
assert loc.snap > location.snap;
|
||||||
DBTraceMemoryBlockEntry cp = space.blockStore.create();
|
DBTraceMemoryBlockEntry cp = space.blockStore.create();
|
||||||
cp.setLoc(loc);
|
cp.setLoc(loc);
|
||||||
|
space.blockCacheMostRecent.clear();
|
||||||
|
space.blockCacheMostRecent.put(loc, cp);
|
||||||
DBTraceMemoryBufferEntry myBuf = findAssignedBuffer();
|
DBTraceMemoryBufferEntry myBuf = findAssignedBuffer();
|
||||||
if (myBuf == null) {
|
if (myBuf == null) {
|
||||||
return cp;
|
return cp;
|
||||||
|
@ -134,11 +143,11 @@ class DBTraceMemoryBlockEntry extends DBAnnotatedObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected DBTraceMemoryBufferEntry findFreeBufferInFuture() throws IOException {
|
protected DBTraceMemoryBufferEntry findFreeBufferInFuture() throws IOException {
|
||||||
DBTraceMemoryBlockEntry prev = space.findSoonestBlockEntry(location, false);
|
DBTraceMemoryBlockEntry next = space.findSoonestBlockEntry(location, false);
|
||||||
if (prev == null) {
|
if (next == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return findFreeBuffer(prev);
|
return findFreeBuffer(next);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected DBTraceMemoryBufferEntry findFreeBuffer() throws IOException {
|
protected DBTraceMemoryBufferEntry findFreeBuffer() throws IOException {
|
||||||
|
|
|
@ -86,7 +86,7 @@ public class DBTraceMemorySpace implements Unfinished, TraceMemorySpace, DBTrace
|
||||||
protected final DBCachedObjectStore<DBTraceMemoryBufferEntry> bufferStore;
|
protected final DBCachedObjectStore<DBTraceMemoryBufferEntry> bufferStore;
|
||||||
protected final DBCachedObjectStore<DBTraceMemoryBlockEntry> blockStore;
|
protected final DBCachedObjectStore<DBTraceMemoryBlockEntry> blockStore;
|
||||||
protected final DBCachedObjectIndex<OffsetSnap, DBTraceMemoryBlockEntry> blocksByOffset;
|
protected final DBCachedObjectIndex<OffsetSnap, DBTraceMemoryBlockEntry> blocksByOffset;
|
||||||
protected final Map<OffsetSnap, DBTraceMemoryBlockEntry> blockCache = CacheBuilder
|
protected final Map<OffsetSnap, DBTraceMemoryBlockEntry> blockCacheMostRecent = CacheBuilder
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.removalListener(this::blockCacheEntryRemoved)
|
.removalListener(this::blockCacheEntryRemoved)
|
||||||
.maximumSize(10)
|
.maximumSize(10)
|
||||||
|
@ -483,7 +483,7 @@ public class DBTraceMemorySpace implements Unfinished, TraceMemorySpace, DBTrace
|
||||||
if (!inclusive) {
|
if (!inclusive) {
|
||||||
loc = new OffsetSnap(loc.offset, loc.snap - 1);
|
loc = new OffsetSnap(loc.offset, loc.snap - 1);
|
||||||
}
|
}
|
||||||
ent = blockCache.get(loc);
|
ent = blockCacheMostRecent.get(loc);
|
||||||
if (ent != null) {
|
if (ent != null) {
|
||||||
return ent;
|
return ent;
|
||||||
}
|
}
|
||||||
|
@ -492,13 +492,26 @@ public class DBTraceMemorySpace implements Unfinished, TraceMemorySpace, DBTrace
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
ent = it.next();
|
ent = it.next();
|
||||||
if (ent.getOffset() != loc.offset) {
|
if (ent.getOffset() != loc.offset || ent.isScratch() != loc.isScratch()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
blockCache.put(loc, ent);
|
blockCacheMostRecent.put(loc, ent);
|
||||||
return ent;
|
return ent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locate the soonest block entry for the given offset-snap pair
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* To qualify, the entry must have a snap greater than (or optionally equal to) that given and
|
||||||
|
* an offset exactly equal to that given. That is, it is the earliest in time, but most follow
|
||||||
|
* the given snap. Additionally, if the given snap is in scratch space, the found entry must
|
||||||
|
* also be in scratch space.
|
||||||
|
*
|
||||||
|
* @param loc the offset-snap pair
|
||||||
|
* @param inclusive true to allow equal snap
|
||||||
|
* @return the found entry, or null
|
||||||
|
*/
|
||||||
protected DBTraceMemoryBlockEntry findSoonestBlockEntry(OffsetSnap loc, boolean inclusive) {
|
protected DBTraceMemoryBlockEntry findSoonestBlockEntry(OffsetSnap loc, boolean inclusive) {
|
||||||
Iterator<DBTraceMemoryBlockEntry> it;
|
Iterator<DBTraceMemoryBlockEntry> it;
|
||||||
if (inclusive) {
|
if (inclusive) {
|
||||||
|
@ -512,7 +525,7 @@ public class DBTraceMemorySpace implements Unfinished, TraceMemorySpace, DBTrace
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
DBTraceMemoryBlockEntry next = it.next();
|
DBTraceMemoryBlockEntry next = it.next();
|
||||||
if (next.getOffset() != loc.offset) {
|
if (next.getOffset() != loc.offset || next.isScratch() != loc.isScratch()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return next;
|
return next;
|
||||||
|
@ -541,19 +554,19 @@ public class DBTraceMemorySpace implements Unfinished, TraceMemorySpace, DBTrace
|
||||||
}
|
}
|
||||||
ent = ent.copy(loc);
|
ent = ent.copy(loc);
|
||||||
ent.setBytes(buf, dstOffset, maxLen);
|
ent.setBytes(buf, dstOffset, maxLen);
|
||||||
blockCache.put(loc, ent);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// (1) or (2a)
|
// (1) or (2b)
|
||||||
ent = blockStore.create();
|
ent = blockStore.create();
|
||||||
ent.setLoc(loc);
|
ent.setLoc(loc);
|
||||||
|
blockCacheMostRecent.clear();
|
||||||
|
blockCacheMostRecent.put(loc, ent);
|
||||||
if (ent.cmpBytes(buf, dstOffset, maxLen) == 0) {
|
if (ent.cmpBytes(buf, dstOffset, maxLen) == 0) {
|
||||||
// Keep the entry, but don't allocate storage in a buffer
|
// Keep the entry, but don't allocate storage in a buffer
|
||||||
buf.position(buf.position() + maxLen);
|
buf.position(buf.position() + maxLen);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ent.setBytes(buf, dstOffset, maxLen);
|
ent.setBytes(buf, dstOffset, maxLen);
|
||||||
blockCache.put(loc, ent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static class OutSnap {
|
protected static class OutSnap {
|
||||||
|
@ -568,13 +581,14 @@ public class DBTraceMemorySpace implements Unfinished, TraceMemorySpace, DBTrace
|
||||||
OutSnap lastSnap, Set<TraceAddressSnapRange> changed) throws IOException {
|
OutSnap lastSnap, Set<TraceAddressSnapRange> changed) throws IOException {
|
||||||
// NOTE: Do not leave the buffer advanced from here
|
// NOTE: Do not leave the buffer advanced from here
|
||||||
int pos = buf.position();
|
int pos = buf.position();
|
||||||
|
// exclusive?
|
||||||
Iterator<DBTraceMemoryBlockEntry> it =
|
Iterator<DBTraceMemoryBlockEntry> it =
|
||||||
blocksByOffset.tail(new OffsetSnap(loc.offset, loc.snap + 1), true).values().iterator(); // exclusive
|
blocksByOffset.tail(new OffsetSnap(loc.offset, loc.snap + 1), true).values().iterator();
|
||||||
AddressSet remaining = new AddressSet(space.getAddress(loc.offset + dstOffset),
|
AddressSet remaining = new AddressSet(space.getAddress(loc.offset + dstOffset),
|
||||||
space.getAddress(loc.offset + dstOffset + maxLen - 1));
|
space.getAddress(loc.offset + dstOffset + maxLen - 1));
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
DBTraceMemoryBlockEntry next = it.next();
|
DBTraceMemoryBlockEntry next = it.next();
|
||||||
if (next.getOffset() != loc.offset) {
|
if (next.getOffset() != loc.offset || next.isScratch() != loc.isScratch()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
AddressSetView withState =
|
AddressSetView withState =
|
||||||
|
@ -892,6 +906,26 @@ public class DBTraceMemorySpace implements Unfinished, TraceMemorySpace, DBTrace
|
||||||
return BLOCK_SIZE;
|
return BLOCK_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean isCross(long lower, long upper) {
|
||||||
|
return lower < 0 && upper >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine the truncation snap if the given span and range include byte changes
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Code units do not understand or accommodate changes in time, so the underlying bytes of the
|
||||||
|
* unit must be the same throughout its lifespan. Typically, units are placed with a desired
|
||||||
|
* creation snap, and then its life is extended into the future opportunistically. Thus, when
|
||||||
|
* truncating, we desire to keep the start snap, then search for the soonest byte change within
|
||||||
|
* the desired lifespan. Furthermore, we generally don't permit a unit to exist in both record
|
||||||
|
* and scratch spaces, i.e., it cannot span both the -1 and 0 snaps.
|
||||||
|
*
|
||||||
|
* @param span the desired lifespan
|
||||||
|
* @param range the address range covered
|
||||||
|
* @return the first snap that should be excluded, or {@link Long#MIN_VALUE} to indicate no
|
||||||
|
* change.
|
||||||
|
*/
|
||||||
public long getFirstChange(Range<Long> span, AddressRange range) {
|
public long getFirstChange(Range<Long> span, AddressRange range) {
|
||||||
assertInSpace(range);
|
assertInSpace(range);
|
||||||
long lower = DBTraceUtils.lowerEndpoint(span);
|
long lower = DBTraceUtils.lowerEndpoint(span);
|
||||||
|
@ -899,21 +933,24 @@ public class DBTraceMemorySpace implements Unfinished, TraceMemorySpace, DBTrace
|
||||||
if (lower == upper) {
|
if (lower == upper) {
|
||||||
return Long.MIN_VALUE;
|
return Long.MIN_VALUE;
|
||||||
}
|
}
|
||||||
Range<Long> fwdOne = DBTraceUtils.toRange(lower + 1, upper);
|
boolean cross = isCross(lower, upper);
|
||||||
|
if (cross && lower == -1) {
|
||||||
|
return 0; // Avoid reversal of range end points.
|
||||||
|
}
|
||||||
|
Range<Long> fwdOne = DBTraceUtils.toRange(lower + 1, cross ? -1 : upper);
|
||||||
ByteBuffer buf1 = ByteBuffer.allocate(BLOCK_SIZE);
|
ByteBuffer buf1 = ByteBuffer.allocate(BLOCK_SIZE);
|
||||||
ByteBuffer buf2 = ByteBuffer.allocate(BLOCK_SIZE);
|
ByteBuffer buf2 = ByteBuffer.allocate(BLOCK_SIZE);
|
||||||
try (LockHold hold = LockHold.lock(lock.readLock())) {
|
try (LockHold hold = LockHold.lock(lock.readLock())) {
|
||||||
for (TraceAddressSnapRange tasr : stateMapSpace.reduce(
|
for (TraceAddressSnapRange tasr : stateMapSpace.reduce(
|
||||||
TraceAddressSnapRangeQuery.intersecting(range, fwdOne)
|
TraceAddressSnapRangeQuery.intersecting(range, fwdOne)
|
||||||
.starting(
|
.starting(Rectangle2DDirection.BOTTOMMOST))
|
||||||
Rectangle2DDirection.BOTTOMMOST))
|
|
||||||
.orderedKeys()) {
|
.orderedKeys()) {
|
||||||
AddressRange toExamine = range.intersect(tasr.getRange());
|
AddressRange toExamine = range.intersect(tasr.getRange());
|
||||||
if (doCheckBytesChanged(tasr.getY1(), toExamine, buf1, buf2)) {
|
if (doCheckBytesChanged(tasr.getY1(), toExamine, buf1, buf2)) {
|
||||||
return tasr.getY1();
|
return tasr.getY1();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Long.MIN_VALUE;
|
return cross ? 0 : Long.MIN_VALUE;
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
blockStore.dbError(e);
|
blockStore.dbError(e);
|
||||||
|
@ -936,7 +973,8 @@ public class DBTraceMemorySpace implements Unfinished, TraceMemorySpace, DBTrace
|
||||||
getBytes(snap, start, oldBytes);
|
getBytes(snap, start, oldBytes);
|
||||||
// New in the sense that they're about to replace the old bytes
|
// New in the sense that they're about to replace the old bytes
|
||||||
ByteBuffer newBytes = ByteBuffer.allocate(len);
|
ByteBuffer newBytes = ByteBuffer.allocate(len);
|
||||||
if (snap != 0) {
|
// NB. Don't want to wrap to Long.MAX_VALUE, but also don't want to read from scratch
|
||||||
|
if (snap != 0 && snap != Long.MIN_VALUE) {
|
||||||
getBytes(snap - 1, start, newBytes);
|
getBytes(snap - 1, start, newBytes);
|
||||||
newBytes.flip();
|
newBytes.flip();
|
||||||
}
|
}
|
||||||
|
@ -991,7 +1029,7 @@ public class DBTraceMemorySpace implements Unfinished, TraceMemorySpace, DBTrace
|
||||||
stateMapSpace.invalidateCache();
|
stateMapSpace.invalidateCache();
|
||||||
bufferStore.invalidateCache();
|
bufferStore.invalidateCache();
|
||||||
blockStore.invalidateCache();
|
blockStore.invalidateCache();
|
||||||
blockCache.clear();
|
blockCacheMostRecent.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -201,6 +201,24 @@ public class DBTraceCodeManagerTest extends AbstractGhidraHeadlessIntegrationTes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddInstructionInScratch() throws CodeUnitInsertionException {
|
||||||
|
try (UndoableTransaction tid = b.startTransaction()) {
|
||||||
|
b.trace.getMemoryManager().putBytes(-5L, b.addr(0x4001), b.buf(0xaa));
|
||||||
|
TraceInstruction i4000 =
|
||||||
|
b.addInstruction(-10, b.addr(0x4000), b.language, b.buf(0xf4, 0));
|
||||||
|
assertEquals(Range.closed(-10L, -6L), i4000.getLifespan());
|
||||||
|
|
||||||
|
TraceInstruction i4004 =
|
||||||
|
b.addInstruction(-1, b.addr(0x4004), b.language, b.buf(0xf4, 0));
|
||||||
|
assertEquals(Range.closed(-1L, -1L), i4004.getLifespan());
|
||||||
|
|
||||||
|
TraceInstruction i4008 =
|
||||||
|
b.addInstruction(-10, b.addr(0x4008), b.language, b.buf(0xf4, 0));
|
||||||
|
assertEquals(Range.closed(-10L, -1L), i4008.getLifespan());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPutBytesTruncatesInstruction() throws CodeUnitInsertionException {
|
public void testPutBytesTruncatesInstruction() throws CodeUnitInsertionException {
|
||||||
try (UndoableTransaction tid = b.startTransaction()) {
|
try (UndoableTransaction tid = b.startTransaction()) {
|
||||||
|
|
|
@ -708,6 +708,21 @@ public abstract class AbstractDBTraceMemoryManagerTest
|
||||||
assertArrayEquals(arr(0, 0, 9, 10, 5, 6, 7, 8, 3, 4, 17, 18, 0, 0), read.array());
|
assertArrayEquals(arr(0, 0, 9, 10, 5, 6, 7, 8, 3, 4, 17, 18, 0, 0), read.array());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetBytesCrossScratch() {
|
||||||
|
try (UndoableTransaction tid = b.startTransaction()) {
|
||||||
|
assertEquals(4, memory.putBytes(Long.MIN_VALUE, b.addr(0x4000), buf(1, 2, 3, 4)));
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteBuffer read = buf(-1, -1, -1, -1);
|
||||||
|
assertEquals(4, memory.getBytes(1, b.addr(0x4000), read));
|
||||||
|
assertArrayEquals(arr(-1, -1, -1, -1), read.array());
|
||||||
|
|
||||||
|
read.position(0);
|
||||||
|
assertEquals(4, memory.getBytes(-1, b.addr(0x4000), read));
|
||||||
|
assertArrayEquals(arr(1, 2, 3, 4), read.array());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPutBytesPackGetBytes() {
|
public void testPutBytesPackGetBytes() {
|
||||||
try (UndoableTransaction tid = b.startTransaction()) {
|
try (UndoableTransaction tid = b.startTransaction()) {
|
||||||
|
|
|
@ -57,20 +57,10 @@ public class CodeBrowserSelectionPlugin extends Plugin {
|
||||||
|
|
||||||
private static final String SELECT_GROUP = "Select Group";
|
private static final String SELECT_GROUP = "Select Group";
|
||||||
private static final String SELECTION_LIMIT_OPTION_NAME = "Table From Selection Limit";
|
private static final String SELECTION_LIMIT_OPTION_NAME = "Table From Selection Limit";
|
||||||
private static final int DEFAULT_TABLE_LIMIT = 20000;
|
|
||||||
|
|
||||||
public CodeBrowserSelectionPlugin(PluginTool tool) {
|
public CodeBrowserSelectionPlugin(PluginTool tool) {
|
||||||
super(tool);
|
super(tool);
|
||||||
createActions();
|
createActions();
|
||||||
registerOptions();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void registerOptions() {
|
|
||||||
ToolOptions toolOptions = tool.getOptions(ToolConstants.TOOL_OPTIONS);
|
|
||||||
toolOptions.registerOption(SELECTION_LIMIT_OPTION_NAME, DEFAULT_TABLE_LIMIT,
|
|
||||||
new HelpLocation("CodeBrowserPlugin", "Selection_Table"),
|
|
||||||
"The maximum number of code units to include when creating a table from " +
|
|
||||||
"a selection in the Listing");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createActions() {
|
private void createActions() {
|
||||||
|
@ -126,14 +116,14 @@ public class CodeBrowserSelectionPlugin extends Plugin {
|
||||||
Msg.showWarn(this, null, "No Table Service", "Please add the TableServicePlugin.");
|
Msg.showWarn(this, null, "No Table Service", "Please add the TableServicePlugin.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Program program = componentProvider.getProgram();
|
Program program = componentProvider.getProgram();
|
||||||
Listing listing = program.getListing();
|
Listing listing = program.getListing();
|
||||||
|
|
||||||
ProgramSelection selection = componentProvider.getSelection();
|
ProgramSelection selection = componentProvider.getSelection();
|
||||||
CodeUnitIterator codeUnits = listing.getCodeUnits(selection, true);
|
CodeUnitIterator codeUnits = listing.getCodeUnits(selection, true);
|
||||||
if (!codeUnits.hasNext()) {
|
if (!codeUnits.hasNext()) {
|
||||||
tool.setStatusInfo(
|
tool.setStatusInfo(
|
||||||
"Unable to create table from selection: no " + "code units in selection");
|
"Unable to create table from selection: no code units in selection");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,7 +141,6 @@ public class CodeBrowserSelectionPlugin extends Plugin {
|
||||||
|
|
||||||
CodeUnitFromSelectionTableModelLoader loader =
|
CodeUnitFromSelectionTableModelLoader loader =
|
||||||
new CodeUnitFromSelectionTableModelLoader(iterator, selection);
|
new CodeUnitFromSelectionTableModelLoader(iterator, selection);
|
||||||
|
|
||||||
return new CustomLoadingAddressTableModel(" - from " + selection.getMinAddress(), tool,
|
return new CustomLoadingAddressTableModel(" - from " + selection.getMinAddress(), tool,
|
||||||
program, loader, null, true);
|
program, loader, null, true);
|
||||||
}
|
}
|
||||||
|
@ -172,8 +161,8 @@ public class CodeBrowserSelectionPlugin extends Plugin {
|
||||||
throws CancelledException {
|
throws CancelledException {
|
||||||
|
|
||||||
ToolOptions options = tool.getOptions(ToolConstants.TOOL_OPTIONS);
|
ToolOptions options = tool.getOptions(ToolConstants.TOOL_OPTIONS);
|
||||||
int resultsLimit =
|
int resultsLimit = options.getInt(GhidraOptions.OPTION_SEARCH_LIMIT,
|
||||||
options.getInt(GhidraOptions.OPTION_SEARCH_LIMIT, DEFAULT_TABLE_LIMIT);
|
PluginConstants.DEFAULT_SEARCH_LIMIT);
|
||||||
|
|
||||||
long size = selection.getNumAddresses();
|
long size = selection.getNumAddresses();
|
||||||
monitor.initialize(size);
|
monitor.initialize(size);
|
||||||
|
|
|
@ -53,20 +53,27 @@ import ghidra.program.util.ProgramSelection;
|
||||||
)
|
)
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
public final class GoToServicePlugin extends ProgramPlugin {
|
public final class GoToServicePlugin extends ProgramPlugin {
|
||||||
|
|
||||||
private GoToServiceImpl gotoService;
|
private GoToServiceImpl gotoService;
|
||||||
private boolean disposed;
|
private boolean disposed;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance of the <CODE>GoToServicePlugin</CODE>
|
* Creates a new instance of the <CODE>GoToServicePlugin</CODE>
|
||||||
* @param plugintool the tool
|
* @param tool the tool
|
||||||
*/
|
*/
|
||||||
public GoToServicePlugin(PluginTool plugintool) {
|
public GoToServicePlugin(PluginTool tool) {
|
||||||
super(plugintool, true, true);
|
super(tool, true, true);
|
||||||
|
|
||||||
|
Options opt = tool.getOptions(PluginConstants.SEARCH_OPTION_NAME);
|
||||||
|
|
||||||
|
// we register this option here, since the other search plugins all depend on this service
|
||||||
|
opt.registerOption(GhidraOptions.OPTION_SEARCH_LIMIT,
|
||||||
|
PluginConstants.DEFAULT_SEARCH_LIMIT, null,
|
||||||
|
"The maximum number of search results.");
|
||||||
|
|
||||||
gotoService = new GoToServiceImpl(this, new DefaultNavigatable());
|
gotoService = new GoToServiceImpl(this, new DefaultNavigatable());
|
||||||
|
|
||||||
registerServiceProvided(GoToService.class, gotoService);
|
registerServiceProvided(GoToService.class, gotoService);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -49,40 +49,19 @@ import ghidra.util.bean.opteditor.OptionsVetoException;
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
public class GoToAddressLabelPlugin extends Plugin implements OptionsChangeListener {
|
public class GoToAddressLabelPlugin extends Plugin implements OptionsChangeListener {
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
|
||||||
// //
|
|
||||||
// Instance fields //
|
|
||||||
// //
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
private GoToAddressLabelDialog goToDialog;
|
|
||||||
private DockingAction action;
|
|
||||||
// configurable properties
|
|
||||||
private int maximumGotoEntries;
|
|
||||||
private boolean cStyleInput;
|
|
||||||
private boolean goToMemory;
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
|
||||||
// //
|
|
||||||
// Class fields and methods //
|
|
||||||
// //
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
private static final int DEFAULT_MAX_GOTO_ENTRIES = 10;
|
private static final int DEFAULT_MAX_GOTO_ENTRIES = 10;
|
||||||
private static final boolean DEFAULT_C_STYLE = false;
|
private static final boolean DEFAULT_C_STYLE = false;
|
||||||
|
|
||||||
/**
|
// remembers the last successful 'go to' entry
|
||||||
* This option controls the Go To dialog's feature that remembers the last successful
|
|
||||||
* go to entry.
|
|
||||||
*/
|
|
||||||
private static final String GO_TO_MEMORY = "Goto Dialog Memory";
|
private static final String GO_TO_MEMORY = "Goto Dialog Memory";
|
||||||
private static final boolean DEFAULT_MEMORY = true;
|
private static final boolean DEFAULT_MEMORY = true;
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
private GoToAddressLabelDialog goToDialog;
|
||||||
// //
|
private DockingAction action;
|
||||||
// Constructor //
|
|
||||||
// //
|
private int maximumGotoEntries;
|
||||||
//////////////////////////////////////////////////////////////////////
|
private boolean cStyleInput;
|
||||||
|
private boolean goToMemory;
|
||||||
|
|
||||||
public GoToAddressLabelPlugin(PluginTool pluginTool) {
|
public GoToAddressLabelPlugin(PluginTool pluginTool) {
|
||||||
super(pluginTool);
|
super(pluginTool);
|
||||||
|
@ -120,17 +99,11 @@ public class GoToAddressLabelPlugin extends Plugin implements OptionsChangeListe
|
||||||
GoToService gotoService = tool.getService(GoToService.class);
|
GoToService gotoService = tool.getService(GoToService.class);
|
||||||
goToDialog = new GoToAddressLabelDialog(gotoService, this);
|
goToDialog = new GoToAddressLabelDialog(gotoService, this);
|
||||||
maximumGotoEntries = DEFAULT_MAX_GOTO_ENTRIES;
|
maximumGotoEntries = DEFAULT_MAX_GOTO_ENTRIES;
|
||||||
getOptions();
|
initOptions();
|
||||||
|
|
||||||
tool.addAction(action);
|
tool.addAction(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
|
||||||
// //
|
|
||||||
// Configurable properties
|
|
||||||
// //
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
public final int getMaximumGotoEntries() {
|
public final int getMaximumGotoEntries() {
|
||||||
return maximumGotoEntries;
|
return maximumGotoEntries;
|
||||||
}
|
}
|
||||||
|
@ -145,16 +118,6 @@ public class GoToAddressLabelPlugin extends Plugin implements OptionsChangeListe
|
||||||
goToDialog.writeConfigState(saveState);
|
goToDialog.writeConfigState(saveState);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Notification that an option changed.
|
|
||||||
*
|
|
||||||
* @param options options object containing the property that changed
|
|
||||||
* @param group name of the group to which this option is associated,
|
|
||||||
* null if not associated with any group
|
|
||||||
* @param opName name of option that changed
|
|
||||||
* @param oldValue old value of the option
|
|
||||||
* @param newValue new value of the option
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void optionsChanged(ToolOptions options, String opName, Object oldValue,
|
public void optionsChanged(ToolOptions options, String opName, Object oldValue,
|
||||||
Object newValue) {
|
Object newValue) {
|
||||||
|
@ -177,12 +140,6 @@ public class GoToAddressLabelPlugin extends Plugin implements OptionsChangeListe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
|
||||||
// //
|
|
||||||
// Overridden Plugin Methods //
|
|
||||||
// //
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
ToolOptions options = tool.getOptions(ToolConstants.TOOL_OPTIONS);
|
ToolOptions options = tool.getOptions(ToolConstants.TOOL_OPTIONS);
|
||||||
|
@ -191,9 +148,8 @@ public class GoToAddressLabelPlugin extends Plugin implements OptionsChangeListe
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void getOptions() {
|
private void initOptions() {
|
||||||
ToolOptions opt = tool.getOptions(ToolConstants.TOOL_OPTIONS);
|
ToolOptions opt = tool.getOptions(ToolConstants.TOOL_OPTIONS);
|
||||||
// descriptions
|
|
||||||
opt.registerOption(GhidraOptions.OPTION_NUMERIC_FORMATTING, DEFAULT_C_STYLE, null,
|
opt.registerOption(GhidraOptions.OPTION_NUMERIC_FORMATTING, DEFAULT_C_STYLE, null,
|
||||||
"Interpret value entered in the Go To dialog as either hex, " +
|
"Interpret value entered in the Go To dialog as either hex, " +
|
||||||
"octal, or binary number.");
|
"octal, or binary number.");
|
||||||
|
@ -206,7 +162,6 @@ public class GoToAddressLabelPlugin extends Plugin implements OptionsChangeListe
|
||||||
"successful go to input in the combo box of the Go " +
|
"successful go to input in the combo box of the Go " +
|
||||||
"To dialog and will select the " + "value for easy paste replacement.");
|
"To dialog and will select the " + "value for easy paste replacement.");
|
||||||
|
|
||||||
// options
|
|
||||||
maximumGotoEntries =
|
maximumGotoEntries =
|
||||||
opt.getInt(GhidraOptions.OPTION_MAX_GO_TO_ENTRIES, DEFAULT_MAX_GOTO_ENTRIES);
|
opt.getInt(GhidraOptions.OPTION_MAX_GO_TO_ENTRIES, DEFAULT_MAX_GOTO_ENTRIES);
|
||||||
|
|
||||||
|
|
|
@ -93,7 +93,6 @@ public class MemSearchPlugin extends Plugin implements OptionsChangeListener,
|
||||||
private MemSearchDialog searchDialog;
|
private MemSearchDialog searchDialog;
|
||||||
private GoToService goToService;
|
private GoToService goToService;
|
||||||
private int searchLimit;
|
private int searchLimit;
|
||||||
private static int DEFAULT_SEARCH_LIMIT = 500; // Default maximum number of search results.
|
|
||||||
private ImageIcon searchIcon;
|
private ImageIcon searchIcon;
|
||||||
|
|
||||||
private Color defaultHighlightColor;
|
private Color defaultHighlightColor;
|
||||||
|
@ -121,7 +120,7 @@ public class MemSearchPlugin extends Plugin implements OptionsChangeListener,
|
||||||
|
|
||||||
createActions();
|
createActions();
|
||||||
initializeOptionListeners();
|
initializeOptionListeners();
|
||||||
getOptions();
|
loadOptions();
|
||||||
tool.addContextListener(this);
|
tool.addContextListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -383,8 +382,6 @@ public class MemSearchPlugin extends Plugin implements OptionsChangeListener,
|
||||||
opt.registerOption(PluginConstants.AUTO_RESTRICT_SELECTION, true, null,
|
opt.registerOption(PluginConstants.AUTO_RESTRICT_SELECTION, true, null,
|
||||||
"Automactically adjusts memory searches restricted" +
|
"Automactically adjusts memory searches restricted" +
|
||||||
" to the current selection, as selections comes and goes");
|
" to the current selection, as selections comes and goes");
|
||||||
opt.registerOption(GhidraOptions.OPTION_SEARCH_LIMIT, DEFAULT_SEARCH_LIMIT, null,
|
|
||||||
"Number of search hits found before stopping");
|
|
||||||
opt.registerOption(PluginConstants.SEARCH_HIGHLIGHT_NAME, true, null,
|
opt.registerOption(PluginConstants.SEARCH_HIGHLIGHT_NAME, true, null,
|
||||||
"Toggles highlight search results");
|
"Toggles highlight search results");
|
||||||
|
|
||||||
|
@ -400,10 +397,11 @@ public class MemSearchPlugin extends Plugin implements OptionsChangeListener,
|
||||||
opt.addOptionsChangeListener(this);
|
opt.addOptionsChangeListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void getOptions() {
|
private void loadOptions() {
|
||||||
|
|
||||||
Options opt = tool.getOptions(PluginConstants.SEARCH_OPTION_NAME);
|
Options opt = tool.getOptions(PluginConstants.SEARCH_OPTION_NAME);
|
||||||
int newSearchLimit = opt.getInt(GhidraOptions.OPTION_SEARCH_LIMIT, DEFAULT_SEARCH_LIMIT);
|
int newSearchLimit =
|
||||||
|
opt.getInt(GhidraOptions.OPTION_SEARCH_LIMIT, PluginConstants.DEFAULT_SEARCH_LIMIT);
|
||||||
if (newSearchLimit <= 0) {
|
if (newSearchLimit <= 0) {
|
||||||
throw new OptionsVetoException("Search limit must be greater than 0");
|
throw new OptionsVetoException("Search limit must be greater than 0");
|
||||||
}
|
}
|
||||||
|
@ -424,7 +422,7 @@ public class MemSearchPlugin extends Plugin implements OptionsChangeListener,
|
||||||
@Override
|
@Override
|
||||||
public void optionsChanged(ToolOptions options, String optionName, Object oldValue,
|
public void optionsChanged(ToolOptions options, String optionName, Object oldValue,
|
||||||
Object newValue) {
|
Object newValue) {
|
||||||
getOptions();
|
loadOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void updateSelection(NavigatableActionContext context) {
|
protected void updateSelection(NavigatableActionContext context) {
|
||||||
|
|
|
@ -32,7 +32,6 @@ import ghidra.util.task.TaskMonitor;
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractSearchTableModel extends ProgramLocationPreviewTableModel {
|
public abstract class AbstractSearchTableModel extends ProgramLocationPreviewTableModel {
|
||||||
|
|
||||||
private final static int DEFAULT_SEARCH_LIMIT = 500;
|
|
||||||
final static String TITLE = "Text Search";
|
final static String TITLE = "Text Search";
|
||||||
|
|
||||||
protected SearchOptions options;
|
protected SearchOptions options;
|
||||||
|
@ -50,7 +49,8 @@ public abstract class AbstractSearchTableModel extends ProgramLocationPreviewTab
|
||||||
this.set = set;
|
this.set = set;
|
||||||
this.options = options;
|
this.options = options;
|
||||||
Options opt = tool.getOptions(PluginConstants.SEARCH_OPTION_NAME);
|
Options opt = tool.getOptions(PluginConstants.SEARCH_OPTION_NAME);
|
||||||
searchLimit = opt.getInt(GhidraOptions.OPTION_SEARCH_LIMIT, DEFAULT_SEARCH_LIMIT);
|
searchLimit =
|
||||||
|
opt.getInt(GhidraOptions.OPTION_SEARCH_LIMIT, PluginConstants.DEFAULT_SEARCH_LIMIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -91,7 +91,6 @@ public class SearchTextPlugin extends ProgramPlugin implements OptionsChangeList
|
||||||
private static final ImageIcon searchIcon = ResourceManager.loadImage("images/searchm_obj.gif");
|
private static final ImageIcon searchIcon = ResourceManager.loadImage("images/searchm_obj.gif");
|
||||||
|
|
||||||
private static final String DESCRIPTION = "Search program text for string";
|
private static final String DESCRIPTION = "Search program text for string";
|
||||||
private final static int DEFAULT_SEARCH_LIMIT = 500;
|
|
||||||
private final static Highlight[] NO_HIGHLIGHTS = new Highlight[0];
|
private final static Highlight[] NO_HIGHLIGHTS = new Highlight[0];
|
||||||
|
|
||||||
private boolean waitingForSearchAll;
|
private boolean waitingForSearchAll;
|
||||||
|
@ -442,9 +441,6 @@ public class SearchTextPlugin extends ProgramPlugin implements OptionsChangeList
|
||||||
ToolOptions opt = tool.getOptions(PluginConstants.SEARCH_OPTION_NAME);
|
ToolOptions opt = tool.getOptions(PluginConstants.SEARCH_OPTION_NAME);
|
||||||
HelpLocation loc = new HelpLocation(HelpTopics.SEARCH, "HighlightText");
|
HelpLocation loc = new HelpLocation(HelpTopics.SEARCH, "HighlightText");
|
||||||
|
|
||||||
opt.registerOption(GhidraOptions.OPTION_SEARCH_LIMIT, DEFAULT_SEARCH_LIMIT, loc,
|
|
||||||
"Max number of matches on a search that will be displayed.");
|
|
||||||
|
|
||||||
opt.registerOption(PluginConstants.SEARCH_HIGHLIGHT_NAME, true, loc,
|
opt.registerOption(PluginConstants.SEARCH_HIGHLIGHT_NAME, true, loc,
|
||||||
"Determines whether to highlight the matched string for a search in the listing.");
|
"Determines whether to highlight the matched string for a search in the listing.");
|
||||||
opt.registerOption(PluginConstants.SEARCH_HIGHLIGHT_COLOR_NAME,
|
opt.registerOption(PluginConstants.SEARCH_HIGHLIGHT_COLOR_NAME,
|
||||||
|
@ -454,7 +450,8 @@ public class SearchTextPlugin extends ProgramPlugin implements OptionsChangeList
|
||||||
PluginConstants.SEARCH_HIGHLIGHT_COLOR, loc,
|
PluginConstants.SEARCH_HIGHLIGHT_COLOR, loc,
|
||||||
"Color to use for highlighting when the match string occurs at the current address.");
|
"Color to use for highlighting when the match string occurs at the current address.");
|
||||||
|
|
||||||
searchLimit = opt.getInt(GhidraOptions.OPTION_SEARCH_LIMIT, DEFAULT_SEARCH_LIMIT);
|
searchLimit =
|
||||||
|
opt.getInt(GhidraOptions.OPTION_SEARCH_LIMIT, PluginConstants.DEFAULT_SEARCH_LIMIT);
|
||||||
|
|
||||||
doHighlight = opt.getBoolean(PluginConstants.SEARCH_HIGHLIGHT_NAME, true);
|
doHighlight = opt.getBoolean(PluginConstants.SEARCH_HIGHLIGHT_NAME, true);
|
||||||
highlightColor = opt.getColor(PluginConstants.SEARCH_HIGHLIGHT_COLOR_NAME,
|
highlightColor = opt.getColor(PluginConstants.SEARCH_HIGHLIGHT_COLOR_NAME,
|
||||||
|
|
|
@ -71,13 +71,8 @@ public class GoToQuery {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.goToService = goToService;
|
this.goToService = goToService;
|
||||||
this.navigationOptions = navigationOptions;
|
this.navigationOptions = navigationOptions;
|
||||||
Options opt = plugin.getTool().getOptions(PluginConstants.SEARCH_OPTION_NAME);
|
|
||||||
|
|
||||||
if (!opt.contains(GhidraOptions.OPTION_SEARCH_LIMIT)) {
|
Options opt = plugin.getTool().getOptions(PluginConstants.SEARCH_OPTION_NAME);
|
||||||
opt.registerOption(GhidraOptions.OPTION_SEARCH_LIMIT,
|
|
||||||
PluginConstants.DEFAULT_SEARCH_LIMIT, null,
|
|
||||||
"The maximum number of search hits before stopping.");
|
|
||||||
}
|
|
||||||
this.maxHits =
|
this.maxHits =
|
||||||
opt.getInt(GhidraOptions.OPTION_SEARCH_LIMIT, PluginConstants.DEFAULT_SEARCH_LIMIT);
|
opt.getInt(GhidraOptions.OPTION_SEARCH_LIMIT, PluginConstants.DEFAULT_SEARCH_LIMIT);
|
||||||
this.fromAddress = fromAddr;
|
this.fromAddress = fromAddr;
|
||||||
|
@ -496,7 +491,7 @@ public class GoToQuery {
|
||||||
Program program = navigatable.getProgram();
|
Program program = navigatable.getProgram();
|
||||||
SymbolTable symTable = program.getSymbolTable();
|
SymbolTable symTable = program.getSymbolTable();
|
||||||
|
|
||||||
List<Symbol> symbols = new ArrayList<Symbol>();
|
List<Symbol> symbols = new ArrayList<>();
|
||||||
SymbolIterator symbolIterator = symTable.getSymbols(queryData.getQueryString());
|
SymbolIterator symbolIterator = symTable.getSymbols(queryData.getQueryString());
|
||||||
while (symbolIterator.hasNext()) {
|
while (symbolIterator.hasNext()) {
|
||||||
Symbol symbol = symbolIterator.next();
|
Symbol symbol = symbolIterator.next();
|
||||||
|
|
|
@ -66,7 +66,7 @@ import ghidra.util.table.field.LabelTableColumn;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
import util.CollectionUtils;
|
import util.CollectionUtils;
|
||||||
|
|
||||||
public class GoToPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
public class GoToAddressLabelPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
private TestEnv env;
|
private TestEnv env;
|
||||||
private PluginTool tool;
|
private PluginTool tool;
|
||||||
private AddressFactory addrFactory;
|
private AddressFactory addrFactory;
|
Loading…
Add table
Add a link
Reference in a new issue