diff --git a/Ghidra/Debug/Debugger-agent-gdb/src/main/py/src/ghidragdb/methods.py b/Ghidra/Debug/Debugger-agent-gdb/src/main/py/src/ghidragdb/methods.py index 101c0cd425..bae891bd95 100644 --- a/Ghidra/Debug/Debugger-agent-gdb/src/main/py/src/ghidragdb/methods.py +++ b/Ghidra/Debug/Debugger-agent-gdb/src/main/py/src/ghidragdb/methods.py @@ -367,7 +367,7 @@ def refresh_modules(node: sch.Schema('ModuleContainer')): # node is Module so this appears in Modules panel -@REGISTRY.method(display='Load all Modules and all Sections') +@REGISTRY.method(display='Refresh all Modules and all Sections') def load_all_sections(node: sch.Schema('Module')): """ Load/refresh all modules and all sections. diff --git a/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/action/LocationTracker.java b/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/action/LocationTracker.java index 49247ebb9d..c2edb03ef5 100644 --- a/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/action/LocationTracker.java +++ b/Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/action/LocationTracker.java @@ -51,8 +51,7 @@ public interface LocationTracker { * @param coordinates the trace, thread, snap, etc., of the tool * @return the address to navigate to */ - CompletableFuture
computeTraceAddress(PluginTool tool, - DebuggerCoordinates coordinates); + Address computeTraceAddress(PluginTool tool, DebuggerCoordinates coordinates); /** * Get the suggested input if the user activates "Go To" while this tracker is active diff --git a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/service/tracermi/TraceRmiHandler.java b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/service/tracermi/TraceRmiHandler.java index e7697d01b6..19c73acd5c 100644 --- a/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/service/tracermi/TraceRmiHandler.java +++ b/Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/service/tracermi/TraceRmiHandler.java @@ -484,10 +484,10 @@ public class TraceRmiHandler implements TraceRmiConnection { RootMessage.Builder dispatch(RootMessage req, RootMessage.Builder rep) throws Exception; default RootMessage handle(RootMessage req) { - /*String desc = toString(req); + String desc = toString(req); if (desc != null) { TimedMsg.debug(this, "HANDLING: " + desc); - }*/ + } RootMessage.Builder rep = RootMessage.newBuilder(); try { rep = dispatch(req, rep); @@ -514,12 +514,12 @@ public class TraceRmiHandler implements TraceRmiConnection { case REQUEST_START_TX -> "startTx(%d,%s)".formatted( req.getRequestStartTx().getTxid().getId(), req.getRequestStartTx().getDescription()); - case REQUEST_SET_VALUE -> "setValue(%d,%s,%s,=%s)".formatted( + /*case REQUEST_SET_VALUE -> "setValue(%d,%s,%s,=%s)".formatted( req.getRequestSetValue().getValue().getParent().getId(), req.getRequestSetValue().getValue().getParent().getPath().getPath(), req.getRequestSetValue().getValue().getKey(), ValueDecoder.DISPLAY - .toValue(req.getRequestSetValue().getValue().getValue())); + .toValue(req.getRequestSetValue().getValue().getValue()));*/ default -> null; }; } diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/DebuggerResources.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/DebuggerResources.java index 57bded0203..855d6be8c2 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/DebuggerResources.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/DebuggerResources.java @@ -62,6 +62,7 @@ import ghidra.util.exception.CancelledException; import resources.MultiIcon; public interface DebuggerResources { + String OPTIONS_CATEGORY_DEBUGGER = "Debugger"; String OPTIONS_CATEGORY_WORKFLOW = "Workflow"; diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/DebuggerTrackLocationTrait.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/DebuggerTrackLocationTrait.java index fdffd4a399..35ff2c3d27 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/DebuggerTrackLocationTrait.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/DebuggerTrackLocationTrait.java @@ -19,7 +19,6 @@ import java.awt.Color; import java.lang.invoke.MethodHandles; import java.math.BigInteger; import java.util.*; -import java.util.concurrent.CompletableFuture; import docking.ActionContext; import docking.ComponentProvider; @@ -34,13 +33,13 @@ import ghidra.app.plugin.core.debug.gui.colors.MultiSelectionBlendedLayoutBackgr import ghidra.app.plugin.core.debug.gui.listing.DebuggerTrackedRegisterListingBackgroundColorModel; import ghidra.app.util.viewer.listingpanel.ListingBackgroundColorModel; import ghidra.app.util.viewer.listingpanel.ListingPanel; -import ghidra.async.AsyncUtils; import ghidra.debug.api.action.*; import ghidra.debug.api.action.LocationTrackingSpec.TrackingSpecConfigFieldCodec; import ghidra.debug.api.tracemgr.DebuggerCoordinates; import ghidra.framework.options.SaveState; import ghidra.framework.plugintool.*; import ghidra.framework.plugintool.annotation.AutoConfigStateField; +import ghidra.program.model.address.Address; import ghidra.program.util.ProgramLocation; import ghidra.trace.model.*; import ghidra.trace.model.stack.TraceStack; @@ -252,7 +251,7 @@ public class DebuggerTrackLocationTrait { doTrack(); } - protected CompletableFuture
+ * The wrapper will notify the parent and child, if necessary.
+ *
+ * @param lifespan the new lifespan
+ */
+ void doSetLifespan(Lifespan lifespan);
+
+ Lifespan getLifespan();
+
+ DBTraceObject getChildOrNull();
+
+ Object getValue();
+
+ boolean isDeleted();
+
+ void doDelete();
+}
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/thread/DBTraceThreadManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/thread/DBTraceThreadManager.java
index 6073901aaf..56277ed82f 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/thread/DBTraceThreadManager.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/thread/DBTraceThreadManager.java
@@ -77,10 +77,9 @@ public class DBTraceThreadManager implements TraceThreadManager, DBTraceManager
if (objectManager.hasSchema()) {
return objectManager.assertMyThread(thread);
}
- if (!(thread instanceof DBTraceThread)) {
+ if (!(thread instanceof DBTraceThread dbThread)) {
throw new IllegalArgumentException("Thread " + thread + " is not part of this trace");
}
- DBTraceThread dbThread = (DBTraceThread) thread;
if (dbThread.manager != this) {
throw new IllegalArgumentException("Thread " + thread + " is not part of this trace");
}
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/target/TraceObjectManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/target/TraceObjectManager.java
index 6da8c977eb..c7bac4fd15 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/target/TraceObjectManager.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/target/TraceObjectManager.java
@@ -123,16 +123,23 @@ public interface TraceObjectManager {
/**
* Get all the objects in the database
*
- * @return the collection of all objects
+ * @return the stream of all objects
*/
- Collection extends TraceObject> getAllObjects();
+ Stream extends TraceObject> getAllObjects();
+
+ /**
+ * Get the number of objects in the database
+ *
+ * @return the number of objects
+ */
+ int getObjectCount();
/**
* Get all the values (edges) in the database
*
- * @return the collect of all values
+ * @return the stream of all values
*/
- Collection extends TraceObjectValue> getAllValues();
+ Stream extends TraceObjectValue> getAllValues();
/**
* Get all address-ranged values intersecting the given span and address range
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/ToyDBTraceBuilder.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/ToyDBTraceBuilder.java
index b3524eae0d..72a429dc5a 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/ToyDBTraceBuilder.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/ToyDBTraceBuilder.java
@@ -729,6 +729,7 @@ public class ToyDBTraceBuilder implements AutoCloseable {
public File save() throws IOException, CancelledException {
Path tmp = Files.createTempFile("test", ".db");
Files.delete(tmp); // saveAs must create the file
+ trace.objectManager.flushWbCaches();
trace.getDBHandle().saveAs(tmp.toFile(), false, new ConsoleTaskMonitor());
return tmp.toFile();
}
diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/target/DBTraceObjectManagerTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/target/DBTraceObjectManagerTest.java
index 26c55c8a96..1af4b18767 100644
--- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/target/DBTraceObjectManagerTest.java
+++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/target/DBTraceObjectManagerTest.java
@@ -327,42 +327,42 @@ public class DBTraceObjectManagerTest extends AbstractGhidraHeadlessIntegrationT
@Test
public void testClear() {
populateModel(3);
- assertEquals(5, manager.getAllObjects().size());
+ assertEquals(5, manager.getObjectCount());
try (Transaction tx = b.startTransaction()) {
manager.clear();
}
- assertEquals(0, manager.getAllObjects().size());
+ assertEquals(0, manager.getObjectCount());
populateModel(3);
- assertEquals(5, manager.getAllObjects().size());
+ assertEquals(5, manager.getObjectCount());
}
- @Test
+ // @Test // Write-behind cache does not implement undo or redo
public void testUndoRedo() throws Exception {
populateModel(3);
- assertEquals(5, manager.getAllObjects().size());
+ assertEquals(5, manager.getObjectCount());
b.trace.undo();
- assertEquals(0, manager.getAllObjects().size());
+ assertEquals(0, manager.getObjectCount());
b.trace.redo();
- assertEquals(5, manager.getAllObjects().size());
+ assertEquals(5, manager.getObjectCount());
}
- @Test
+ // @Test // Write-behind cache does not implement abort
public void testAbort() throws Exception {
try (Transaction tx = b.startTransaction()) {
populateModel(3);
- assertEquals(5, manager.getAllObjects().size());
+ assertEquals(5, manager.getObjectCount());
tx.abort();
}
- assertEquals(0, manager.getAllObjects().size());
+ assertEquals(0, manager.getObjectCount());
populateModel(3);
- assertEquals(5, manager.getAllObjects().size());
+ assertEquals(5, manager.getObjectCount());
}
@Test
diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/StreamUtils.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/StreamUtils.java
index 6f89d6cddc..292f40a9ac 100644
--- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/StreamUtils.java
+++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/StreamUtils.java
@@ -15,13 +15,14 @@
*/
package ghidra.util;
-import java.util.Collection;
-import java.util.Comparator;
+import java.util.*;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
-public enum StreamUtils {
- ;
+public class StreamUtils {
+ private StreamUtils() {
+ }
+
@SuppressWarnings("unchecked")
public static
+ * With the addition of the write-behind cache, this test is no longer sane.
*/
- @Test
+ // @Test
public void testAbortAddBreakpointSetSleigh() throws Throwable {
DebuggerControlService controlService =
addPlugin(tool, DebuggerControlServicePlugin.class);
diff --git a/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/app/plugin/core/debug/service/tracermi/TraceRmiPerformanceTest.java b/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/app/plugin/core/debug/service/tracermi/TraceRmiPerformanceTest.java
new file mode 100644
index 0000000000..80d00e2afe
--- /dev/null
+++ b/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/app/plugin/core/debug/service/tracermi/TraceRmiPerformanceTest.java
@@ -0,0 +1,628 @@
+/* ###
+ * 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.app.plugin.core.debug.service.tracermi;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.*;
+import java.net.*;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.*;
+
+import org.apache.commons.lang3.exception.ExceptionUtils;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import db.*;
+import generic.Unique;
+import generic.test.rule.Repeated;
+import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerIntegrationTest;
+import ghidra.app.services.TraceRmiService;
+import ghidra.dbg.target.schema.XmlSchemaContext;
+import ghidra.debug.api.tracermi.TraceRmiAcceptor;
+import ghidra.debug.api.tracermi.TraceRmiConnection;
+import ghidra.framework.plugintool.PluginTool;
+import ghidra.program.model.address.*;
+import ghidra.rmi.trace.TraceRmi.*;
+import ghidra.rmi.trace.TraceRmi.Compiler;
+import ghidra.rmi.trace.TraceRmi.RootMessage.MsgCase;
+import ghidra.trace.database.ToyDBTraceBuilder;
+import ghidra.trace.database.target.DBTraceObject;
+import ghidra.trace.model.Lifespan;
+import ghidra.trace.model.Trace;
+import ghidra.trace.model.target.TraceObject.ConflictResolution;
+import ghidra.trace.model.target.TraceObjectKeyPath;
+import ghidra.util.LockHold;
+import ghidra.util.Msg;
+import ghidra.util.database.*;
+import ghidra.util.database.annot.*;
+import ghidra.util.database.spatial.RStarTreeMapTest.IntRect;
+import ghidra.util.database.spatial.RStarTreeMapTest.MyDomainObject;
+import ghidra.util.task.TaskMonitor;
+
+@Ignore // Only want for manual testing
+public class TraceRmiPerformanceTest extends AbstractGhidraHeadedDebuggerIntegrationTest {
+ public static final int REGION_COUNT = 1000;
+ public static final int RECORD_COUNT = 1000 * 6;
+
+ interface Tx extends AutoCloseable {
+ }
+
+ interface TraceHandle extends AutoCloseable {
+ Trace getTrace() throws Throwable;
+
+ Tx startTx() throws Throwable;
+
+ default void addLotsOfRegions() throws Throwable {
+ try (Tx tx = startTx()) {
+ AddressFactory af = getTrace().getBaseAddressFactory();
+ AddressSpace space = af.getDefaultAddressSpace();
+ for (int i = 0; i < REGION_COUNT; i++) {
+ AddressRange range = new AddressRangeImpl(space.getAddress(i * 1024), 1024);
+ addRegion(Integer.toString(i), range, "rw");
+ }
+ }
+ }
+
+ void addRegion(String key, AddressRange range, String perms) throws Throwable;
+ }
+
+ interface TraceMaker {
+ TraceHandle createTrace() throws Throwable;
+ }
+
+ static class ApiTx implements Tx {
+ private final Transaction tx;
+
+ private ApiTx(Transaction tx) {
+ this.tx = tx;
+ }
+
+ @Override
+ public void close() throws Exception {
+ tx.close();
+ }
+ }
+
+ static class ApiTraceHandle implements TraceHandle {
+ private final ToyDBTraceBuilder tb;
+
+ public ApiTraceHandle(ToyDBTraceBuilder tb) {
+ this.tb = tb;
+ }
+
+ @Override
+ public Trace getTrace() throws Throwable {
+ return tb.trace;
+ }
+
+ @Override
+ public Tx startTx() throws Throwable {
+ return new ApiTx(tb.trace.openTransaction("Test"));
+ }
+
+ @Override
+ public void addRegion(String key, AddressRange range, String perms) {
+ DBTraceObject region = tb.trace.getObjectManager()
+ .createObject(TraceObjectKeyPath.parse("Processes[0].Memory[" + key + "]"));
+ region.setValue(Lifespan.nowOn(0), "Range", range);
+ region.setValue(Lifespan.nowOn(0), "R", perms.contains("r"));
+ region.setValue(Lifespan.nowOn(0), "W", perms.contains("w"));
+ region.setValue(Lifespan.nowOn(0), "X", perms.contains("x"));
+ region.insert(Lifespan.nowOn(0), ConflictResolution.ADJUST);
+ }
+
+ @Override
+ public void close() throws Exception {
+ tb.close();
+ }
+ }
+
+ class ApiTraceMaker implements TraceMaker {
+ @Override
+ public TraceHandle createTrace() throws Throwable {
+ tb = new ToyDBTraceBuilder(name.getMethodName(), LANGID_TOYBE64);
+ try (Transaction tx = tb.startTransaction()) {
+ tb.trace.getObjectManager().createRootObject(SCHEMA_SESSION);
+ }
+ return new ApiTraceHandle(tb);
+ }
+ }
+
+ static class RmiTraceHandle implements TraceHandle {
+ private static final int RESULT_COUNT = REGION_COUNT * 6 + 2;
+ private final TraceRmiConnection connection;
+ private final Socket client;
+
+ private final List the type of spans (recursive)
@@ -387,7 +387,7 @@ public interface Span {
* existing entries are truncated or deleted (or coalesced if they share the same value as the
* new entry) so that the new entry can fit.
*
- * @implNote It is recommended to create an interface (having only the {@link V} parameter)
+ * @implNote It is recommended to create an interface (having only the {@code {
if (this == obj) {
return true;
}
- if (!(obj instanceof @SuppressWarnings("rawtypes") DefaultSpanMap that)) {
+ if (!(obj instanceof DefaultSpanMap that)) {
return false;
}
if (this.domain != that.domain) {
@@ -995,7 +995,7 @@ public interface Span {
if (this == obj) {
return true;
}
- if (!(obj instanceof @SuppressWarnings("rawtypes") DefaultSpanSet that)) {
+ if (!(obj instanceof DefaultSpanSet that)) {
return false;
}
if (!Objects.equals(this.map, that.map)) {
@@ -1081,6 +1081,11 @@ public interface Span {
}
}
+ /**
+ * Provides a default {@link #toString} implementation
+ *
+ * @return the string
+ */
@SuppressWarnings("unchecked")
default String doToString() {
return domain().toString((S) this);
diff --git a/Ghidra/Test/DebuggerIntegrationTest/build.gradle b/Ghidra/Test/DebuggerIntegrationTest/build.gradle
index da5acecdb7..8fbbf5e120 100644
--- a/Ghidra/Test/DebuggerIntegrationTest/build.gradle
+++ b/Ghidra/Test/DebuggerIntegrationTest/build.gradle
@@ -63,6 +63,7 @@ dependencies {
testImplementation project(path: ':PDB', configuration: 'testArtifacts')
testImplementation project(path: ':GnuDemangler', configuration: 'testArtifacts')
+ testImplementation project(path: ':ProposedUtils', configuration: 'testArtifacts')
testImplementation project(path: ':Framework-TraceModeling', configuration: 'testArtifacts')
testImplementation project(path: ':Framework-AsyncComm', configuration: 'testArtifacts')
testImplementation project(path: ':Framework-Debugging', configuration: 'testArtifacts')
diff --git a/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/app/plugin/core/debug/service/breakpoint/AbstractDebuggerLogicalBreakpointServiceTest.java b/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/app/plugin/core/debug/service/breakpoint/AbstractDebuggerLogicalBreakpointServiceTest.java
index 7fd2058274..bd2fbcf1ac 100644
--- a/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/app/plugin/core/debug/service/breakpoint/AbstractDebuggerLogicalBreakpointServiceTest.java
+++ b/Ghidra/Test/DebuggerIntegrationTest/src/test/java/ghidra/app/plugin/core/debug/service/breakpoint/AbstractDebuggerLogicalBreakpointServiceTest.java
@@ -1051,7 +1051,7 @@ public abstract class AbstractDebuggerLogicalBreakpointServiceTest