diff --git a/Ghidra/Debug/Debugger-gadp/src/main/java/ghidra/dbg/gadp/util/AsyncProtobufMessageChannel.java b/Ghidra/Debug/Debugger-gadp/src/main/java/ghidra/dbg/gadp/util/AsyncProtobufMessageChannel.java
index 2f9bd3e797..c1efeafc93 100644
--- a/Ghidra/Debug/Debugger-gadp/src/main/java/ghidra/dbg/gadp/util/AsyncProtobufMessageChannel.java
+++ b/Ghidra/Debug/Debugger-gadp/src/main/java/ghidra/dbg/gadp/util/AsyncProtobufMessageChannel.java
@@ -26,7 +26,7 @@ import com.google.protobuf.*;
import com.google.protobuf.CodedOutputStream.OutOfSpaceException;
import ghidra.async.*;
-import ghidra.comm.util.ByteBufferUtils;
+import ghidra.util.ByteBufferUtils;
import ghidra.util.Msg;
public class AsyncProtobufMessageChannel {
diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProvider.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProvider.java
index cdc6637163..dcf3f6799a 100644
--- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProvider.java
+++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/listing/DebuggerListingProvider.java
@@ -381,10 +381,13 @@ public class DebuggerListingProvider extends CodeViewerProvider implements Listi
protected final ForStaticSyncMappingChangeListener mappingChangeListener =
new ForStaticSyncMappingChangeListener();
+ protected final boolean isMainListing;
+
public DebuggerListingProvider(DebuggerListingPlugin plugin, FormatManager formatManager,
boolean isConnected) {
super(plugin, formatManager, isConnected);
this.plugin = plugin;
+ this.isMainListing = isConnected;
goToDialog = new DebuggerGoToDialog(this);
@@ -420,6 +423,34 @@ public class DebuggerListingProvider extends CodeViewerProvider implements Listi
setHelpLocation(DebuggerResources.HELP_PROVIDER_LISTING);
}
+ @Override
+ public boolean isConnected() {
+ /*
+ * NB. Other plugins ask isConnected meaning the main static listing. We don't want to be
+ * mistaken for it.
+ */
+ return false;
+ }
+
+ /**
+ * Check if this is the main dynamic listing.
+ *
+ *
+ * The method {@link #isConnected()} is not quite the same as this, although the concepts are a
+ * little conflated, since before the debugger, no one else presented a listing that could claim
+ * to be "main" except the "connected" one. Here, we treat "connected" to mean that the address
+ * is synchronized exactly with the other providers. "Main" on the other hand, does not
+ * necessarily have that property, but it is still not a snapshot. It is the main
+ * listing presented by this plugin, and so it has certain unique features. Calling
+ * {@link DebuggerListingPlugin#getConnectedProvider()} will return the main dynamic listing,
+ * despite it not really being "connected."
+ *
+ * @return true if this is the main listing for the plugin.
+ */
+ public boolean isMainListing() {
+ return isMainListing;
+ }
+
@Override
public String getWindowGroup() {
//TODO: Overriding this to align disconnected providers
@@ -428,7 +459,7 @@ public class DebuggerListingProvider extends CodeViewerProvider implements Listi
@Override
public void writeDataState(SaveState saveState) {
- if (!isConnected()) {
+ if (!isMainListing()) {
current.writeDataState(tool, saveState, KEY_DEBUGGER_COORDINATES);
}
super.writeDataState(saveState);
@@ -436,7 +467,7 @@ public class DebuggerListingProvider extends CodeViewerProvider implements Listi
@Override
public void readDataState(SaveState saveState) {
- if (!isConnected()) {
+ if (!isMainListing()) {
DebuggerCoordinates coordinates =
DebuggerCoordinates.readDataState(tool, saveState, KEY_DEBUGGER_COORDINATES, true);
coordinatesActivated(coordinates);
@@ -466,7 +497,7 @@ public class DebuggerListingProvider extends CodeViewerProvider implements Listi
CONFIG_STATE_HANDLER.readConfigState(this, saveState);
actionTrackLocation.setCurrentActionStateByUserData(trackingSpec);
- if (isConnected()) {
+ if (isMainListing()) {
actionSyncToStaticListing.setSelected(syncToStaticListing);
followsCurrentThread = true;
}
@@ -549,7 +580,7 @@ public class DebuggerListingProvider extends CodeViewerProvider implements Listi
this.markerService = markerService;
createNewStaticTrackingMarker();
- if (this.markerService != null && !isConnected()) {
+ if (this.markerService != null && !isMainListing()) {
// NOTE: Connected provider marker listener is taken care of by CodeBrowserPlugin
this.markerService.addChangeListener(markerChangeListener);
}
@@ -735,7 +766,7 @@ public class DebuggerListingProvider extends CodeViewerProvider implements Listi
.onAction(this::activatedGoTo)
.buildAndInstallLocal(this);
- if (isConnected()) {
+ if (isMainListing()) {
actionSyncToStaticListing = new SyncToStaticListingAction();
}
else {
@@ -999,7 +1030,7 @@ public class DebuggerListingProvider extends CodeViewerProvider implements Listi
}
public void setSyncToStaticListing(boolean sync) {
- if (!isConnected()) {
+ if (!isMainListing()) {
throw new IllegalStateException(
"Only the main dynamic listing can be synced to the main static listing");
}
@@ -1018,7 +1049,7 @@ public class DebuggerListingProvider extends CodeViewerProvider implements Listi
}
public void setFollowsCurrentThread(boolean follows) {
- if (isConnected()) {
+ if (isMainListing()) {
throw new IllegalStateException(
"The main dynamic listing always follows the current trace and thread");
}
diff --git a/Ghidra/Debug/Framework-AsyncComm/src/main/java/ghidra/comm/util/ByteBufferUtils.java b/Ghidra/Debug/Framework-AsyncComm/src/main/java/ghidra/comm/util/ByteBufferUtils.java
deleted file mode 100644
index f37a8662c0..0000000000
--- a/Ghidra/Debug/Framework-AsyncComm/src/main/java/ghidra/comm/util/ByteBufferUtils.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/* ###
- * 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.comm.util;
-
-import java.nio.ByteBuffer;
-
-/**
- * Some utilities for manipulating a {@link ByteBuffer}
- */
-public interface ByteBufferUtils {
- /**
- * Resize a write-mode buffer
- *
- * This preserves the buffer contents
- *
- * @param buf the buffer
- * @param capacity the new capacity, greater or equal to the buffer's limit
- * @return the new buffer
- */
- public static ByteBuffer resize(ByteBuffer buf, int capacity) {
- if (capacity < buf.limit()) {
- throw new IllegalArgumentException("New capacity must fit current contents");
- }
- buf.flip();
- ByteBuffer resized = ByteBuffer.allocate(capacity);
- resized.put(buf);
- return resized;
- }
-
- /**
- * Resize a write-mode buffer to twice its current capacity
- *
- * This preserves the buffer contents
- *
- * @param buf the buffer
- * @return the new buffer
- */
- public static ByteBuffer upsize(ByteBuffer buf) {
- return resize(buf, buf.capacity() * 2);
- }
-}
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceCommentAdapter.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceCommentAdapter.java
index 352e529aed..5fae79917a 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceCommentAdapter.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/DBTraceCommentAdapter.java
@@ -34,8 +34,12 @@ import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMap;
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree;
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.AbstractDBTraceAddressSnapRangePropertyMapData;
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery;
+import ghidra.trace.database.space.DBTraceSpaceKey;
import ghidra.trace.database.thread.DBTraceThreadManager;
+import ghidra.trace.model.ImmutableTraceAddressSnapRange;
+import ghidra.trace.model.Trace.TraceCommentChangeType;
import ghidra.trace.model.TraceAddressSnapRange;
+import ghidra.trace.util.TraceChangeRecord;
import ghidra.util.LockHold;
import ghidra.util.database.*;
import ghidra.util.database.annot.*;
@@ -49,7 +53,7 @@ public class DBTraceCommentAdapter
protected static final int MAX_COMMENT_TYPE = CodeUnit.REPEATABLE_COMMENT;
@DBAnnotatedObjectInfo(version = 0)
- protected static class DBTraceCommentEntry
+ public static class DBTraceCommentEntry
extends AbstractDBTraceAddressSnapRangePropertyMapData {
static final String TYPE_COLUMN_NAME = "Type";
static final String COMMENT_COLUMN_NAME = "Comment";
@@ -89,6 +93,10 @@ public class DBTraceCommentAdapter
void setLifespan(Range lifespan) {
super.doSetLifespan(lifespan);
}
+
+ public int getType() {
+ return type;
+ }
}
public DBTraceCommentAdapter(DBHandle dbh, DBOpenMode openMode, ReadWriteLock lock,
@@ -106,10 +114,15 @@ public class DBTraceCommentAdapter
if (commentType < MIN_COMMENT_TYPE || commentType > MAX_COMMENT_TYPE) {
throw new IllegalArgumentException("commentType");
}
+ String oldValue = null;
try (LockHold hold = LockHold.lock(lock.writeLock())) {
for (DBTraceCommentEntry entry : reduce(TraceAddressSnapRangeQuery.intersecting(
new AddressRangeImpl(address, address), lifespan)).values()) {
if (entry.type == commentType) {
+ if (lifespan.hasLowerBound() &&
+ entry.getLifespan().contains(lifespan.lowerEndpoint())) {
+ oldValue = entry.comment;
+ }
makeWay(entry, lifespan);
}
}
@@ -118,6 +131,11 @@ public class DBTraceCommentAdapter
entry.set((byte) commentType, comment);
}
}
+ trace.setChanged(new TraceChangeRecord(
+ TraceCommentChangeType.byType(commentType),
+ DBTraceSpaceKey.create(address.getAddressSpace(), null, 0),
+ new ImmutableTraceAddressSnapRange(address, lifespan),
+ oldValue, comment));
}
public static String commentFromArray(String[] comment) {
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/memory/DBTraceMemorySpace.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/memory/DBTraceMemorySpace.java
index c73708808f..f8caac413f 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/memory/DBTraceMemorySpace.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/memory/DBTraceMemorySpace.java
@@ -15,8 +15,6 @@
*/
package ghidra.trace.database.memory;
-import static ghidra.lifecycle.Unfinished.TODO;
-
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@@ -47,8 +45,8 @@ import ghidra.trace.model.Trace.*;
import ghidra.trace.model.memory.*;
import ghidra.trace.util.TraceChangeRecord;
import ghidra.trace.util.TraceViewportSpanIterator;
-import ghidra.util.LockHold;
-import ghidra.util.MathUtilities;
+import ghidra.util.*;
+import ghidra.util.AddressIteratorAdapter;
import ghidra.util.database.*;
import ghidra.util.database.spatial.rect.Rectangle2DDirection;
import ghidra.util.exception.DuplicateNameException;
@@ -758,10 +756,59 @@ public class DBTraceMemorySpace implements Unfinished, TraceMemorySpace, DBTrace
return len;
}
+ protected Address doFindBytesInRange(long snap, AddressRange range, ByteBuffer data,
+ ByteBuffer mask, boolean forward, TaskMonitor monitor) {
+ int len = data.capacity();
+ AddressRange rangeOfStarts =
+ new AddressRangeImpl(range.getMinAddress(), range.getMaxAddress().subtract(len - 1));
+ ByteBuffer read = ByteBuffer.allocate(len);
+ for (Address addr : AddressIteratorAdapter.forRange(rangeOfStarts, forward)) {
+ monitor.incrementProgress(1);
+ if (monitor.isCancelled()) {
+ return null;
+ }
+ read.clear();
+ int l = getBytes(snap, addr, read);
+ if (l != len) {
+ continue;
+ }
+ if (!ByteBufferUtils.maskedEquals(mask, data, read)) {
+ continue;
+ }
+ return addr;
+ }
+ return null;
+ }
+
@Override
public Address findBytes(long snap, AddressRange range, ByteBuffer data, ByteBuffer mask,
boolean forward, TaskMonitor monitor) {
- return TODO();
+ // ProgramDB uses the naive method with some skipping, so here we go....
+ // TODO: This could be made faster by skipping over non-initialized blocks
+ // TODO: DFA method would be complicated by masks....
+ int len = data.capacity();
+ if (mask != null && mask.capacity() != len) {
+ throw new IllegalArgumentException("data and mask must have same capacity");
+ }
+ if (len == 0 || range.getLength() > 0 && range.getLength() < len) {
+ return null;
+ }
+
+ // TODO: Could do better, but have to worry about viewport, too
+ // This will reduce the search to ranges that have been written at any snap
+ // We could do for this and previous snaps, but that's where the viewport comes in.
+ // TODO: Potentially costly to pre-compute the set concretely
+ AddressSet known = new AddressSet(
+ stateMapSpace.getAddressSetView(Range.all(), s -> s == TraceMemoryState.KNOWN))
+ .intersect(new AddressSet(range));
+ monitor.initialize(known.getNumAddresses());
+ for (AddressRange knownRange : known.getAddressRanges(forward)) {
+ Address found = doFindBytesInRange(snap, knownRange, data, mask, forward, monitor);
+ if (found != null) {
+ return found;
+ }
+ }
+ return null;
}
// TODO: Test this
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 9888c57eea..fe45f80d9f 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
@@ -424,8 +424,10 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV
@Override
public AddressIterator getCommentAddressIterator(int commentType, AddressSetView addrSet,
boolean forward) {
- // TODO Auto-generated method stub
- return null;
+ return new IntersectionAddressSetView(addrSet, program.viewport.unionedAddresses(
+ s -> program.trace.getCommentAdapter()
+ .getAddressSetView(Range.singleton(s), e -> e.getType() == commentType)))
+ .getAddresses(forward);
}
@Override
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewMemory.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewMemory.java
index 76b8d5097f..77ad369a6b 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewMemory.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewMemory.java
@@ -240,8 +240,10 @@ public abstract class AbstractDBTraceProgramViewMemory
ByteBuffer bufBytes = ByteBuffer.wrap(bytes);
ByteBuffer bufMasks = masks == null ? null : ByteBuffer.wrap(masks);
+ Address minAddr = forward ? startAddr : endAddr;
+ Address maxAddr = forward ? endAddr : startAddr;
Iterator it =
- program.getAddressFactory().getAddressSet(startAddr, endAddr).iterator(forward);
+ program.getAddressFactory().getAddressSet(minAddr, maxAddr).iterator(forward);
while (it.hasNext()) {
AddressRange range = it.next();
DBTraceMemorySpace space = memoryManager.getMemorySpace(range.getAddressSpace(), false);
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramView.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramView.java
index 596da292e8..86bea1494a 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramView.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramView.java
@@ -110,6 +110,12 @@ public class DBTraceProgramView implements TraceProgramView {
listenFor(TraceCodeChangeType.FRAGMENT_CHANGED, this::codeFragmentChanged);
listenFor(TraceCodeChangeType.DATA_TYPE_REPLACED, this::codeDataTypeReplaced);
+ listenFor(TraceCommentChangeType.EOL_CHANGED, this::commentEolChanged);
+ listenFor(TraceCommentChangeType.PLATE_CHANGED, this::commentPlateChanged);
+ listenFor(TraceCommentChangeType.POST_CHANGED, this::commentPostChanged);
+ listenFor(TraceCommentChangeType.PRE_CHANGED, this::commentPreChanged);
+ listenFor(TraceCommentChangeType.REPEATABLE_CHANGED, this::commentRepeatableChanged);
+
listenFor(TraceCompositeDataChangeType.ADDED, this::compositeDataAdded);
listenFor(TraceCompositeDataChangeType.LIFESPAN_CHANGED,
this::compositeLifespanChanged);
@@ -328,6 +334,48 @@ public class DBTraceProgramView implements TraceProgramView {
range.getX1(), range.getX2(), null, null, null));
}
+ private void commentChanged(int docrType, TraceAddressSpace space,
+ TraceAddressSnapRange range,
+ String oldValue, String newValue) {
+ DomainObjectEventQueues queues = isVisible(space, range);
+ if (queues == null) {
+ return;
+ }
+ queues.fireEvent(new ProgramChangeRecord(docrType,
+ range.getX1(), range.getX2(), null, oldValue, newValue));
+ }
+
+ private void commentEolChanged(TraceAddressSpace space, TraceAddressSnapRange range,
+ String oldValue, String newValue) {
+ commentChanged(ChangeManager.DOCR_EOL_COMMENT_CHANGED, space, range, oldValue,
+ newValue);
+ }
+
+ private void commentPlateChanged(TraceAddressSpace space, TraceAddressSnapRange range,
+ String oldValue, String newValue) {
+ commentChanged(ChangeManager.DOCR_PLATE_COMMENT_CHANGED, space, range, oldValue,
+ newValue);
+ }
+
+ private void commentPostChanged(TraceAddressSpace space, TraceAddressSnapRange range,
+ String oldValue, String newValue) {
+ commentChanged(ChangeManager.DOCR_POST_COMMENT_CHANGED, space, range, oldValue,
+ newValue);
+ }
+
+ private void commentPreChanged(TraceAddressSpace space, TraceAddressSnapRange range,
+ String oldValue, String newValue) {
+ commentChanged(ChangeManager.DOCR_PRE_COMMENT_CHANGED, space, range, oldValue,
+ newValue);
+ }
+
+ private void commentRepeatableChanged(TraceAddressSpace space, TraceAddressSnapRange range,
+ String oldValue, String newValue) {
+ // TODO: The "repeatable" semantics are not implemented, yet.
+ commentChanged(ChangeManager.DOCR_REPEATABLE_COMMENT_CHANGED, space, range, oldValue,
+ newValue);
+ }
+
private void compositeDataAdded(TraceAddressSpace space, TraceAddressSnapRange range,
TraceData oldIsNull, TraceData added) {
DomainObjectEventQueues queues = isCodeVisible(space, added);
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/Trace.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/Trace.java
index 328c935c62..1f0dc98802 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/Trace.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/Trace.java
@@ -15,6 +15,8 @@
*/
package ghidra.trace.model;
+import java.util.*;
+
import javax.swing.ImageIcon;
import com.google.common.collect.Range;
@@ -106,6 +108,33 @@ public interface Trace extends DataTypeManagerDomainObject {
new TraceCodeChangeType<>();
}
+ public static final class TraceCommentChangeType
+ extends DefaultTraceChangeType {
+ private static final Map BY_TYPE = new HashMap<>();
+
+ public static final TraceCommentChangeType PLATE_CHANGED =
+ new TraceCommentChangeType(CodeUnit.PLATE_COMMENT);
+ public static final TraceCommentChangeType PRE_CHANGED =
+ new TraceCommentChangeType(CodeUnit.PRE_COMMENT);
+ public static final TraceCommentChangeType POST_CHANGED =
+ new TraceCommentChangeType(CodeUnit.POST_COMMENT);
+ public static final TraceCommentChangeType EOL_CHANGED =
+ new TraceCommentChangeType(CodeUnit.EOL_COMMENT);
+ public static final TraceCommentChangeType REPEATABLE_CHANGED =
+ new TraceCommentChangeType(CodeUnit.REPEATABLE_COMMENT);
+
+ public static TraceCommentChangeType byType(int type) {
+ return Objects.requireNonNull(BY_TYPE.get(type));
+ }
+
+ public final int type;
+
+ private TraceCommentChangeType(int type) {
+ this.type = type;
+ BY_TYPE.put(type, this);
+ }
+ }
+
public static final class TraceCompositeDataChangeType
extends DefaultTraceChangeType {
public static final TraceCompositeDataChangeType ADDED =
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/memory/TraceMemoryOperations.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/memory/TraceMemoryOperations.java
index 7e59ecfc8c..0f5bc95cab 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/memory/TraceMemoryOperations.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/memory/TraceMemoryOperations.java
@@ -418,7 +418,7 @@ public interface TraceMemoryOperations {
* @param snap the time to search
* @param range the address range to search
* @param data the values to search for
- * @param mask a mask on the bits of {@code data}
+ * @param mask a mask on the bits of {@code data}; or null to match all bytes exactly
* @param forward true to return the match with the lowest address in {@code range}, false for
* the highest address.
* @param monitor a monitor for progress reporting and canceling
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/memory/AbstractDBTraceMemoryManagerTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/memory/AbstractDBTraceMemoryManagerTest.java
index 84cf80f294..fc95f97fba 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/memory/AbstractDBTraceMemoryManagerTest.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/memory/AbstractDBTraceMemoryManagerTest.java
@@ -42,6 +42,7 @@ import ghidra.trace.model.TraceAddressSnapRange;
import ghidra.trace.model.memory.TraceMemoryState;
import ghidra.util.database.*;
import ghidra.util.task.ConsoleTaskMonitor;
+import ghidra.util.task.TaskMonitor;
public abstract class AbstractDBTraceMemoryManagerTest
extends AbstractGhidraHeadlessIntegrationTest {
@@ -715,6 +716,66 @@ public abstract class AbstractDBTraceMemoryManagerTest
assertArrayEquals(arr(1, 2, 3, 4), read.array());
}
+ @Test
+ public void testFindBytes() {
+ try (UndoableTransaction tid = UndoableTransaction.start(trace, "Testing", true)) {
+ assertEquals(4, memory.putBytes(3, addr(0x4000), buf(1, 2, 3, 4)));
+ }
+
+ try {
+ memory.findBytes(3, range(0x4000, 0x4003), buf(1, 2, 3, 4), buf(-1, -1, -1),
+ true, TaskMonitor.DUMMY);
+ }
+ catch (IllegalArgumentException e) {
+ // pass
+ }
+
+ // Degenerate
+ assertNull(
+ memory.findBytes(2, range(0x4000, 0x4003), buf(), buf(),
+ true, TaskMonitor.DUMMY));
+
+ // Too soon
+ assertNull(
+ memory.findBytes(2, range(0x4000, 0x4003), buf(1, 2, 3, 4), buf(-1, -1, -1, -1),
+ true, TaskMonitor.DUMMY));
+
+ // Too small
+ assertNull(
+ memory.findBytes(3, range(0x4000, 0x4002), buf(1, 2, 3, 4), buf(-1, -1, -1, -1),
+ true, TaskMonitor.DUMMY));
+
+ // Too high
+ assertNull(
+ memory.findBytes(3, range(0x4001, 0x4004), buf(1, 2, 3, 4), buf(-1, -1, -1, -1),
+ true, TaskMonitor.DUMMY));
+
+ // Too low
+ assertNull(
+ memory.findBytes(3, range(0x3fff, 0x4002), buf(1, 2, 3, 4), buf(-1, -1, -1, -1),
+ true, TaskMonitor.DUMMY));
+
+ // Perfect match
+ assertEquals(addr(0x4000),
+ memory.findBytes(3, range(0x4000, 0x4003), buf(1, 2, 3, 4), buf(-1, -1, -1, -1),
+ true, TaskMonitor.DUMMY));
+
+ // Make it work for the match
+ assertEquals(addr(0x4000),
+ memory.findBytes(3, range(0x0, -1), buf(1, 2, 3, 4), buf(-1, -1, -1, -1),
+ true, TaskMonitor.DUMMY));
+
+ // Make it work for the match
+ assertEquals(addr(0x4000),
+ memory.findBytes(3, range(0x0, -1), buf(1), buf(-1),
+ true, TaskMonitor.DUMMY));
+
+ // Sub match
+ assertEquals(addr(0x4001),
+ memory.findBytes(3, range(0x4000, 0x4003), buf(2, 3, 4), buf(-1, -1, -1),
+ true, TaskMonitor.DUMMY));
+ }
+
@Test
public void testRemoveBytes() {
try (UndoableTransaction tid = UndoableTransaction.start(trace, "Testing", true)) {
diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/AddressIteratorAdapter.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/AddressIteratorAdapter.java
index 43b1200a18..43954807f9 100644
--- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/AddressIteratorAdapter.java
+++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/AddressIteratorAdapter.java
@@ -89,6 +89,11 @@ public class AddressIteratorAdapter extends NestedIterator forRange(AddressRange range, boolean forward) {
+ return () -> forward ? new ForwardAddressIterator(range)
+ : new BackwardAddressIterator(range);
+ }
+
public AddressIteratorAdapter(Iterator outer, boolean forward) {
super(outer, forward ? ForwardAddressIterator::new : BackwardAddressIterator::new);
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/SearchTextPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/SearchTextPlugin.java
index b650e35c97..d159f7c2ee 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/SearchTextPlugin.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/SearchTextPlugin.java
@@ -62,8 +62,7 @@ import ghidra.util.task.*;
import resources.ResourceManager;
/**
- * Plugin to search text as it is displayed in the fields of the
- * Code Browser.
+ * Plugin to search text as it is displayed in the fields of the Code Browser.
*/
//@formatter:off
@PluginInfo(
@@ -114,6 +113,7 @@ public class SearchTextPlugin extends ProgramPlugin implements OptionsChangeList
/**
* The constructor for the SearchTextPlugin.
+ *
* @param plugintool The tool required by this plugin.
*/
public SearchTextPlugin(PluginTool plugintool) {
@@ -260,10 +260,7 @@ public class SearchTextPlugin extends ProgramPlugin implements OptionsChangeList
}
private ProgramLocation getStartLocation() {
- if (currentLocation == null) {
- currentLocation = navigatable.getLocation();
- }
- return currentLocation;
+ return currentLocation = navigatable.getLocation();
}
private void searchNext(Program program, Navigatable searchNavigatable, Searcher textSearcher) {
@@ -475,9 +472,8 @@ public class SearchTextPlugin extends ProgramPlugin implements OptionsChangeList
searchDialog.setHasSelection(context.hasSelection());
}
- CodeViewerService codeViewerService = tool.getService(CodeViewerService.class);
String textSelection = navigatable.getTextSelection();
- ProgramLocation location = codeViewerService.getCurrentLocation();
+ ProgramLocation location = navigatable.getLocation();
Address address = location.getAddress();
Listing listing = context.getProgram().getListing();
CodeUnit codeUnit = listing.getCodeUnitAt(address);
@@ -499,6 +495,7 @@ public class SearchTextPlugin extends ProgramPlugin implements OptionsChangeList
/**
* Get the address set for the selection.
+ *
* @return null if there is no selection
*/
private AddressSetView getAddressSet(Navigatable searchNavigatable, SearchOptions options) {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/databasesearcher/InstructionMnemonicOperandFieldSearcher.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/databasesearcher/InstructionMnemonicOperandFieldSearcher.java
index bf6ad1f9fc..99a2ea80a9 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/databasesearcher/InstructionMnemonicOperandFieldSearcher.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/databasesearcher/InstructionMnemonicOperandFieldSearcher.java
@@ -75,7 +75,7 @@ public class InstructionMnemonicOperandFieldSearcher extends ProgramDatabaseFiel
@Override
protected Address advance(List currentMatches) {
- Instruction instruction = iterator.next();
+ Instruction instruction = iterator.hasNext() ? iterator.next() : null;
Address nextAddress = null;
if (instruction != null) {
nextAddress = instruction.getMinAddress();
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/table/TableComponentProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/table/TableComponentProvider.java
index 8476fe75ae..4fe7009972 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/table/TableComponentProvider.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/table/TableComponentProvider.java
@@ -84,7 +84,7 @@ public class TableComponentProvider extends ComponentProviderAdapter
this.tableServicePlugin = plugin;
this.navigatable = navigatable;
- this.program = plugin.getProgram();
+ this.program = navigatable.getProgram();
this.model = model;
this.programName = programName;
this.markerService = markerService;
@@ -152,7 +152,6 @@ public class TableComponentProvider extends ComponentProviderAdapter
selectAction = new MakeProgramSelectionAction(tableServicePlugin, table) {
@Override
protected ProgramSelection makeSelection(ActionContext context) {
-
ProgramSelection selection = table.getProgramSelection();
navigatable.goTo(program, new ProgramLocation(program, selection.getMinAddress()));
navigatable.setSelection(selection);