mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
Merge remote-tracking branch 'origin/GP-1386_Dan_DBTraceObjectModel-REBASED-1--SQUASHED'
This commit is contained in:
commit
8e59d0e673
179 changed files with 9971 additions and 797 deletions
|
@ -121,28 +121,28 @@ public abstract class AbstractModelForDbgengBreakpointsTest
|
|||
@Override
|
||||
protected void disableViaInterpreter(TargetTogglable t, TargetInterpreter interpreter)
|
||||
throws Throwable {
|
||||
String bpId = getBreakPattern().matchIndices(t.getPath()).get(BREAK_ID_POS);
|
||||
String bpId = getBreakPattern().matchKeys(t.getPath()).get(BREAK_ID_POS);
|
||||
waitOn(interpreter.execute("bd " + bpId));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void enableViaInterpreter(TargetTogglable t, TargetInterpreter interpreter)
|
||||
throws Throwable {
|
||||
String bpId = getBreakPattern().matchIndices(t.getPath()).get(BREAK_ID_POS);
|
||||
String bpId = getBreakPattern().matchKeys(t.getPath()).get(BREAK_ID_POS);
|
||||
waitOn(interpreter.execute("be " + bpId));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deleteViaInterpreter(TargetDeletable d, TargetInterpreter interpreter)
|
||||
throws Throwable {
|
||||
String bpId = getBreakPattern().matchIndices(d.getPath()).get(BREAK_ID_POS);
|
||||
String bpId = getBreakPattern().matchKeys(d.getPath()).get(BREAK_ID_POS);
|
||||
waitOn(interpreter.execute("bc " + bpId));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assertLocCoversViaInterpreter(AddressRange range, TargetBreakpointKind kind,
|
||||
TargetBreakpointLocation loc, TargetInterpreter interpreter) throws Throwable {
|
||||
String bpId = getBreakPattern().matchIndices(loc.getPath()).get(BREAK_ID_POS);
|
||||
String bpId = getBreakPattern().matchKeys(loc.getPath()).get(BREAK_ID_POS);
|
||||
String line = waitOn(interpreter.executeCapture("bl " + bpId)).trim();
|
||||
assertFalse(line.contains("\n"));
|
||||
// NB. WinDbg numbers breakpoints in base 10, by default
|
||||
|
@ -153,7 +153,7 @@ public abstract class AbstractModelForDbgengBreakpointsTest
|
|||
@Override
|
||||
protected void assertEnabledViaInterpreter(TargetTogglable t, boolean enabled,
|
||||
TargetInterpreter interpreter) throws Throwable {
|
||||
String bpId = getBreakPattern().matchIndices(t.getPath()).get(BREAK_ID_POS);
|
||||
String bpId = getBreakPattern().matchKeys(t.getPath()).get(BREAK_ID_POS);
|
||||
String line = waitOn(interpreter.executeCapture("bl " + bpId)).trim();
|
||||
assertFalse(line.contains("\n"));
|
||||
assertTrue(line.startsWith(bpId));
|
||||
|
@ -164,7 +164,7 @@ public abstract class AbstractModelForDbgengBreakpointsTest
|
|||
@Override
|
||||
protected void assertDeletedViaInterpreter(TargetDeletable d, TargetInterpreter interpreter)
|
||||
throws Throwable {
|
||||
String bpId = getBreakPattern().matchIndices(d.getPath()).get(BREAK_ID_POS);
|
||||
String bpId = getBreakPattern().matchKeys(d.getPath()).get(BREAK_ID_POS);
|
||||
String line = waitOn(interpreter.executeCapture("bl " + bpId)).trim();
|
||||
assertEquals("", line);
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ public abstract class AbstractModelForDbgengFrameActivationTest
|
|||
String line = waitOn(interpreter.executeCapture(".frame")).trim();
|
||||
assertFalse(line.contains("\n"));
|
||||
int frameId = Integer.parseInt(line.split("\\s+")[0], 16);
|
||||
int expId = Integer.decode(getStackPattern().matchIndices(expected.getPath()).get(2));
|
||||
int expId = Integer.decode(getStackPattern().matchKeys(expected.getPath()).get(2));
|
||||
assertEquals(expId, frameId);
|
||||
}
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ public abstract class AbstractModelForDbgengProcessActivationTest
|
|||
@Override
|
||||
protected void activateViaInterpreter(TargetObject obj, TargetInterpreter interpreter)
|
||||
throws Throwable {
|
||||
String id = Unique.assertOne(getProcessPattern().matchIndices(obj.getPath()));
|
||||
String id = Unique.assertOne(getProcessPattern().matchKeys(obj.getPath()));
|
||||
waitOn(interpreter.execute("|" + id + " s"));
|
||||
}
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ public abstract class AbstractModelForDbgengThreadActivationTest
|
|||
@Override
|
||||
protected void activateViaInterpreter(TargetObject obj, TargetInterpreter interpreter)
|
||||
throws Throwable {
|
||||
String threadId = getThreadPattern().matchIndices(obj.getPath()).get(1);
|
||||
String threadId = getThreadPattern().matchKeys(obj.getPath()).get(1);
|
||||
// TODO: This test is imperfect, since processes are activated as well
|
||||
waitOn(interpreter.execute("~" + threadId + " s"));
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ public abstract class AbstractModelForDbgengThreadActivationTest
|
|||
.filter(l -> l.trim().startsWith("."))
|
||||
.collect(Collectors.toList())).trim();
|
||||
String threadId = getIdFromCapture(line);
|
||||
String expId = getThreadPattern().matchIndices(expected.getPath()).get(1);
|
||||
String expId = getThreadPattern().matchKeys(expected.getPath()).get(1);
|
||||
assertEquals(expId, threadId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -119,7 +119,7 @@ public abstract class AbstractModelForGdbBreakpointsTest
|
|||
protected void disableViaInterpreter(TargetTogglable t, TargetInterpreter interpreter)
|
||||
throws Throwable {
|
||||
assert t instanceof TargetBreakpointSpec; // TODO: or Location
|
||||
String index = Unique.assertOne(BREAK_PATTERN.matchIndices(t.getPath()));
|
||||
String index = Unique.assertOne(BREAK_PATTERN.matchKeys(t.getPath()));
|
||||
waitOn(interpreter.execute("disable " + index));
|
||||
}
|
||||
|
||||
|
@ -127,7 +127,7 @@ public abstract class AbstractModelForGdbBreakpointsTest
|
|||
protected void enableViaInterpreter(TargetTogglable t, TargetInterpreter interpreter)
|
||||
throws Throwable {
|
||||
assert t instanceof TargetBreakpointSpec; // TODO: or Location
|
||||
String index = Unique.assertOne(BREAK_PATTERN.matchIndices(t.getPath()));
|
||||
String index = Unique.assertOne(BREAK_PATTERN.matchKeys(t.getPath()));
|
||||
waitOn(interpreter.execute("enable " + index));
|
||||
}
|
||||
|
||||
|
@ -135,7 +135,7 @@ public abstract class AbstractModelForGdbBreakpointsTest
|
|||
protected void deleteViaInterpreter(TargetDeletable d, TargetInterpreter interpreter)
|
||||
throws Throwable {
|
||||
assert d instanceof TargetBreakpointSpec; // TODO: or Location
|
||||
String index = Unique.assertOne(BREAK_PATTERN.matchIndices(d.getPath()));
|
||||
String index = Unique.assertOne(BREAK_PATTERN.matchKeys(d.getPath()));
|
||||
waitOn(interpreter.execute("delete " + index));
|
||||
}
|
||||
|
||||
|
@ -143,7 +143,7 @@ public abstract class AbstractModelForGdbBreakpointsTest
|
|||
protected void assertLocCoversViaInterpreter(AddressRange range, TargetBreakpointKind kind,
|
||||
TargetBreakpointLocation loc, TargetInterpreter interpreter) throws Throwable {
|
||||
String index =
|
||||
Unique.assertOne(BREAK_PATTERN.matchIndices(loc.getSpecification().getPath()));
|
||||
Unique.assertOne(BREAK_PATTERN.matchKeys(loc.getSpecification().getPath()));
|
||||
String output = waitOn(interpreter.executeCapture("info break " + index));
|
||||
String line = Unique.assertOne(Stream.of(output.split("\n"))
|
||||
.filter(l -> !l.trim().startsWith("Num"))
|
||||
|
@ -156,7 +156,7 @@ public abstract class AbstractModelForGdbBreakpointsTest
|
|||
protected void assertEnabledViaInterpreter(TargetTogglable t, boolean enabled,
|
||||
TargetInterpreter interpreter) throws Throwable {
|
||||
assert t instanceof TargetBreakpointSpec; // TODO: or Location
|
||||
String index = Unique.assertOne(BREAK_PATTERN.matchIndices(t.getPath()));
|
||||
String index = Unique.assertOne(BREAK_PATTERN.matchKeys(t.getPath()));
|
||||
String output = waitOn(interpreter.executeCapture("info break " + index));
|
||||
String line = Unique.assertOne(Stream.of(output.split("\n"))
|
||||
.filter(l -> !l.trim().startsWith("Num"))
|
||||
|
@ -170,7 +170,7 @@ public abstract class AbstractModelForGdbBreakpointsTest
|
|||
protected void assertDeletedViaInterpreter(TargetDeletable d, TargetInterpreter interpreter)
|
||||
throws Throwable {
|
||||
assert d instanceof TargetBreakpointSpec; // TODO: or Location
|
||||
String index = Unique.assertOne(BREAK_PATTERN.matchIndices(d.getPath()));
|
||||
String index = Unique.assertOne(BREAK_PATTERN.matchKeys(d.getPath()));
|
||||
String output = waitOn(interpreter.executeCapture("info break " + index));
|
||||
assertTrue(output.contains("No breakpoint"));
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ public abstract class AbstractModelForGdbFrameActivationTest
|
|||
@Override
|
||||
protected void activateViaInterpreter(TargetObject obj, TargetInterpreter interpreter)
|
||||
throws Throwable {
|
||||
String index = Unique.assertOne(STACK_PATTERN.matchIndices(obj.getPath()));
|
||||
String index = Unique.assertOne(STACK_PATTERN.matchKeys(obj.getPath()));
|
||||
waitOn(interpreter.execute("frame " + index));
|
||||
}
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ public abstract class AbstractModelForGdbInferiorActivationTest
|
|||
@Override
|
||||
protected void activateViaInterpreter(TargetObject obj, TargetInterpreter interpreter)
|
||||
throws Throwable {
|
||||
String index = Unique.assertOne(INF_PATTERN.matchIndices(obj.getPath()));
|
||||
String index = Unique.assertOne(INF_PATTERN.matchKeys(obj.getPath()));
|
||||
waitOn(interpreter.execute("inferior " + index));
|
||||
}
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ public abstract class AbstractModelForGdbThreadActivationTest
|
|||
@Override
|
||||
protected void activateViaInterpreter(TargetObject obj, TargetInterpreter interpreter)
|
||||
throws Throwable {
|
||||
String index = Unique.assertOne(Set.copyOf(THREAD_PATTERN.matchIndices(obj.getPath())));
|
||||
String index = Unique.assertOne(Set.copyOf(THREAD_PATTERN.matchKeys(obj.getPath())));
|
||||
// TODO: This test is imperfect, since inferiors are activated as well
|
||||
waitOn(interpreter.execute("thread " + index + ".1"));
|
||||
}
|
||||
|
|
|
@ -145,7 +145,7 @@ public abstract class AbstractModelForLldbBreakpointsTest
|
|||
@Override
|
||||
protected void disableViaInterpreter(TargetTogglable t, TargetInterpreter interpreter)
|
||||
throws Throwable {
|
||||
String bpId = getBreakPattern().matchIndices(t.getPath()).get(BREAK_ID_POS);
|
||||
String bpId = getBreakPattern().matchKeys(t.getPath()).get(BREAK_ID_POS);
|
||||
String type = getTypeFromSpec(t);
|
||||
waitOn(interpreter.execute(getCommand("disable", type, bpId)));
|
||||
}
|
||||
|
@ -153,7 +153,7 @@ public abstract class AbstractModelForLldbBreakpointsTest
|
|||
@Override
|
||||
protected void enableViaInterpreter(TargetTogglable t, TargetInterpreter interpreter)
|
||||
throws Throwable {
|
||||
String bpId = getBreakPattern().matchIndices(t.getPath()).get(BREAK_ID_POS);
|
||||
String bpId = getBreakPattern().matchKeys(t.getPath()).get(BREAK_ID_POS);
|
||||
String type = getTypeFromSpec(t);
|
||||
waitOn(interpreter.execute(getCommand("enable", type, bpId)));
|
||||
}
|
||||
|
@ -161,7 +161,7 @@ public abstract class AbstractModelForLldbBreakpointsTest
|
|||
@Override
|
||||
protected void deleteViaInterpreter(TargetDeletable d, TargetInterpreter interpreter)
|
||||
throws Throwable {
|
||||
String bpId = getBreakPattern().matchIndices(d.getPath()).get(BREAK_ID_POS);
|
||||
String bpId = getBreakPattern().matchKeys(d.getPath()).get(BREAK_ID_POS);
|
||||
String type = getTypeFromSpec(d);
|
||||
waitOn(interpreter.execute(getCommand("delete", type, bpId)));
|
||||
}
|
||||
|
@ -169,7 +169,7 @@ public abstract class AbstractModelForLldbBreakpointsTest
|
|||
@Override
|
||||
protected void assertLocCoversViaInterpreter(AddressRange range, TargetBreakpointKind kind,
|
||||
TargetBreakpointLocation loc, TargetInterpreter interpreter) throws Throwable {
|
||||
List<String> matchIndices = getBreakPattern().matchIndices(loc.getSpecification().getPath());
|
||||
List<String> matchIndices = getBreakPattern().matchKeys(loc.getSpecification().getPath());
|
||||
String bpId = matchIndices.get(BREAK_ID_POS);
|
||||
String type = getTypeFromKind(kind);
|
||||
String line = waitOn(interpreter.executeCapture(getCommand("list", type, bpId))).trim();
|
||||
|
@ -182,7 +182,7 @@ public abstract class AbstractModelForLldbBreakpointsTest
|
|||
@Override
|
||||
protected void assertEnabledViaInterpreter(TargetTogglable t, boolean enabled,
|
||||
TargetInterpreter interpreter) throws Throwable {
|
||||
String bpId = getBreakPattern().matchIndices(t.getPath()).get(BREAK_ID_POS);
|
||||
String bpId = getBreakPattern().matchKeys(t.getPath()).get(BREAK_ID_POS);
|
||||
String type = getTypeFromSpec(t);
|
||||
String line = waitOn(interpreter.executeCapture(getCommand("list", type, bpId))).trim();
|
||||
assertTrue(line.contains(bpId.substring(1)+":"));
|
||||
|
@ -192,7 +192,7 @@ public abstract class AbstractModelForLldbBreakpointsTest
|
|||
@Override
|
||||
protected void assertDeletedViaInterpreter(TargetDeletable d, TargetInterpreter interpreter)
|
||||
throws Throwable {
|
||||
String bpId = getBreakPattern().matchIndices(d.getPath()).get(BREAK_ID_POS);
|
||||
String bpId = getBreakPattern().matchKeys(d.getPath()).get(BREAK_ID_POS);
|
||||
String type = getTypeFromSpec(d);
|
||||
String line = waitOn(interpreter.executeCapture(type + " list ")).trim();
|
||||
assertFalse(line.contains(bpId+":"));
|
||||
|
|
|
@ -57,7 +57,7 @@ public abstract class AbstractModelForLldbFrameActivationTest
|
|||
|
||||
protected void activateViaInterpreter(TargetObject obj, TargetInterpreter interpreter)
|
||||
throws Throwable {
|
||||
String index = getStackPattern().matchIndices(obj.getPath()).get(3);
|
||||
String index = getStackPattern().matchKeys(obj.getPath()).get(3);
|
||||
waitOn(interpreter.execute("frame select " + index));
|
||||
}
|
||||
|
||||
|
@ -70,7 +70,7 @@ public abstract class AbstractModelForLldbFrameActivationTest
|
|||
assertFalse(line.contains("\n"));
|
||||
String id = getIdFromCapture(line);
|
||||
int frameId = Integer.parseInt(id, 10);
|
||||
int expId = Integer.decode(getStackPattern().matchIndices(expected.getPath()).get(3));
|
||||
int expId = Integer.decode(getStackPattern().matchKeys(expected.getPath()).get(3));
|
||||
assertEquals(expId, frameId);
|
||||
}
|
||||
|
||||
|
|
|
@ -94,7 +94,7 @@ public abstract class AbstractModelForLldbProcessActivationTest
|
|||
.filter(l -> l.trim().startsWith("*"))
|
||||
.collect(Collectors.toList())).trim();
|
||||
String procId = getIdFromCapture(line);
|
||||
String expId = getProcessPattern().matchIndices(expected.getPath()).get(1);
|
||||
String expId = getProcessPattern().matchKeys(expected.getPath()).get(1);
|
||||
assertEquals(Long.parseLong(expId, 16), Long.parseLong(procId));
|
||||
}
|
||||
|
||||
|
|
|
@ -97,7 +97,7 @@ public abstract class AbstractModelForLldbSessionActivationTest
|
|||
.filter(l -> l.trim().startsWith("*"))
|
||||
.collect(Collectors.toList())).trim();
|
||||
String procId = getIdFromCapture(line);
|
||||
String expId = getSessionPattern().matchIndices(expected.getPath()).get(0);
|
||||
String expId = getSessionPattern().matchKeys(expected.getPath()).get(0);
|
||||
assertEquals(Long.parseLong(expId, 16), Long.parseLong(procId));
|
||||
}
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@ public abstract class AbstractModelForLldbThreadActivationTest
|
|||
.filter(l -> l.trim().startsWith("*"))
|
||||
.collect(Collectors.toList())).trim();
|
||||
String threadId = getIdFromCapture(line);
|
||||
String expId = getThreadPattern().matchIndices(expected.getPath()).get(2);
|
||||
String expId = getThreadPattern().matchKeys(expected.getPath()).get(2);
|
||||
assertEquals(expId, threadId);
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,8 @@ public class BreakpointLocationRow {
|
|||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return loc.isEnabled();
|
||||
TraceRecorder recorder = provider.modelService.getRecorder(loc.getTrace());
|
||||
return recorder != null && loc.isEnabled(recorder.getSnap());
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
|
|
|
@ -210,8 +210,8 @@ public class DebuggerConsoleProvider extends ComponentProviderAdapter
|
|||
}
|
||||
|
||||
@Override
|
||||
public java.util.List<LogTableColumns> defaultSortOrder() {
|
||||
return java.util.List.of(LogTableColumns.ACTIONS, LogTableColumns.TIME);
|
||||
public List<LogTableColumns> defaultSortOrder() {
|
||||
return List.of(LogTableColumns.ACTIONS, LogTableColumns.TIME);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -228,7 +228,7 @@ public class DebuggerCopyPlan {
|
|||
Address dest = intoAddress.add(off);
|
||||
ProgramBreakpoint pb =
|
||||
new ProgramBreakpoint(into, dest, bpt.getLength(), bpt.getKinds());
|
||||
if (bpt.isEnabled()) {
|
||||
if (bpt.isEnabled(from.getSnap())) {
|
||||
pb.enable();
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -210,6 +210,11 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
|||
public ModuleTableModel() {
|
||||
super("Modules", ModuleTableColumns.class, TraceModule::getObjectKey, ModuleRow::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ModuleTableColumns> defaultSortOrder() {
|
||||
return List.of(ModuleTableColumns.BASE);
|
||||
}
|
||||
}
|
||||
|
||||
protected static class SectionTableModel
|
||||
|
@ -220,6 +225,11 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
|||
super("Sections", SectionTableColumns.class, TraceSection::getObjectKey,
|
||||
SectionRow::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SectionTableColumns> defaultSortOrder() {
|
||||
return List.of(SectionTableColumns.START);
|
||||
}
|
||||
}
|
||||
|
||||
protected static Set<TraceModule> getSelectedModulesFromModuleContext(
|
||||
|
|
|
@ -22,6 +22,7 @@ import ghidra.app.services.TraceRecorder;
|
|||
import ghidra.dbg.target.TargetExecutionStateful.TargetExecutionState;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.database.UndoableTransaction;
|
||||
|
||||
public class ThreadRow {
|
||||
|
@ -109,6 +110,12 @@ public class ThreadRow {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName();
|
||||
try {
|
||||
return getName();
|
||||
}
|
||||
catch (Exception e) {
|
||||
Msg.error(this, "Error rendering as string: " + e);
|
||||
return "<ERROR>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -288,7 +288,7 @@ public interface LogicalBreakpointInternal extends LogicalBreakpoint {
|
|||
public TraceEnablement computeEnablement() {
|
||||
TraceEnablement en = TraceEnablement.MISSING;
|
||||
for (IDHashed<TraceBreakpoint> bpt : breakpoints) {
|
||||
en = en.combine(TraceEnablement.fromBool(bpt.obj.isEnabled()));
|
||||
en = en.combine(TraceEnablement.fromBool(bpt.obj.isEnabled(recorder.getSnap())));
|
||||
if (en == TraceEnablement.MIXED) {
|
||||
return en;
|
||||
}
|
||||
|
|
|
@ -167,7 +167,7 @@ public class DefaultBreakpointRecorder implements ManagedBreakpointRecorder {
|
|||
traceBpt.setClearedSnap(snap - 1);
|
||||
}
|
||||
breakpointManager.placeBreakpoint(path, snap, range,
|
||||
traceBpt.getThreads(), traceBpt.getKinds(), traceBpt.isEnabled(),
|
||||
traceBpt.getThreads(), traceBpt.getKinds(), traceBpt.isEnabled(snap),
|
||||
traceBpt.getComment());
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
|
|
|
@ -173,7 +173,7 @@ public class DebuggerBreakpointsPluginScreenShots extends GhidraScreenShotGenera
|
|||
assertEquals(3, allBreakpoints.size());
|
||||
});
|
||||
waitForPass(() -> {
|
||||
assertFalse(bpt.isEnabled());
|
||||
assertFalse(bpt.isEnabled(0));
|
||||
});
|
||||
/**
|
||||
* TODO: Might be necessary to debounce and wait for service callbacks to settle. Sometimes,
|
||||
|
|
|
@ -31,9 +31,9 @@ import ghidra.async.AsyncTestUtils;
|
|||
import ghidra.test.ToyProgramBuilder;
|
||||
import ghidra.trace.database.ToyDBTraceBuilder;
|
||||
import ghidra.trace.database.memory.DBTraceMemoryManager;
|
||||
import ghidra.trace.database.thread.DBTraceThread;
|
||||
import ghidra.trace.database.time.DBTraceTimeManager;
|
||||
import ghidra.trace.model.memory.TraceMemoryFlag;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.trace.model.time.schedule.TraceSchedule;
|
||||
import ghidra.util.Swing;
|
||||
import ghidra.util.database.UndoableTransaction;
|
||||
|
@ -105,7 +105,7 @@ public class DebuggerTraceViewDiffPluginScreenShots extends GhidraScreenShotGene
|
|||
|
||||
@Test
|
||||
public void testCaptureDebuggerTimeSelectionDialog() throws Throwable {
|
||||
DBTraceThread thread;
|
||||
TraceThread thread;
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
DBTraceTimeManager tm = tb.trace.getTimeManager();
|
||||
thread = tb.getOrAddThread("main", 0);
|
||||
|
|
|
@ -30,7 +30,6 @@ import ghidra.framework.model.DomainFolder;
|
|||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.test.ToyProgramBuilder;
|
||||
import ghidra.trace.database.ToyDBTraceBuilder;
|
||||
import ghidra.trace.database.thread.DBTraceThread;
|
||||
import ghidra.trace.model.breakpoint.TraceBreakpointKind;
|
||||
import ghidra.trace.model.memory.TraceMemoryFlag;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
|
@ -80,7 +79,7 @@ public class DebuggerMemviewPluginScreenShots extends GhidraScreenShotGenerator
|
|||
|
||||
private void populateTraceAndPrograms() throws Exception {
|
||||
DomainFolder root = tool.getProject().getProjectData().getRootFolder();
|
||||
DBTraceThread thread1;
|
||||
TraceThread thread1;
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
thread1 = tb.trace.getThreadManager().addThread("[0]", Range.openClosed(0L, 40L));
|
||||
tb.trace.getThreadManager().addThread("[1]", Range.openClosed(3L, 50L));
|
||||
|
|
|
@ -43,8 +43,7 @@ import docking.widgets.tree.GTreeNode;
|
|||
import generic.Unique;
|
||||
import ghidra.app.plugin.core.debug.gui.action.*;
|
||||
import ghidra.app.plugin.core.debug.mapping.*;
|
||||
import ghidra.app.plugin.core.debug.service.model.DebuggerModelServiceInternal;
|
||||
import ghidra.app.plugin.core.debug.service.model.DebuggerModelServiceProxyPlugin;
|
||||
import ghidra.app.plugin.core.debug.service.model.*;
|
||||
import ghidra.app.plugin.core.debug.service.tracemgr.DebuggerTraceManagerServicePlugin;
|
||||
import ghidra.app.services.*;
|
||||
import ghidra.app.util.viewer.listingpanel.ListingPanel;
|
||||
|
@ -521,6 +520,8 @@ public abstract class AbstractGhidraHeadedDebuggerGUITest
|
|||
|
||||
@After
|
||||
public void tearDown() {
|
||||
runSwing(() -> traceManager.setSaveTracesByDefault(false));
|
||||
|
||||
if (tb != null) {
|
||||
if (traceManager != null && traceManager.getOpenTraces().contains(tb.trace)) {
|
||||
traceManager.closeTrace(tb.trace);
|
||||
|
@ -531,8 +532,6 @@ public abstract class AbstractGhidraHeadedDebuggerGUITest
|
|||
if (mb != null) {
|
||||
if (mb.testModel != null) {
|
||||
modelService.removeModel(mb.testModel);
|
||||
|
||||
runSwing(() -> traceManager.setSaveTracesByDefault(false));
|
||||
for (TraceRecorder recorder : modelService.getTraceRecorders()) {
|
||||
recorder.stopRecording();
|
||||
}
|
||||
|
@ -588,6 +587,17 @@ public abstract class AbstractGhidraHeadedDebuggerGUITest
|
|||
tb = new ToyDBTraceBuilder(trace);
|
||||
}
|
||||
|
||||
protected DebuggerTargetTraceMapper createTargetTraceMapper(TargetObject target)
|
||||
throws Exception {
|
||||
return new TestDebuggerTargetTraceMapper(target) {
|
||||
@Override
|
||||
public TraceRecorder startRecording(DebuggerModelServicePlugin service, Trace trace) {
|
||||
useTrace(trace);
|
||||
return super.startRecording(service, trace);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected void createAndOpenTrace(String langID) throws IOException {
|
||||
createTrace(langID);
|
||||
traceManager.openTrace(tb.trace);
|
||||
|
|
|
@ -137,7 +137,7 @@ public class DebuggerBreakpointMarkerPluginTest extends AbstractGhidraHeadedDebu
|
|||
createTestModel();
|
||||
mb.createTestProcessesAndThreads();
|
||||
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
Trace trace = recorder.getTrace();
|
||||
createProgramFromTrace(trace);
|
||||
intoProject(trace);
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
/* ###
|
||||
* 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.gui.breakpoint;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.dbg.target.schema.SchemaContext;
|
||||
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
|
||||
import ghidra.dbg.target.schema.XmlSchemaContext;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.util.database.UndoableTransaction;
|
||||
|
||||
public class DebuggerBreakpointsProviderObjectTest extends DebuggerBreakpointsProviderTest {
|
||||
|
||||
protected SchemaContext ctx;
|
||||
|
||||
@Override
|
||||
protected void createTrace(String langID) throws IOException {
|
||||
super.createTrace(langID);
|
||||
try {
|
||||
activateObjectsMode();
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void useTrace(Trace trace) {
|
||||
super.useTrace(trace);
|
||||
try {
|
||||
activateObjectsMode();
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void activateObjectsMode() throws Exception {
|
||||
// NOTE the use of index='...' allowing object-based managers to ID unique path
|
||||
// TODO: I guess this'll burn down if the naming scheme changes....
|
||||
int index = tb.trace.getName().startsWith("[3]") ? 3 : 1;
|
||||
ctx = XmlSchemaContext.deserialize("" + //
|
||||
"<context>" + //
|
||||
" <schema name='Session' elementResync='NEVER' attributeResync='ONCE'>" + //
|
||||
" <attribute name='Processes' schema='ProcessContainer' />" + //
|
||||
" </schema>" + //
|
||||
" <schema name='ProcessContainer' canonical='yes' elementResync='NEVER' " + //
|
||||
" attributeResync='ONCE'>" + //
|
||||
" <element index='" + index + "' schema='Process' />" + // <---- NOTE HERE
|
||||
" </schema>" + //
|
||||
" <schema name='Process' elementResync='NEVER' attributeResync='ONCE'>" + //
|
||||
" <attribute name='Threads' schema='ThreadContainer' />" + //
|
||||
" <attribute name='Memory' schema='RegionContainer' />" + //
|
||||
" <attribute name='Breakpoints' schema='BreakpointContainer' />" + //
|
||||
" </schema>" + //
|
||||
" <schema name='ThreadContainer' canonical='yes' elementResync='NEVER' " + //
|
||||
" attributeResync='ONCE'>" + //
|
||||
" <element schema='Thread' />" + //
|
||||
" </schema>" + //
|
||||
" <schema name='Thread' elementResync='NEVER' attributeResync='NEVER'>" + //
|
||||
" <interface name='Thread' />" + //
|
||||
" </schema>" + //
|
||||
" <schema name='RegionContainer' canonical='yes' elementResync='NEVER' " + //
|
||||
" attributeResync='ONCE'>" + //
|
||||
" <element schema='Region' />" + //
|
||||
" </schema>" + //
|
||||
" <schema name='Region' elementResync='NEVER' attributeResync='NEVER'>" + //
|
||||
" <interface name='MemoryRegion' />" + //
|
||||
" </schema>" + //
|
||||
" <schema name='BreakpointContainer' canonical='yes' elementResync='NEVER' " + //
|
||||
" attributeResync='ONCE'>" + //
|
||||
" <element schema='Breakpoint' />" + //
|
||||
" </schema>" + //
|
||||
" <schema name='Breakpoint' elementResync='NEVER' attributeResync='NEVER'>" + //
|
||||
" <interface name='BreakpointSpec' />" + //
|
||||
" <interface name='BreakpointLocation' />" + //
|
||||
" </schema>" + //
|
||||
"</context>");
|
||||
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
tb.trace.getObjectManager().createRootObject(ctx.getSchema(new SchemaName("Session")));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -121,7 +121,7 @@ public class DebuggerBreakpointsProviderTest extends AbstractGhidraHeadedDebugge
|
|||
createTestModel();
|
||||
mb.createTestProcessesAndThreads();
|
||||
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
Trace trace = recorder.getTrace();
|
||||
|
||||
addLiveMemoryAndBreakpoint(mb.testProcess1, recorder);
|
||||
|
@ -145,7 +145,7 @@ public class DebuggerBreakpointsProviderTest extends AbstractGhidraHeadedDebugge
|
|||
createTestModel();
|
||||
mb.createTestProcessesAndThreads();
|
||||
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
Trace trace = recorder.getTrace();
|
||||
|
||||
addLiveMemoryAndBreakpoint(mb.testProcess1, recorder);
|
||||
|
@ -210,7 +210,7 @@ public class DebuggerBreakpointsProviderTest extends AbstractGhidraHeadedDebugge
|
|||
createTestModel();
|
||||
mb.createTestProcessesAndThreads();
|
||||
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
Trace trace = recorder.getTrace();
|
||||
createProgramFromTrace(trace);
|
||||
intoProject(trace);
|
||||
|
@ -471,7 +471,7 @@ public class DebuggerBreakpointsProviderTest extends AbstractGhidraHeadedDebugge
|
|||
createTestModel();
|
||||
mb.createTestProcessesAndThreads();
|
||||
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
Trace trace = recorder.getTrace();
|
||||
createProgramFromTrace(trace);
|
||||
intoProject(trace);
|
||||
|
@ -512,12 +512,15 @@ public class DebuggerBreakpointsProviderTest extends AbstractGhidraHeadedDebugge
|
|||
public void testActionFilters() throws Exception {
|
||||
createTestModel();
|
||||
mb.createTestProcessesAndThreads();
|
||||
|
||||
TraceRecorder recorder1 = modelService.recordTarget(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
Trace trace1 = recorder1.getTrace();
|
||||
|
||||
TraceRecorder recorder3 = modelService.recordTarget(mb.testProcess3,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess3));
|
||||
createTargetTraceMapper(mb.testProcess3));
|
||||
Trace trace3 = recorder3.getTrace();
|
||||
|
||||
createProgramFromTrace(trace1);
|
||||
intoProject(trace1);
|
||||
intoProject(trace3);
|
||||
|
|
|
@ -37,7 +37,6 @@ import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingPlugin;
|
|||
import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingProvider;
|
||||
import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingServicePlugin;
|
||||
import ghidra.app.services.DebuggerStaticMappingService;
|
||||
import ghidra.app.services.TraceRecorder;
|
||||
import ghidra.dbg.DebuggerModelListener;
|
||||
import ghidra.dbg.target.TargetObject;
|
||||
import ghidra.program.model.address.*;
|
||||
|
@ -457,9 +456,7 @@ public class DebuggerCopyActionsPluginTest extends AbstractGhidraHeadedDebuggerG
|
|||
mb.testModel.addModelListener(listener);
|
||||
|
||||
mb.createTestProcessesAndThreads();
|
||||
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
useTrace(recorder.getTrace());
|
||||
modelService.recordTarget(mb.testProcess1, createTargetTraceMapper(mb.testProcess1));
|
||||
mb.testProcess1.memory.addRegion(".text", mb.rng(0x55550000, 0x5555ffff), "rx");
|
||||
mb.testProcess1.memory.setMemory(mb.addr(0x55550000), mb.arr(1, 2, 3, 4, 5, 6, 7, 8));
|
||||
waitForPass(() -> {
|
||||
|
|
|
@ -53,11 +53,11 @@ import ghidra.program.util.ProgramLocation;
|
|||
import ghidra.program.util.ProgramSelection;
|
||||
import ghidra.trace.database.ToyDBTraceBuilder;
|
||||
import ghidra.trace.database.memory.DBTraceMemoryManager;
|
||||
import ghidra.trace.database.stack.DBTraceStack;
|
||||
import ghidra.trace.database.stack.DBTraceStackManager;
|
||||
import ghidra.trace.model.*;
|
||||
import ghidra.trace.model.memory.*;
|
||||
import ghidra.trace.model.modules.TraceModule;
|
||||
import ghidra.trace.model.stack.TraceStack;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.trace.model.time.TraceSnapshot;
|
||||
import ghidra.util.database.UndoableTransaction;
|
||||
|
@ -632,7 +632,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
|||
mb.createTestProcessesAndThreads();
|
||||
|
||||
TraceRecorder recorder = modelService.recordTargetAndActivateTrace(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
Trace trace = recorder.getTrace();
|
||||
|
||||
mb.testProcess1.addRegion("exe:.text", mb.rng(0x55550000, 0x5555ffff), "rx");
|
||||
|
@ -960,7 +960,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
|||
mb.createTestProcessesAndThreads();
|
||||
|
||||
TraceRecorder recorder = modelService.recordTargetAndActivateTrace(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
Trace trace = recorder.getTrace();
|
||||
|
||||
mb.testProcess1.addRegion("exe:.text", mb.rng(0x55550000, 0x555500ff), "rx");
|
||||
|
@ -1256,7 +1256,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
|||
TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
|
||||
thread = tb.getOrAddThread("Thread 1", 0);
|
||||
DBTraceStackManager sm = tb.trace.getStackManager();
|
||||
DBTraceStack stack = sm.getStack(thread, 0, true);
|
||||
TraceStack stack = sm.getStack(thread, 0, true);
|
||||
stack.getFrame(0, true).setProgramCounter(tb.addr(0x00401234));
|
||||
stack.getFrame(1, true).setProgramCounter(tb.addr(0x00404321));
|
||||
}
|
||||
|
@ -1318,7 +1318,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
|||
regs.setValue(0, new RegisterValue(pc, new BigInteger("00401234", 16)));
|
||||
|
||||
DBTraceStackManager sm = tb.trace.getStackManager();
|
||||
DBTraceStack stack = sm.getStack(thread, 0, true);
|
||||
TraceStack stack = sm.getStack(thread, 0, true);
|
||||
stack.getFrame(0, true);
|
||||
}
|
||||
waitForDomainObject(tb.trace);
|
||||
|
@ -1348,7 +1348,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
|||
mm.addRegion("exe:.text", Range.atLeast(0L), tb.range(0x00400000, 0x0040ffff),
|
||||
TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
|
||||
thread = tb.getOrAddThread("Thread 1", 0);
|
||||
DBTraceStack stack = sm.getStack(thread, 0, true);
|
||||
TraceStack stack = sm.getStack(thread, 0, true);
|
||||
stack.getFrame(0, true).setProgramCounter(tb.addr(0x00401234));
|
||||
}
|
||||
waitForDomainObject(tb.trace);
|
||||
|
@ -1358,7 +1358,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
|||
assertEquals(tb.addr(0x00401234), listingProvider.getLocation().getAddress());
|
||||
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
DBTraceStack stack = sm.getStack(thread, 0, true);
|
||||
TraceStack stack = sm.getStack(thread, 0, true);
|
||||
stack.getFrame(0, true).setProgramCounter(tb.addr(0x00404321));
|
||||
}
|
||||
waitForDomainObject(tb.trace);
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
package ghidra.app.plugin.core.debug.gui.memory;
|
||||
|
||||
import static ghidra.lifecycle.Unfinished.*;
|
||||
import static ghidra.lifecycle.Unfinished.TODO;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.awt.*;
|
||||
|
@ -55,11 +55,11 @@ import ghidra.program.util.ProgramLocation;
|
|||
import ghidra.program.util.ProgramSelection;
|
||||
import ghidra.trace.database.ToyDBTraceBuilder;
|
||||
import ghidra.trace.database.memory.DBTraceMemoryManager;
|
||||
import ghidra.trace.database.stack.DBTraceStack;
|
||||
import ghidra.trace.database.stack.DBTraceStackManager;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.memory.*;
|
||||
import ghidra.trace.model.modules.TraceModule;
|
||||
import ghidra.trace.model.stack.TraceStack;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.trace.model.time.TraceSnapshot;
|
||||
import ghidra.util.database.UndoableTransaction;
|
||||
|
@ -468,7 +468,7 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge
|
|||
mb.createTestProcessesAndThreads();
|
||||
|
||||
TraceRecorder recorder = modelService.recordTargetAndActivateTrace(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
Trace trace = recorder.getTrace();
|
||||
|
||||
mb.testProcess1.addRegion("exe:.text", mb.rng(0x55550000, 0x5555ffff), "rx");
|
||||
|
@ -762,7 +762,7 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge
|
|||
mb.createTestProcessesAndThreads();
|
||||
|
||||
TraceRecorder recorder = modelService.recordTargetAndActivateTrace(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
Trace trace = recorder.getTrace();
|
||||
|
||||
mb.testProcess1.addRegion("exe:.text", mb.rng(0x55550000, 0x555500ff), "rx");
|
||||
|
@ -957,7 +957,7 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge
|
|||
TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
|
||||
thread = tb.getOrAddThread("Thread 1", 0);
|
||||
DBTraceStackManager sm = tb.trace.getStackManager();
|
||||
DBTraceStack stack = sm.getStack(thread, 0, true);
|
||||
TraceStack stack = sm.getStack(thread, 0, true);
|
||||
stack.getFrame(0, true).setProgramCounter(tb.addr(0x00401234));
|
||||
stack.getFrame(1, true).setProgramCounter(tb.addr(0x00404321));
|
||||
}
|
||||
|
@ -1019,7 +1019,7 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge
|
|||
regs.setValue(0, new RegisterValue(pc, new BigInteger("00401234", 16)));
|
||||
|
||||
DBTraceStackManager sm = tb.trace.getStackManager();
|
||||
DBTraceStack stack = sm.getStack(thread, 0, true);
|
||||
TraceStack stack = sm.getStack(thread, 0, true);
|
||||
stack.getFrame(0, true);
|
||||
}
|
||||
waitForDomainObject(tb.trace);
|
||||
|
@ -1049,7 +1049,7 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge
|
|||
mm.addRegion("exe:.text", Range.atLeast(0L), tb.range(0x00400000, 0x0040ffff),
|
||||
TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
|
||||
thread = tb.getOrAddThread("Thread 1", 0);
|
||||
DBTraceStack stack = sm.getStack(thread, 0, true);
|
||||
TraceStack stack = sm.getStack(thread, 0, true);
|
||||
stack.getFrame(0, true).setProgramCounter(tb.addr(0x00401234));
|
||||
}
|
||||
waitForDomainObject(tb.trace);
|
||||
|
@ -1059,7 +1059,7 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge
|
|||
assertEquals(tb.addr(0x00401234), memBytesProvider.getLocation().getAddress());
|
||||
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
DBTraceStack stack = sm.getStack(thread, 0, true);
|
||||
TraceStack stack = sm.getStack(thread, 0, true);
|
||||
stack.getFrame(0, true).setProgramCounter(tb.addr(0x00404321));
|
||||
}
|
||||
waitForDomainObject(tb.trace);
|
||||
|
@ -1074,7 +1074,7 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge
|
|||
mb.createTestProcessesAndThreads();
|
||||
|
||||
TraceRecorder recorder = modelService.recordTargetAndActivateTrace(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
Trace trace = recorder.getTrace();
|
||||
|
||||
mb.testProcess1.addRegion("exe:.text", mb.rng(0x55550000, 0x5555ffff), "rx");
|
||||
|
@ -1106,7 +1106,7 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge
|
|||
mb.createTestProcessesAndThreads();
|
||||
|
||||
TraceRecorder recorder = modelService.recordTargetAndActivateTrace(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
Trace trace = recorder.getTrace();
|
||||
|
||||
mb.testProcess1.addRegion("exe:.text", mb.rng(0x55550000, 0x5555ffff), "rx");
|
||||
|
@ -1150,7 +1150,7 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge
|
|||
mb.createTestProcessesAndThreads();
|
||||
|
||||
TraceRecorder recorder = modelService.recordTargetAndActivateTrace(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
Trace trace = recorder.getTrace();
|
||||
|
||||
mb.testProcess1.addRegion("exe:.text", mb.rng(0x55550000, 0x5555ffff), "rx");
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
/* ###
|
||||
* 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.gui.memory;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.dbg.target.schema.SchemaContext;
|
||||
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
|
||||
import ghidra.dbg.target.schema.XmlSchemaContext;
|
||||
import ghidra.util.database.UndoableTransaction;
|
||||
|
||||
public class DebuggerRegionsProviderObjectTest extends DebuggerRegionsProviderTest {
|
||||
|
||||
protected SchemaContext ctx;
|
||||
|
||||
@Override
|
||||
protected void createTrace(String langID) throws IOException {
|
||||
super.createTrace(langID);
|
||||
try {
|
||||
activateObjectsMode();
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void activateObjectsMode() throws Exception {
|
||||
ctx = XmlSchemaContext.deserialize("" + //
|
||||
"<context>" + //
|
||||
" <schema name='Session' elementResync='NEVER' attributeResync='ONCE'>" + //
|
||||
" <attribute name='Memory' schema='RegionContainer' />" + //
|
||||
" </schema>" + //
|
||||
" <schema name='RegionContainer' canonical='yes' elementResync='NEVER' " + //
|
||||
" attributeResync='ONCE'>" + //
|
||||
" <element schema='Region' />" + //
|
||||
" </schema>" + //
|
||||
" <schema name='Region' elementResync='NEVER' attributeResync='NEVER'>" + //
|
||||
" <interface name='MemoryRegion' />" + //
|
||||
" </schema>" + //
|
||||
"</context>");
|
||||
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
tb.trace.getObjectManager().createRootObject(ctx.getSchema(new SchemaName("Session")));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -62,13 +62,13 @@ public class DebuggerRegionsProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
|||
protected void addRegions() throws Exception {
|
||||
TraceMemoryManager mm = tb.trace.getMemoryManager();
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
regionExeText = mm.createRegion("Regions[/bin/echo 0x55550000]", 0,
|
||||
regionExeText = mm.createRegion("Memory[/bin/echo 0x55550000]", 0,
|
||||
tb.range(0x55550000, 0x555500ff), TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
|
||||
regionExeData = mm.createRegion("Regions[/bin/echo 0x55750000]", 0,
|
||||
regionExeData = mm.createRegion("Memory[/bin/echo 0x55750000]", 0,
|
||||
tb.range(0x55750000, 0x5575007f), TraceMemoryFlag.READ, TraceMemoryFlag.WRITE);
|
||||
regionLibText = mm.createRegion("Regions[/lib/libc.so 0x7f000000]", 0,
|
||||
regionLibText = mm.createRegion("Memory[/lib/libc.so 0x7f000000]", 0,
|
||||
tb.range(0x7f000000, 0x7f0003ff), TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
|
||||
regionLibData = mm.createRegion("Regions[/lib/libc.so 0x7f100000]", 0,
|
||||
regionLibData = mm.createRegion("Memory[/lib/libc.so 0x7f100000]", 0,
|
||||
tb.range(0x7f100000, 0x7f10003f), TraceMemoryFlag.READ, TraceMemoryFlag.WRITE);
|
||||
}
|
||||
}
|
||||
|
@ -104,7 +104,8 @@ public class DebuggerRegionsProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
|||
TraceMemoryRegion region;
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
TraceMemoryManager mm = tb.trace.getMemoryManager();
|
||||
region = mm.addRegion("bin:.text", Range.atLeast(0L), tb.range(0x00400000, 0x0040ffff),
|
||||
region = mm.addRegion("Memory[bin:.text]", Range.atLeast(0L),
|
||||
tb.range(0x00400000, 0x0040ffff),
|
||||
TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
|
||||
}
|
||||
|
||||
|
@ -114,7 +115,7 @@ public class DebuggerRegionsProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
|||
|
||||
RegionRow row = Unique.assertOne(provider.regionTableModel.getModelData());
|
||||
assertEquals(region, row.getRegion());
|
||||
assertEquals("bin:.text", row.getName());
|
||||
assertEquals("Memory[bin:.text]", row.getName());
|
||||
assertEquals(tb.addr(0x00400000), row.getMinAddress());
|
||||
assertEquals(tb.addr(0x0040ffff), row.getMaxAddress());
|
||||
assertEquals(tb.range(0x00400000, 0x0040ffff), row.getRange());
|
||||
|
@ -132,7 +133,8 @@ public class DebuggerRegionsProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
|||
TraceMemoryRegion region;
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
TraceMemoryManager mm = tb.trace.getMemoryManager();
|
||||
region = mm.addRegion("bin:.text", Range.atLeast(0L), tb.range(0x00400000, 0x0040ffff),
|
||||
region = mm.addRegion("Memory[bin:.text]", Range.atLeast(0L),
|
||||
tb.range(0x00400000, 0x0040ffff),
|
||||
TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
|
||||
}
|
||||
|
||||
|
@ -149,7 +151,8 @@ public class DebuggerRegionsProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
|||
TraceMemoryRegion region;
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
TraceMemoryManager mm = tb.trace.getMemoryManager();
|
||||
region = mm.addRegion("bin:.text", Range.atLeast(0L), tb.range(0x00400000, 0x0040ffff),
|
||||
region = mm.addRegion("Memory[bin:.text]", Range.atLeast(0L),
|
||||
tb.range(0x00400000, 0x0040ffff),
|
||||
TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
|
||||
}
|
||||
|
||||
|
@ -174,7 +177,7 @@ public class DebuggerRegionsProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
|||
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
TraceMemoryManager mm = tb.trace.getMemoryManager();
|
||||
mm.addRegion("bin:.text", Range.atLeast(0L), tb.range(0x00400000, 0x0040ffff),
|
||||
mm.addRegion("Memory[bin:.text]", Range.atLeast(0L), tb.range(0x00400000, 0x0040ffff),
|
||||
TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
|
||||
}
|
||||
|
||||
|
@ -197,7 +200,7 @@ public class DebuggerRegionsProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
|||
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
TraceMemoryManager mm = tb.trace.getMemoryManager();
|
||||
mm.addRegion("bin:.text", Range.atLeast(0L), tb.range(0x00400000, 0x0040ffff),
|
||||
mm.addRegion("Memory[bin:.text]", Range.atLeast(0L), tb.range(0x00400000, 0x0040ffff),
|
||||
TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
|
||||
|
||||
waitForDomainObject(tb.trace);
|
||||
|
@ -218,7 +221,8 @@ public class DebuggerRegionsProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
|||
TraceMemoryRegion region;
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
TraceMemoryManager mm = tb.trace.getMemoryManager();
|
||||
region = mm.addRegion("bin:.text", Range.atLeast(0L), tb.range(0x00400000, 0x0040ffff),
|
||||
region = mm.addRegion("Memory[bin:.text]", Range.atLeast(0L),
|
||||
tb.range(0x00400000, 0x0040ffff),
|
||||
TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
|
||||
}
|
||||
|
||||
|
@ -333,7 +337,8 @@ public class DebuggerRegionsProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
|||
TraceMemoryRegion region;
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
TraceMemoryManager mm = tb.trace.getMemoryManager();
|
||||
region = mm.addRegion("bin:.text", Range.atLeast(0L), tb.range(0x00400000, 0x0040ffff),
|
||||
region = mm.addRegion("Memory[bin:.text]", Range.atLeast(0L),
|
||||
tb.range(0x00400000, 0x0040ffff),
|
||||
TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
|
||||
}
|
||||
|
||||
|
@ -365,7 +370,8 @@ public class DebuggerRegionsProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
|||
TraceMemoryRegion region;
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
TraceMemoryManager mm = tb.trace.getMemoryManager();
|
||||
region = mm.addRegion("bin:.text", Range.atLeast(0L), tb.range(0x00400000, 0x0040ffff),
|
||||
region = mm.addRegion("Memory[bin:.text]", Range.atLeast(0L),
|
||||
tb.range(0x00400000, 0x0040ffff),
|
||||
TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
/* ###
|
||||
* 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.gui.modules;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.dbg.target.schema.SchemaContext;
|
||||
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.dbg.target.schema.XmlSchemaContext;
|
||||
import ghidra.util.database.UndoableTransaction;
|
||||
|
||||
public class DebuggerModulesProviderObjectTest extends DebuggerModulesProviderTest {
|
||||
|
||||
protected SchemaContext ctx;
|
||||
|
||||
@Override
|
||||
protected void createTrace(String langID) throws IOException {
|
||||
super.createTrace(langID);
|
||||
try {
|
||||
activateObjectsMode();
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void useTrace(Trace trace) {
|
||||
super.useTrace(trace);
|
||||
try {
|
||||
activateObjectsMode();
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void activateObjectsMode() throws Exception {
|
||||
// NOTE the use of index='1' allowing object-based managers to ID unique path
|
||||
ctx = XmlSchemaContext.deserialize("" + //
|
||||
"<context>" + //
|
||||
" <schema name='Session' elementResync='NEVER' attributeResync='ONCE'>" + //
|
||||
" <attribute name='Processes' schema='ProcessContainer' />" + //
|
||||
" </schema>" + //
|
||||
" <schema name='ProcessContainer' canonical='yes' elementResync='NEVER' " + //
|
||||
" attributeResync='ONCE'>" + //
|
||||
" <element index='1' schema='Process' />" + // <---- NOTE HERE
|
||||
" </schema>" + //
|
||||
" <schema name='Process' elementResync='NEVER' attributeResync='ONCE'>" + //
|
||||
" <attribute name='Modules' schema='ModuleContainer' />" + //
|
||||
" <attribute name='Memory' schema='RegionContainer' />" + //
|
||||
" </schema>" + //
|
||||
" <schema name='RegionContainer' canonical='yes' elementResync='NEVER' " + //
|
||||
" attributeResync='ONCE'>" + //
|
||||
" <element schema='Region' />" + //
|
||||
" </schema>" + //
|
||||
" <schema name='Region' elementResync='NEVER' attributeResync='NEVER'>" + //
|
||||
" <interface name='MemoryRegion' />" + //
|
||||
" </schema>" + //
|
||||
" <schema name='ModuleContainer' canonical='yes' elementResync='NEVER' " + //
|
||||
" attributeResync='ONCE'>" + //
|
||||
" <element schema='Module' />" + //
|
||||
" </schema>" + //
|
||||
" <schema name='Module' elementResync='NEVER' attributeResync='NEVER'>" + //
|
||||
" <interface name='Module' />" + //
|
||||
" <attribute name='Sections' schema='SectionContainer' />" + //
|
||||
" </schema>" + //
|
||||
" <schema name='SectionContainer' canonical='yes' elementResync='NEVER' " + //
|
||||
" attributeResync='ONCE'>" + //
|
||||
" <element schema='Section' />" + //
|
||||
" </schema>" + //
|
||||
" <schema name='Section' elementResync='NEVER' attributeResync='NEVER'>" + //
|
||||
" <interface name='Section' />" + //
|
||||
" </schema>" + //
|
||||
"</context>");
|
||||
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
tb.trace.getObjectManager().createRootObject(ctx.getSchema(new SchemaName("Session")));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -100,7 +100,8 @@ public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
|||
else {
|
||||
throw new AssertionError();
|
||||
}
|
||||
manager.addRegion(module.getName() + ":" + section.getName(),
|
||||
manager.addRegion(
|
||||
"Processes[1].Memory[" + module.getName() + ":" + section.getName() + "]",
|
||||
module.getLifespan(), section.getRange(), flags);
|
||||
}
|
||||
}
|
||||
|
@ -110,19 +111,19 @@ public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
|||
protected void addModules() throws Exception {
|
||||
TraceModuleManager manager = tb.trace.getModuleManager();
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
modExe = manager.addLoadedModule("first_proc", "first_proc",
|
||||
modExe = manager.addLoadedModule("Processes[1].Modules[first_proc]", "first_proc",
|
||||
tb.range(0x55550000, 0x5575007f), 0);
|
||||
secExeText =
|
||||
modExe.addSection("first_proc[.text]", ".text", tb.range(0x55550000, 0x555500ff));
|
||||
secExeData =
|
||||
modExe.addSection("first_proc[.data]", ".data", tb.range(0x55750000, 0x5575007f));
|
||||
secExeText = modExe.addSection("Processes[1].Modules[first_proc].Sections[.text]",
|
||||
".text", tb.range(0x55550000, 0x555500ff));
|
||||
secExeData = modExe.addSection("Processes[1].Modules[first_proc].Sections[.data]",
|
||||
".data", tb.range(0x55750000, 0x5575007f));
|
||||
|
||||
modLib = manager.addLoadedModule("some_lib", "some_lib",
|
||||
modLib = manager.addLoadedModule("Processes[1].Modules[some_lib]", "some_lib",
|
||||
tb.range(0x7f000000, 0x7f10003f), 0);
|
||||
secLibText =
|
||||
modLib.addSection("some_lib[.text]", ".text", tb.range(0x7f000000, 0x7f0003ff));
|
||||
secLibData =
|
||||
modLib.addSection("some_lib[.data]", ".data", tb.range(0x7f100000, 0x7f10003f));
|
||||
secLibText = modLib.addSection("Processes[1].Modules[some_lib].Sections[.text]",
|
||||
".text", tb.range(0x7f000000, 0x7f0003ff));
|
||||
secLibData = modLib.addSection("Processes[1].Modules[some_lib].Sections[.data]",
|
||||
".data", tb.range(0x7f100000, 0x7f10003f));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,8 +145,10 @@ public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
|||
}
|
||||
|
||||
protected void assertProviderPopulated() {
|
||||
List<ModuleRow> modulesDisplayed = modulesProvider.moduleTableModel.getModelData();
|
||||
// I should be able to assume this is sorted by base address
|
||||
List<ModuleRow> modulesDisplayed =
|
||||
new ArrayList<>(modulesProvider.moduleTableModel.getModelData());
|
||||
modulesDisplayed.sort(Comparator.comparing(r -> r.getBase()));
|
||||
// I should be able to assume this is sorted by base address. It's the default sort column.
|
||||
assertEquals(2, modulesDisplayed.size());
|
||||
|
||||
ModuleRow execRow = modulesDisplayed.get(0);
|
||||
|
@ -156,7 +159,9 @@ public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
|||
ModuleRow libRow = modulesDisplayed.get(1);
|
||||
assertEquals(tb.addr(0x7f000000), libRow.getBase());
|
||||
|
||||
List<SectionRow> sectionsDisplayed = modulesProvider.sectionTableModel.getModelData();
|
||||
List<SectionRow> sectionsDisplayed =
|
||||
new ArrayList<>(modulesProvider.sectionTableModel.getModelData());
|
||||
sectionsDisplayed.sort(Comparator.comparing(r -> r.getStart()));
|
||||
assertEquals(4, sectionsDisplayed.size());
|
||||
|
||||
SectionRow execTextRow = sectionsDisplayed.get(0);
|
||||
|
@ -261,13 +266,17 @@ public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
|||
}
|
||||
waitForDomainObject(tb.trace);
|
||||
|
||||
List<ModuleRow> modulesDisplayed = modulesProvider.moduleTableModel.getModelData();
|
||||
List<ModuleRow> modulesDisplayed =
|
||||
new ArrayList<>(modulesProvider.moduleTableModel.getModelData());
|
||||
modulesDisplayed.sort(Comparator.comparing(r -> r.getBase()));
|
||||
assertEquals(1, modulesDisplayed.size());
|
||||
|
||||
ModuleRow libRow = modulesDisplayed.get(0);
|
||||
assertEquals("some_lib", libRow.getName());
|
||||
|
||||
List<SectionRow> sectionsDisplayed = modulesProvider.sectionTableModel.getModelData();
|
||||
List<SectionRow> sectionsDisplayed =
|
||||
new ArrayList<>(modulesProvider.sectionTableModel.getModelData());
|
||||
sectionsDisplayed.sort(Comparator.comparing(r -> r.getStart()));
|
||||
assertEquals(2, sectionsDisplayed.size());
|
||||
|
||||
SectionRow libTextRow = sectionsDisplayed.get(0);
|
||||
|
@ -543,13 +552,15 @@ public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
|||
mb.createTestProcessesAndThreads();
|
||||
|
||||
TraceRecorder recorder = modelService.recordTargetAndActivateTrace(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
Trace trace = recorder.getTrace();
|
||||
|
||||
// TODO: A region should not be required first. Just to get a memMapper?
|
||||
mb.testProcess1.addRegion("first_proc:.text", mb.rng(0x55550000, 0x555500ff), "rx");
|
||||
mb.testProcess1.addRegion("Memory[first_proc:.text]", mb.rng(0x55550000, 0x555500ff),
|
||||
"rx");
|
||||
TestTargetModule module =
|
||||
mb.testProcess1.modules.addModule("first_proc", mb.rng(0x55550000, 0x555500ff));
|
||||
mb.testProcess1.modules.addModule("Modules[first_proc]",
|
||||
mb.rng(0x55550000, 0x555500ff));
|
||||
// NOTE: A section should not be required at this point.
|
||||
TestTargetTypedefDataType typedef = module.types.addTypedefDataType("myInt",
|
||||
new DefaultTargetPrimitiveDataType(PrimitiveKind.SINT, 4));
|
||||
|
@ -577,7 +588,7 @@ public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
|||
conv.convertTargetDataType(typedef).get(DEFAULT_WAIT_TIMEOUT, TimeUnit.MILLISECONDS);
|
||||
// TODO: Some heuristic or convention to extract the module name, if applicable
|
||||
waitForPass(() -> {
|
||||
DataType actType = dtm.getDataType("/Processes[1].Modules[first_proc].Types/myInt");
|
||||
DataType actType = dtm.getDataType("/Modules[first_proc].Types/myInt");
|
||||
assertTypeEquals(expType, actType);
|
||||
});
|
||||
|
||||
|
@ -596,11 +607,12 @@ public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
|||
mb.createTestProcessesAndThreads();
|
||||
|
||||
TraceRecorder recorder = modelService.recordTargetAndActivateTrace(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
Trace trace = recorder.getTrace();
|
||||
|
||||
// TODO: A region should not be required first. Just to get a memMapper?
|
||||
mb.testProcess1.addRegion("first_proc:.text", mb.rng(0x55550000, 0x555500ff), "rx");
|
||||
mb.testProcess1.addRegion("first_proc:.text", mb.rng(0x55550000, 0x555500ff),
|
||||
"rx");
|
||||
TestTargetModule module =
|
||||
mb.testProcess1.modules.addModule("first_proc", mb.rng(0x55550000, 0x555500ff));
|
||||
// NOTE: A section should not be required at this point.
|
||||
|
|
|
@ -146,7 +146,7 @@ public class DebuggerRegistersProviderTest extends AbstractGhidraHeadedDebuggerG
|
|||
Register::isBaseRegister);
|
||||
|
||||
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
|
||||
waitFor(() -> {
|
||||
TraceThread thread = recorder.getTraceThread(mb.testThread1);
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
/* ###
|
||||
* 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.gui.stack;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.dbg.target.schema.SchemaContext;
|
||||
import ghidra.dbg.target.schema.XmlSchemaContext;
|
||||
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.util.database.UndoableTransaction;
|
||||
|
||||
public class DebuggerStackProviderObjectTest extends DebuggerStackProviderTest {
|
||||
|
||||
protected SchemaContext ctx;
|
||||
|
||||
@Override
|
||||
protected void createTrace(String langID) throws IOException {
|
||||
super.createTrace(langID);
|
||||
try {
|
||||
activateObjectsMode();
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void useTrace(Trace trace) {
|
||||
super.useTrace(trace);
|
||||
try {
|
||||
activateObjectsMode();
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void activateObjectsMode() throws Exception {
|
||||
// NOTE the use of index='1' allowing object-based managers to ID unique path
|
||||
ctx = XmlSchemaContext.deserialize("" + //
|
||||
"<context>" + //
|
||||
" <schema name='Session' elementResync='NEVER' attributeResync='ONCE'>" + //
|
||||
" <attribute name='Processes' schema='ProcessContainer' />" + //
|
||||
" </schema>" + //
|
||||
" <schema name='ProcessContainer' canonical='yes' elementResync='NEVER' " + //
|
||||
" attributeResync='ONCE'>" + //
|
||||
" <element index='1' schema='Process' />" + // <---- NOTE HERE
|
||||
" </schema>" + //
|
||||
" <schema name='Process' elementResync='NEVER' attributeResync='ONCE'>" + //
|
||||
" <attribute name='Threads' schema='ThreadContainer' />" + //
|
||||
" <attribute name='Memory' schema='RegionContainer' />" + //
|
||||
" </schema>" + //
|
||||
" <schema name='ThreadContainer' canonical='yes' elementResync='NEVER' " + //
|
||||
" attributeResync='ONCE'>" + //
|
||||
" <element schema='Thread' />" + //
|
||||
" </schema>" + //
|
||||
" <schema name='Thread' elementResync='NEVER' attributeResync='NEVER'>" + //
|
||||
" <interface name='Thread' />" + //
|
||||
" <attribute name='Stack' schema='Stack' />" + //
|
||||
" </schema>" + //
|
||||
" <schema name='Stack' canonical='yes' elementResync='NEVER' " + //
|
||||
" attributeResync='ONCE'>" + //
|
||||
" <interface name='Stack' />" + //
|
||||
" <element schema='Frame' />" + //
|
||||
" </schema>" + //
|
||||
" <schema name='Frame' elementResync='NEVER' attributeResync='NEVER'>" + //
|
||||
" <interface name='StackFrame' />" + //
|
||||
" </schema>" + //
|
||||
" <schema name='RegionContainer' canonical='yes' elementResync='NEVER' " + //
|
||||
" attributeResync='ONCE'>" + //
|
||||
" <element schema='Region' />" + //
|
||||
" </schema>" + //
|
||||
" <schema name='Region' elementResync='NEVER' attributeResync='NEVER'>" + //
|
||||
" <interface name='MemoryRegion' />" + //
|
||||
" </schema>" + //
|
||||
"</context>");
|
||||
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
tb.trace.getObjectManager().createRootObject(ctx.getSchema(new SchemaName("Session")));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -155,7 +155,7 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerGUITe
|
|||
public void testActivateThreadNoStackNoRegsEmpty() throws Exception {
|
||||
createAndOpenTrace();
|
||||
|
||||
TraceThread thread = addThread("Thread 1");
|
||||
TraceThread thread = addThread("Processes[1].Threads[1]");
|
||||
waitForDomainObject(tb.trace);
|
||||
|
||||
traceManager.activateThread(thread);
|
||||
|
@ -168,7 +168,7 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerGUITe
|
|||
public void testActivateThreadNoStackRegsSynthetic() throws Exception {
|
||||
createAndOpenTrace();
|
||||
|
||||
TraceThread thread = addThread("Thread 1");
|
||||
TraceThread thread = addThread("Processes[1].Threads[1]");
|
||||
addRegVals(thread);
|
||||
waitForDomainObject(tb.trace);
|
||||
|
||||
|
@ -182,7 +182,7 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerGUITe
|
|||
public void testActivateThreadRegsThenAddEmptyStackEmpty() throws Exception {
|
||||
createAndOpenTrace();
|
||||
|
||||
TraceThread thread = addThread("Thread 1");
|
||||
TraceThread thread = addThread("Processes[1].Threads[1]");
|
||||
addRegVals(thread);
|
||||
addStack(thread);
|
||||
waitForDomainObject(tb.trace);
|
||||
|
@ -197,7 +197,7 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerGUITe
|
|||
public void testActivateThreadThenAddStackPopulatesProvider() throws Exception {
|
||||
createAndOpenTrace();
|
||||
|
||||
TraceThread thread = addThread("Thread 1");
|
||||
TraceThread thread = addThread("Processes[1].Threads[1]");
|
||||
traceManager.activateThread(thread);
|
||||
TraceStack stack = addStack(thread);
|
||||
addStackFrames(stack);
|
||||
|
@ -210,7 +210,7 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerGUITe
|
|||
public void testAddStackThenActivateThreadPopulatesProvider() throws Exception {
|
||||
createAndOpenTrace();
|
||||
|
||||
TraceThread thread = addThread("Thread 1");
|
||||
TraceThread thread = addThread("Processes[1].Threads[1]");
|
||||
TraceStack stack = addStack(thread);
|
||||
addStackFrames(stack);
|
||||
waitForDomainObject(tb.trace);
|
||||
|
@ -225,7 +225,7 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerGUITe
|
|||
public void testAppendStackUpdatesProvider() throws Exception {
|
||||
createAndOpenTrace();
|
||||
|
||||
TraceThread thread = addThread("Thread 1");
|
||||
TraceThread thread = addThread("Processes[1].Threads[1]");
|
||||
TraceStack stack = addStack(thread);
|
||||
addStackFrames(stack);
|
||||
waitForDomainObject(tb.trace);
|
||||
|
@ -250,7 +250,7 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerGUITe
|
|||
public void testPushStackUpdatesProvider() throws Exception {
|
||||
createAndOpenTrace();
|
||||
|
||||
TraceThread thread = addThread("Thread 1");
|
||||
TraceThread thread = addThread("Processes[1].Threads[1]");
|
||||
TraceStack stack = addStack(thread);
|
||||
addStackFrames(stack);
|
||||
waitForDomainObject(tb.trace);
|
||||
|
@ -275,7 +275,7 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerGUITe
|
|||
public void testTruncateStackUpdatesProvider() throws Exception {
|
||||
createAndOpenTrace();
|
||||
|
||||
TraceThread thread = addThread("Thread 1");
|
||||
TraceThread thread = addThread("Processes[1].Threads[1]");
|
||||
TraceStack stack = addStack(thread);
|
||||
addStackFrames(stack);
|
||||
waitForDomainObject(tb.trace);
|
||||
|
@ -298,7 +298,7 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerGUITe
|
|||
public void testPopStackUpdatesProvider() throws Exception {
|
||||
createAndOpenTrace();
|
||||
|
||||
TraceThread thread = addThread("Thread 1");
|
||||
TraceThread thread = addThread("Processes[1].Threads[1]");
|
||||
TraceStack stack = addStack(thread);
|
||||
addStackFrames(stack);
|
||||
waitForDomainObject(tb.trace);
|
||||
|
@ -321,7 +321,7 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerGUITe
|
|||
public void testDeleteStackUpdatesProvider() throws Exception {
|
||||
createAndOpenTrace();
|
||||
|
||||
TraceThread thread = addThread("Thread 1");
|
||||
TraceThread thread = addThread("Processes[1].Threads[1]");
|
||||
TraceStack stack = addStack(thread);
|
||||
addStackFrames(stack);
|
||||
waitForDomainObject(tb.trace);
|
||||
|
@ -343,8 +343,8 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerGUITe
|
|||
public void testActivateOtherThread() throws Exception {
|
||||
createAndOpenTrace();
|
||||
|
||||
TraceThread thread1 = addThread("Thread 1");
|
||||
TraceThread thread2 = addThread("Thread 2");
|
||||
TraceThread thread1 = addThread("Processes[1].Threads[1]");
|
||||
TraceThread thread2 = addThread("Processes[1].Threads[2]");
|
||||
TraceStack stack = addStack(thread1);
|
||||
addStackFrames(stack);
|
||||
waitForDomainObject(tb.trace);
|
||||
|
@ -364,7 +364,7 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerGUITe
|
|||
public void testActivateSnap() throws Exception {
|
||||
createAndOpenTrace();
|
||||
|
||||
TraceThread thread = addThread("Thread 1");
|
||||
TraceThread thread = addThread("Processes[1].Threads[1]");
|
||||
TraceStack stack = addStack(thread);
|
||||
addStackFrames(stack);
|
||||
waitForDomainObject(tb.trace);
|
||||
|
@ -389,7 +389,7 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerGUITe
|
|||
public void testCloseCurrentTraceEmpty() throws Exception {
|
||||
createAndOpenTrace();
|
||||
|
||||
TraceThread thread = addThread("Thread 1");
|
||||
TraceThread thread = addThread("Processes[1].Threads[1]");
|
||||
TraceStack stack = addStack(thread);
|
||||
addStackFrames(stack);
|
||||
waitForDomainObject(tb.trace);
|
||||
|
@ -410,7 +410,7 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerGUITe
|
|||
public void testSelectRowActivatesFrame() throws Exception {
|
||||
createAndOpenTrace();
|
||||
|
||||
TraceThread thread = addThread("Thread 1");
|
||||
TraceThread thread = addThread("Processes[1].Threads[1]");
|
||||
TraceStack stack = addStack(thread);
|
||||
addStackFrames(stack);
|
||||
waitForDomainObject(tb.trace);
|
||||
|
@ -435,7 +435,7 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerGUITe
|
|||
public void testActivateFrameSelectsRow() throws Exception {
|
||||
createAndOpenTrace();
|
||||
|
||||
TraceThread thread = addThread("Thread 1");
|
||||
TraceThread thread = addThread("Processes[1].Threads[1]");
|
||||
TraceStack stack = addStack(thread);
|
||||
addStackFrames(stack);
|
||||
waitForDomainObject(tb.trace);
|
||||
|
@ -467,7 +467,7 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerGUITe
|
|||
traceManager.openTrace(tb.trace);
|
||||
programManager.openProgram(program);
|
||||
|
||||
TraceThread thread = addThread("Thread 1");
|
||||
TraceThread thread = addThread("Processes[1].Threads[1]");
|
||||
TraceStack stack = addStack(thread);
|
||||
addStackFrames(stack);
|
||||
waitForDomainObject(tb.trace);
|
||||
|
@ -491,7 +491,8 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerGUITe
|
|||
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
tb.trace.getMemoryManager()
|
||||
.addRegion("bin:.text", Range.atLeast(0L), tb.drng(0x00400000, 0x00400fff),
|
||||
.addRegion("Processes[1].Memory[bin:.text]", Range.atLeast(0L),
|
||||
tb.drng(0x00400000, 0x00400fff),
|
||||
TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
|
||||
|
||||
TraceLocation dloc =
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
/* ###
|
||||
* 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.gui.thread;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.dbg.target.schema.SchemaContext;
|
||||
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
|
||||
import ghidra.dbg.target.schema.XmlSchemaContext;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.util.database.UndoableTransaction;
|
||||
|
||||
public class DebuggerThreadsProviderObjectTest extends DebuggerThreadsProviderTest {
|
||||
|
||||
protected SchemaContext ctx;
|
||||
|
||||
@Override
|
||||
protected void createTrace(String langID) throws IOException {
|
||||
super.createTrace(langID);
|
||||
try {
|
||||
activateObjectsMode();
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void useTrace(Trace trace) {
|
||||
super.useTrace(trace);
|
||||
try {
|
||||
activateObjectsMode();
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void activateObjectsMode() throws Exception {
|
||||
// NOTE the use of index='1' allowing object-based managers to ID unique path
|
||||
ctx = XmlSchemaContext.deserialize("" + //
|
||||
"<context>" + //
|
||||
" <schema name='Session' elementResync='NEVER' attributeResync='ONCE'>" + //
|
||||
" <attribute name='Processes' schema='ProcessContainer' />" + //
|
||||
" </schema>" + //
|
||||
" <schema name='ProcessContainer' canonical='yes' elementResync='NEVER' " + //
|
||||
" attributeResync='ONCE'>" + //
|
||||
" <element index='1' schema='Process' />" + // <---- NOTE HERE
|
||||
" </schema>" + //
|
||||
" <schema name='Process' elementResync='NEVER' attributeResync='ONCE'>" + //
|
||||
" <attribute name='Threads' schema='ThreadContainer' />" + //
|
||||
" </schema>" + //
|
||||
" <schema name='ThreadContainer' canonical='yes' elementResync='NEVER' " + //
|
||||
" attributeResync='ONCE'>" + //
|
||||
" <element schema='Thread' />" + //
|
||||
" </schema>" + //
|
||||
" <schema name='Thread' elementResync='NEVER' attributeResync='NEVER'>" + //
|
||||
" <interface name='Thread' />" + //
|
||||
" </schema>" + //
|
||||
"</context>");
|
||||
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
tb.trace.getObjectManager().createRootObject(ctx.getSchema(new SchemaName("Session")));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -55,9 +55,9 @@ public class DebuggerThreadsProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
|||
protected void addThreads() throws Exception {
|
||||
TraceThreadManager manager = tb.trace.getThreadManager();
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
thread1 = manager.addThread("Thread 1", Range.atLeast(0L));
|
||||
thread1 = manager.addThread("Processes[1].Threads[1]", Range.atLeast(0L));
|
||||
thread1.setComment("A comment");
|
||||
thread2 = manager.addThread("Thread 2", Range.closed(5L, 10L));
|
||||
thread2 = manager.addThread("Processes[1].Threads[2]", Range.closed(5L, 10L));
|
||||
thread2.setComment("Another comment");
|
||||
}
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ public class DebuggerThreadsProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
|||
|
||||
ThreadRow thread1Record = threadsDisplayed.get(0);
|
||||
assertEquals(thread1, thread1Record.getThread());
|
||||
assertEquals("Thread 1", thread1Record.getName());
|
||||
assertEquals("Processes[1].Threads[1]", thread1Record.getName());
|
||||
assertEquals(Range.atLeast(0L), thread1Record.getLifespan());
|
||||
assertEquals(0, thread1Record.getCreationSnap());
|
||||
assertEquals("", thread1Record.getDestructionSnap());
|
||||
|
@ -475,13 +475,15 @@ public class DebuggerThreadsProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
|||
// Not live, so no seek
|
||||
assertEquals(0, traceManager.getCurrentSnap());
|
||||
|
||||
tb.close();
|
||||
|
||||
createTestModel();
|
||||
mb.createTestProcessesAndThreads();
|
||||
// Threads needs registers to be recognized by the recorder
|
||||
mb.createTestThreadRegisterBanks();
|
||||
|
||||
TraceRecorder recorder = modelService.recordTargetAndActivateTrace(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
Trace trace = recorder.getTrace();
|
||||
|
||||
// Wait till two threads are observed in the database
|
||||
|
|
|
@ -208,7 +208,7 @@ public class DebuggerWatchesProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
|||
mb.testProcess1.memory.writeMemory(mb.addr(0x00400000), tb.arr(1, 2, 3, 4));
|
||||
|
||||
recorder = modelService.recordTarget(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
Trace trace = recorder.getTrace();
|
||||
TraceThread thread = waitForValue(() -> recorder.getTraceThread(mb.testThread1));
|
||||
|
||||
|
@ -348,7 +348,7 @@ public class DebuggerWatchesProviderTest extends AbstractGhidraHeadedDebuggerGUI
|
|||
mb.testProcess1.addRegion(".text", mb.rng(0x00400000, 0x00401000), "rx");
|
||||
|
||||
recorder = modelService.recordTarget(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
Trace trace = recorder.getTrace();
|
||||
TraceThread thread = waitForValue(() -> recorder.getTraceThread(mb.testThread1));
|
||||
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
/* ###
|
||||
* 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.breakpoint;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ghidra.dbg.target.schema.SchemaContext;
|
||||
import ghidra.dbg.target.schema.XmlSchemaContext;
|
||||
import ghidra.dbg.target.schema.TargetObjectSchema.SchemaName;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.util.database.UndoableTransaction;
|
||||
|
||||
public class DebuggerLogicalBreakpointServiceObjectTest
|
||||
extends DebuggerLogicalBreakpointServiceTest {
|
||||
|
||||
protected SchemaContext ctx;
|
||||
|
||||
@Override
|
||||
protected void createTrace(String langID) throws IOException {
|
||||
super.createTrace(langID);
|
||||
try {
|
||||
activateObjectsMode();
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void useTrace(Trace trace) {
|
||||
super.useTrace(trace);
|
||||
try {
|
||||
activateObjectsMode();
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void activateObjectsMode() throws Exception {
|
||||
// NOTE the use of index='...' allowing object-based managers to ID unique path
|
||||
// TODO: I guess this'll burn down if the naming scheme changes....
|
||||
int index = tb.trace.getName().startsWith("[3]") ? 3 : 1;
|
||||
ctx = XmlSchemaContext.deserialize("" + //
|
||||
"<context>" + //
|
||||
" <schema name='Session' elementResync='NEVER' attributeResync='ONCE'>" + //
|
||||
" <attribute name='Processes' schema='ProcessContainer' />" + //
|
||||
" </schema>" + //
|
||||
" <schema name='ProcessContainer' canonical='yes' elementResync='NEVER' " + //
|
||||
" attributeResync='ONCE'>" + //
|
||||
" <element index='" + index + "' schema='Process' />" + // <---- NOTE HERE
|
||||
" </schema>" + //
|
||||
" <schema name='Process' elementResync='NEVER' attributeResync='ONCE'>" + //
|
||||
" <attribute name='Threads' schema='ThreadContainer' />" + //
|
||||
" <attribute name='Memory' schema='RegionContainer' />" + //
|
||||
" <attribute name='Breakpoints' schema='BreakpointContainer' />" + //
|
||||
" </schema>" + //
|
||||
" <schema name='ThreadContainer' canonical='yes' elementResync='NEVER' " + //
|
||||
" attributeResync='ONCE'>" + //
|
||||
" <element schema='Thread' />" + //
|
||||
" </schema>" + //
|
||||
" <schema name='Thread' elementResync='NEVER' attributeResync='NEVER'>" + //
|
||||
" <interface name='Thread' />" + //
|
||||
" </schema>" + //
|
||||
" <schema name='RegionContainer' canonical='yes' elementResync='NEVER' " + //
|
||||
" attributeResync='ONCE'>" + //
|
||||
" <element schema='Region' />" + //
|
||||
" </schema>" + //
|
||||
" <schema name='Region' elementResync='NEVER' attributeResync='NEVER'>" + //
|
||||
" <interface name='MemoryRegion' />" + //
|
||||
" </schema>" + //
|
||||
" <schema name='BreakpointContainer' canonical='yes' elementResync='NEVER' " + //
|
||||
" attributeResync='ONCE'>" + //
|
||||
" <element schema='Breakpoint' />" + //
|
||||
" </schema>" + //
|
||||
" <schema name='Breakpoint' elementResync='NEVER' attributeResync='NEVER'>" + //
|
||||
" <interface name='BreakpointSpec' />" + //
|
||||
" <interface name='BreakpointLocation' />" + //
|
||||
" </schema>" + //
|
||||
"</context>");
|
||||
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
tb.trace.getObjectManager().createRootObject(ctx.getSchema(new SchemaName("Session")));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -74,7 +74,8 @@ public class DebuggerLogicalBreakpointServiceTest extends AbstractGhidraHeadedDe
|
|||
|
||||
@Override
|
||||
public synchronized void breakpointUpdated(LogicalBreakpoint lb) {
|
||||
Msg.debug(this, "LogicalBreakpoint updated: " + lb);
|
||||
Msg.debug(this,
|
||||
"LogicalBreakpoint updated: (" + System.identityHashCode(lb) + ")" + lb);
|
||||
assertTrue(current.contains(lb));
|
||||
}
|
||||
|
||||
|
@ -165,12 +166,12 @@ public class DebuggerLogicalBreakpointServiceTest extends AbstractGhidraHeadedDe
|
|||
|
||||
public void startRecorder1() throws Throwable {
|
||||
recorder1 = modelService.recordTarget(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
}
|
||||
|
||||
public void startRecorder3() throws Throwable {
|
||||
recorder3 = modelService.recordTarget(mb.testProcess3,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess3));
|
||||
createTargetTraceMapper(mb.testProcess3));
|
||||
}
|
||||
|
||||
@After
|
||||
|
|
|
@ -213,7 +213,7 @@ public class DebuggerModelServiceTest extends AbstractGhidraHeadedDebuggerGUITes
|
|||
|
||||
assertEquals(Set.of(), Set.copyOf(modelService.getTraceRecorders()));
|
||||
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
|
||||
assertEquals(Set.of(recorder), Set.copyOf(modelService.getTraceRecorders()));
|
||||
}
|
||||
|
@ -228,7 +228,7 @@ public class DebuggerModelServiceTest extends AbstractGhidraHeadedDebuggerGUITes
|
|||
new CollectionChangeDelegateWrapper<>(recorderChangeListener);
|
||||
modelService.addTraceRecordersChangedListener(wrapper);
|
||||
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
|
||||
new VerificationsInOrder() {
|
||||
{
|
||||
|
@ -243,7 +243,7 @@ public class DebuggerModelServiceTest extends AbstractGhidraHeadedDebuggerGUITes
|
|||
mb.createTestProcessesAndThreads();
|
||||
|
||||
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
// Strong ref
|
||||
CollectionChangeDelegateWrapper<TraceRecorder> wrapper =
|
||||
new CollectionChangeDelegateWrapper<>(recorderChangeListener);
|
||||
|
@ -265,7 +265,7 @@ public class DebuggerModelServiceTest extends AbstractGhidraHeadedDebuggerGUITes
|
|||
mb.createTestProcessesAndThreads();
|
||||
|
||||
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
assertNotNull(recorder);
|
||||
waitOn(recorder.init()); // Already initializing, just wait for it to complete
|
||||
|
||||
|
@ -281,7 +281,7 @@ public class DebuggerModelServiceTest extends AbstractGhidraHeadedDebuggerGUITes
|
|||
mb.createTestProcessesAndThreads();
|
||||
|
||||
modelService.recordTargetAndActivateTrace(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
waitForSwing();
|
||||
|
||||
Trace trace = traceManager.getCurrentTrace();
|
||||
|
@ -290,7 +290,7 @@ public class DebuggerModelServiceTest extends AbstractGhidraHeadedDebuggerGUITes
|
|||
traceManager.closeTrace(trace);
|
||||
waitOn(mb.testModel.close());
|
||||
waitForPass(() -> {
|
||||
assertEquals(List.of(), trace.getConsumerList());
|
||||
assertEquals(List.of(tb), trace.getConsumerList());
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -300,7 +300,7 @@ public class DebuggerModelServiceTest extends AbstractGhidraHeadedDebuggerGUITes
|
|||
mb.createTestProcessesAndThreads();
|
||||
|
||||
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
|
||||
assertEquals(recorder, modelService.getRecorder(mb.testProcess1));
|
||||
}
|
||||
|
@ -311,7 +311,7 @@ public class DebuggerModelServiceTest extends AbstractGhidraHeadedDebuggerGUITes
|
|||
mb.createTestProcessesAndThreads();
|
||||
|
||||
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
|
||||
assertEquals(recorder, modelService.getRecorder(recorder.getTrace()));
|
||||
}
|
||||
|
@ -322,7 +322,7 @@ public class DebuggerModelServiceTest extends AbstractGhidraHeadedDebuggerGUITes
|
|||
mb.createTestProcessesAndThreads();
|
||||
|
||||
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
|
||||
assertEquals(mb.testProcess1, modelService.getTarget(recorder.getTrace()));
|
||||
}
|
||||
|
@ -333,7 +333,7 @@ public class DebuggerModelServiceTest extends AbstractGhidraHeadedDebuggerGUITes
|
|||
mb.createTestProcessesAndThreads();
|
||||
|
||||
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
|
||||
assertEquals(recorder.getTrace(), modelService.getTrace(mb.testProcess1));
|
||||
}
|
||||
|
@ -344,7 +344,7 @@ public class DebuggerModelServiceTest extends AbstractGhidraHeadedDebuggerGUITes
|
|||
mb.createTestProcessesAndThreads();
|
||||
|
||||
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
|
||||
// The most complicated case, lest I want another dimension in a cross product
|
||||
mb.createTestThreadStacksAndFramesHaveRegisterBanks();
|
||||
|
@ -373,7 +373,7 @@ public class DebuggerModelServiceTest extends AbstractGhidraHeadedDebuggerGUITes
|
|||
preRec.run();
|
||||
|
||||
modelService.recordTarget(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
|
||||
postRec.run();
|
||||
|
||||
|
@ -420,7 +420,7 @@ public class DebuggerModelServiceTest extends AbstractGhidraHeadedDebuggerGUITes
|
|||
mb.createTestProcessesAndThreads();
|
||||
|
||||
modelService.recordTarget(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
|
||||
// The most complicated case, lest I want another dimension in a cross product
|
||||
mb.createTestThreadStacksAndFramesHaveRegisterBanks();
|
||||
|
@ -439,9 +439,9 @@ public class DebuggerModelServiceTest extends AbstractGhidraHeadedDebuggerGUITes
|
|||
|
||||
// NOTE: getTargetFocus assumes the target is being recorded
|
||||
modelService.recordTarget(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
modelService.recordTarget(mb.testProcess3,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess3));
|
||||
createTargetTraceMapper(mb.testProcess3));
|
||||
|
||||
assertNull(modelService.getTargetFocus(mb.testProcess1));
|
||||
assertNull(modelService.getTargetFocus(mb.testProcess3));
|
||||
|
|
|
@ -48,7 +48,7 @@ public class DefaultTraceRecorderTest extends AbstractGhidraHeadedDebuggerGUITes
|
|||
mb.createTestProcessesAndThreads();
|
||||
|
||||
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
waitForPass(() -> {
|
||||
assertNotNull(recorder.getTraceThread(mb.testThread1));
|
||||
assertNotNull(recorder.getTraceThread(mb.testThread2));
|
||||
|
@ -61,7 +61,7 @@ public class DefaultTraceRecorderTest extends AbstractGhidraHeadedDebuggerGUITes
|
|||
mb.createTestProcessesAndThreads();
|
||||
|
||||
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
Trace trace = recorder.getTrace();
|
||||
|
||||
TestTargetMemoryRegion targetRegion =
|
||||
|
@ -97,7 +97,7 @@ public class DefaultTraceRecorderTest extends AbstractGhidraHeadedDebuggerGUITes
|
|||
mb.createTestProcessesAndThreads();
|
||||
|
||||
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
Trace trace = recorder.getTrace();
|
||||
Language lang = trace.getBaseLanguage();
|
||||
Register r0 = lang.getRegister("r0");
|
||||
|
@ -131,7 +131,7 @@ public class DefaultTraceRecorderTest extends AbstractGhidraHeadedDebuggerGUITes
|
|||
mb.createTestProcessesAndThreads();
|
||||
|
||||
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
Trace trace = recorder.getTrace();
|
||||
Language lang = trace.getBaseLanguage();
|
||||
Register pc = lang.getRegister("pc");
|
||||
|
@ -180,7 +180,7 @@ public class DefaultTraceRecorderTest extends AbstractGhidraHeadedDebuggerGUITes
|
|||
mb.createTestProcessesAndThreads();
|
||||
|
||||
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
Trace trace = recorder.getTrace();
|
||||
Language lang = trace.getBaseLanguage();
|
||||
Register pc = lang.getRegister("pc");
|
||||
|
@ -229,7 +229,7 @@ public class DefaultTraceRecorderTest extends AbstractGhidraHeadedDebuggerGUITes
|
|||
mb.createTestProcessesAndThreads();
|
||||
|
||||
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
Trace trace = recorder.getTrace();
|
||||
Language lang = trace.getBaseLanguage();
|
||||
Register pc = lang.getRegister("pc");
|
||||
|
|
|
@ -31,7 +31,6 @@ import ghidra.dbg.model.TestTargetStack;
|
|||
import ghidra.dbg.model.TestTargetStackFrameHasRegisterBank;
|
||||
import ghidra.dbg.testutil.DebuggerModelTestUtils;
|
||||
import ghidra.framework.model.DomainFile;
|
||||
import ghidra.trace.database.thread.DBTraceThread;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.stack.TraceStack;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
|
@ -116,7 +115,7 @@ public class DebuggerTraceManagerServiceTest extends AbstractGhidraHeadedDebugge
|
|||
|
||||
assertNull(traceManager.getCurrentThread());
|
||||
|
||||
DBTraceThread thread;
|
||||
TraceThread thread;
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
thread = tb.getOrAddThread("Thread 1", 0);
|
||||
}
|
||||
|
@ -297,7 +296,7 @@ public class DebuggerTraceManagerServiceTest extends AbstractGhidraHeadedDebugge
|
|||
mb.createTestProcessesAndThreads();
|
||||
|
||||
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
Trace trace = recorder.getTrace();
|
||||
|
||||
traceManager.openTrace(trace);
|
||||
|
@ -338,7 +337,7 @@ public class DebuggerTraceManagerServiceTest extends AbstractGhidraHeadedDebugge
|
|||
mb.createTestProcessesAndThreads();
|
||||
|
||||
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
Trace trace = recorder.getTrace();
|
||||
|
||||
waitForValue(() -> modelService.getTarget(trace));
|
||||
|
@ -400,7 +399,7 @@ public class DebuggerTraceManagerServiceTest extends AbstractGhidraHeadedDebugge
|
|||
mb.createTestProcessesAndThreads();
|
||||
|
||||
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
Trace trace = recorder.getTrace();
|
||||
|
||||
traceManager.openTrace(trace);
|
||||
|
|
|
@ -50,7 +50,7 @@ public class TraceRecorderAsyncPcodeExecTest extends AbstractGhidraHeadedDebugge
|
|||
"r1", new byte[] { 6 })));
|
||||
|
||||
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
|
||||
TraceThread thread = waitForValue(() -> recorder.getTraceThread(mb.testThread1));
|
||||
Trace trace = recorder.getTrace();
|
||||
|
@ -93,7 +93,7 @@ public class TraceRecorderAsyncPcodeExecTest extends AbstractGhidraHeadedDebugge
|
|||
"r1", new byte[] { 6 })));
|
||||
|
||||
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
|
||||
new TestDebuggerTargetTraceMapper(mb.testProcess1));
|
||||
createTargetTraceMapper(mb.testProcess1));
|
||||
|
||||
TraceThread thread = waitForValue(() -> recorder.getTraceThread(mb.testThread1));
|
||||
Trace trace = recorder.getTrace();
|
||||
|
|
|
@ -718,6 +718,17 @@ public interface TargetObjectSchema {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the nearest ancestor implementing the given interface along the given path
|
||||
*
|
||||
* <p>
|
||||
* If the given path implements the interface, it is returned, i.e., it is not strictly an
|
||||
* ancestor.
|
||||
*
|
||||
* @param type the interface to search for
|
||||
* @param path the seed path
|
||||
* @return the found path, or {@code null} if no ancestor implements the interface
|
||||
*/
|
||||
default List<String> searchForAncestor(Class<? extends TargetObject> type, List<String> path) {
|
||||
for (; path != null; path = PathUtils.parent(path)) {
|
||||
TargetObjectSchema schema = getSuccessorSchema(path);
|
||||
|
|
|
@ -38,6 +38,23 @@ public class PathMatcher implements PathPredicates {
|
|||
return String.format("<PathMatcher\n %s\n>", StringUtils.join(patterns, "\n "));
|
||||
}
|
||||
|
||||
@Override
|
||||
public PathPredicates or(PathPredicates that) {
|
||||
PathMatcher result = new PathMatcher();
|
||||
result.patterns.addAll(this.patterns);
|
||||
if (that instanceof PathMatcher) {
|
||||
PathMatcher matcher = (PathMatcher) that;
|
||||
result.patterns.addAll(matcher.patterns);
|
||||
}
|
||||
else if (that instanceof PathPattern) {
|
||||
result.patterns.add((PathPattern) that);
|
||||
}
|
||||
else {
|
||||
throw new AssertionError();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: We could probably do a lot better, esp. for many patterns, by using a trie.
|
||||
*/
|
||||
|
@ -81,6 +98,23 @@ public class PathMatcher implements PathPredicates {
|
|||
return patterns.iterator().next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getNextKeys(List<String> path) {
|
||||
Set<String> result = new HashSet<>();
|
||||
for (PathPattern pattern : patterns) {
|
||||
result.addAll(pattern.getNextKeys(path));
|
||||
}
|
||||
if (result.contains("")) {
|
||||
result.removeIf(PathUtils::isName);
|
||||
result.add("");
|
||||
}
|
||||
if (result.contains("[]")) {
|
||||
result.removeIf(PathUtils::isIndex);
|
||||
result.add("[]");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getNextNames(List<String> path) {
|
||||
Set<String> result = new HashSet<>();
|
||||
|
@ -111,10 +145,10 @@ public class PathMatcher implements PathPredicates {
|
|||
}
|
||||
|
||||
@Override
|
||||
public PathMatcher applyIndices(List<String> indices) {
|
||||
public PathMatcher applyKeys(List<String> indices) {
|
||||
PathMatcher result = new PathMatcher();
|
||||
for (PathPattern pat : patterns) {
|
||||
result.addPattern(pat.applyIndices(indices));
|
||||
result.addPattern(pat.applyKeys(indices));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -62,26 +62,33 @@ public class PathPattern implements PathPredicates {
|
|||
return pattern.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PathPredicates or(PathPredicates that) {
|
||||
if (this.equals(that)) {
|
||||
return this;
|
||||
}
|
||||
PathMatcher result = new PathMatcher();
|
||||
result.addPattern(this);
|
||||
if (that instanceof PathPattern) {
|
||||
result.addPattern(this);
|
||||
}
|
||||
else if (that instanceof PathMatcher) {
|
||||
PathMatcher matcher = (PathMatcher) that;
|
||||
result.patterns.addAll(matcher.patterns);
|
||||
}
|
||||
else {
|
||||
throw new AssertionError();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static boolean isWildcard(String pat) {
|
||||
return "[]".equals(pat) || "".equals(pat);
|
||||
}
|
||||
|
||||
public static boolean keyMatches(String pat, String key) {
|
||||
if (key.equals(pat)) {
|
||||
return true;
|
||||
}
|
||||
if ("[]".equals(pat) && PathUtils.isIndex(key)) {
|
||||
return true;
|
||||
}
|
||||
if ("".equals(pat) && PathUtils.isName(key)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean matchesUpTo(List<String> path, int length) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (!keyMatches(pattern.get(i), path.get(i))) {
|
||||
if (!PathPredicates.keyMatches(pattern.get(i), path.get(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -144,11 +151,25 @@ public class PathPattern implements PathPredicates {
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getNextKeys(List<String> path) {
|
||||
if (path.size() >= pattern.size()) {
|
||||
return Set.of();
|
||||
}
|
||||
if (!matchesUpTo(path, path.size())) {
|
||||
return Set.of();
|
||||
}
|
||||
return Set.of(pattern.get(path.size()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getNextNames(List<String> path) {
|
||||
if (path.size() >= pattern.size()) {
|
||||
return Set.of();
|
||||
}
|
||||
if (!matchesUpTo(path, path.size())) {
|
||||
return Set.of();
|
||||
}
|
||||
String pat = pattern.get(path.size());
|
||||
if (PathUtils.isName(pat)) {
|
||||
return Set.of(pat);
|
||||
|
@ -161,6 +182,9 @@ public class PathPattern implements PathPredicates {
|
|||
if (path.size() >= pattern.size()) {
|
||||
return Set.of();
|
||||
}
|
||||
if (!matchesUpTo(path, path.size())) {
|
||||
return Set.of();
|
||||
}
|
||||
String pat = pattern.get(path.size());
|
||||
if (PathUtils.isIndex(pat)) {
|
||||
return Set.of(PathUtils.parseIndex(pat));
|
||||
|
@ -174,7 +198,7 @@ public class PathPattern implements PathPredicates {
|
|||
}
|
||||
|
||||
@Override
|
||||
public PathPattern applyIndices(List<String> indices) {
|
||||
public PathPattern applyKeys(List<String> indices) {
|
||||
List<String> result = new ArrayList<>(pattern.size());
|
||||
Iterator<String> it = indices.iterator();
|
||||
for (String pat : pattern) {
|
||||
|
@ -196,18 +220,18 @@ public class PathPattern implements PathPredicates {
|
|||
}
|
||||
|
||||
/**
|
||||
* If the given path matches, extract indices where matched by wildcards
|
||||
* If the given path matches, extract keys where matched by wildcards
|
||||
*
|
||||
* <p>
|
||||
* This is essentially the inverse of {@link #applyIndices(List)}, but can only be asked of one
|
||||
* This is essentially the inverse of {@link #applyKeys(List)}, but can only be asked of one
|
||||
* pattern. The keys are returned from left to right, in the order matched by the pattern. Only
|
||||
* those keys matched by a wildcard are included in the result. Indices are extracted with the
|
||||
* brackets {@code []} removed.
|
||||
*
|
||||
* @param path the path to match
|
||||
* @return the list of matched indices or {@code null} if not matched
|
||||
* @return the list of matched keys or {@code null} if not matched
|
||||
*/
|
||||
public List<String> matchIndices(List<String> path) {
|
||||
public List<String> matchKeys(List<String> path) {
|
||||
int length = pattern.size();
|
||||
if (length != path.size()) {
|
||||
return null;
|
||||
|
@ -216,7 +240,7 @@ public class PathPattern implements PathPredicates {
|
|||
for (int i = 0; i < length; i++) {
|
||||
String pat = pattern.get(i);
|
||||
String key = path.get(i);
|
||||
if (!keyMatches(pat, key)) {
|
||||
if (!PathPredicates.keyMatches(pat, key)) {
|
||||
return null;
|
||||
}
|
||||
if (isWildcard(pat)) {
|
||||
|
|
|
@ -23,6 +23,38 @@ import ghidra.dbg.target.TargetObject;
|
|||
import ghidra.dbg.util.PathUtils.PathComparator;
|
||||
|
||||
public interface PathPredicates {
|
||||
|
||||
static boolean keyMatches(String pat, String key) {
|
||||
if (key.equals(pat)) {
|
||||
return true;
|
||||
}
|
||||
if ("[]".equals(pat)) {
|
||||
return PathUtils.isIndex(key);
|
||||
}
|
||||
if ("".equals(pat)) {
|
||||
return PathUtils.isName(key);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static boolean anyMatches(Set<String> pats, String key) {
|
||||
return pats.stream().anyMatch(p -> keyMatches(p, key));
|
||||
}
|
||||
|
||||
static PathPredicates pattern(String... keyPatterns) {
|
||||
return new PathPattern(List.of(keyPatterns));
|
||||
}
|
||||
|
||||
static PathPredicates pattern(List<String> keyPatterns) {
|
||||
return new PathPattern(keyPatterns);
|
||||
}
|
||||
|
||||
static PathPredicates parse(String pattern) {
|
||||
return new PathPattern(PathUtils.parse(pattern));
|
||||
}
|
||||
|
||||
PathPredicates or(PathPredicates that);
|
||||
|
||||
/**
|
||||
* Check if the entire path passes
|
||||
*
|
||||
|
@ -59,10 +91,22 @@ public interface PathPredicates {
|
|||
boolean ancestorMatches(List<String> path, boolean strict);
|
||||
|
||||
/**
|
||||
* Assuming a successor of path could match, get the patterns for the next possible key
|
||||
* Get the patterns for the next possible key
|
||||
*
|
||||
* <p>
|
||||
* If the pattern could accept a name next, get all patterns describing those names
|
||||
* If a successor of the given path cannot match this pattern, the empty set is returned.
|
||||
*
|
||||
* @param path the ancestor path
|
||||
* @return a set of patterns where indices are enclosed in brackets ({@code [])
|
||||
*/
|
||||
Set<String> getNextKeys(List<String> path);
|
||||
|
||||
/**
|
||||
* Get the patterns for the next possible name
|
||||
*
|
||||
* <p>
|
||||
* If a successor of the given path cannot match this pattern, the empty set is returned. If the
|
||||
* pattern could accept a name next, get all patterns describing those names
|
||||
*
|
||||
* @param path the ancestor path
|
||||
* @return a set of patterns
|
||||
|
@ -73,10 +117,11 @@ public interface PathPredicates {
|
|||
* Assuming a successor of path could match, get the patterns for the next possible index
|
||||
*
|
||||
* <p>
|
||||
* If the pattern could accept an index next, get all patterns describing those indices
|
||||
* If a successor of the given path cannot match this pattern, the empty set is returned. If the
|
||||
* pattern could accept an index next, get all patterns describing those indices
|
||||
*
|
||||
* @param path the ancestor path
|
||||
* @return a set of patterns, without brack@Override ets ({@code [])
|
||||
* @return a set of patterns, without brackets ({@code [])
|
||||
*/
|
||||
Set<String> getNextIndices(List<String> path);
|
||||
|
||||
|
@ -94,18 +139,6 @@ public interface PathPredicates {
|
|||
*/
|
||||
PathPattern getSingletonPattern();
|
||||
|
||||
static boolean anyMatches(Set<String> pats, String key) {
|
||||
for (String pat : pats) {
|
||||
if ("".equals(pat)) {
|
||||
return true;
|
||||
}
|
||||
if (key.equals(pat)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
default NavigableMap<List<String>, ?> getCachedValues(TargetObject seed) {
|
||||
return getCachedValues(List.of(), seed);
|
||||
}
|
||||
|
@ -259,10 +292,10 @@ public interface PathPredicates {
|
|||
* @param indices the indices to substitute
|
||||
* @return the pattern or matcher with the applied substitutions
|
||||
*/
|
||||
PathPredicates applyIndices(List<String> indices);
|
||||
PathPredicates applyKeys(List<String> indices);
|
||||
|
||||
default PathPredicates applyIndices(String... indices) {
|
||||
return applyIndices(List.of(indices));
|
||||
return applyKeys(List.of(indices));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -25,6 +25,7 @@ dependencies {
|
|||
api project(':Generic')
|
||||
api project(':SoftwareModeling')
|
||||
api project(':ProposedUtils')
|
||||
api project(':Framework-Debugging')
|
||||
annotationProcessor project(':AnnotationValidator')
|
||||
|
||||
testImplementation project(':Base')
|
||||
|
|
|
@ -42,7 +42,6 @@ import ghidra.trace.database.language.DBTraceLanguageManager;
|
|||
import ghidra.trace.database.listing.DBTraceCodeManager;
|
||||
import ghidra.trace.database.listing.DBTraceCommentAdapter;
|
||||
import ghidra.trace.database.memory.DBTraceMemoryManager;
|
||||
import ghidra.trace.database.memory.DBTraceMemoryRegion;
|
||||
import ghidra.trace.database.module.DBTraceModuleManager;
|
||||
import ghidra.trace.database.module.DBTraceStaticMappingManager;
|
||||
import ghidra.trace.database.program.DBTraceProgramView;
|
||||
|
@ -50,9 +49,11 @@ import ghidra.trace.database.program.DBTraceVariableSnapProgramView;
|
|||
import ghidra.trace.database.property.DBTraceAddressPropertyManager;
|
||||
import ghidra.trace.database.stack.DBTraceStackManager;
|
||||
import ghidra.trace.database.symbol.*;
|
||||
import ghidra.trace.database.target.DBTraceObjectManager;
|
||||
import ghidra.trace.database.thread.DBTraceThreadManager;
|
||||
import ghidra.trace.database.time.DBTraceTimeManager;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.memory.TraceMemoryRegion;
|
||||
import ghidra.trace.util.TraceChangeManager;
|
||||
import ghidra.trace.util.TraceChangeRecord;
|
||||
import ghidra.util.*;
|
||||
|
@ -104,6 +105,8 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
|||
@DependentService
|
||||
protected DBTraceModuleManager moduleManager;
|
||||
@DependentService
|
||||
protected DBTraceObjectManager objectManager;
|
||||
@DependentService
|
||||
protected DBTraceOverlaySpaceAdapter overlaySpaceAdapter;
|
||||
@DependentService
|
||||
protected DBTraceReferenceManager referenceManager;
|
||||
|
@ -340,6 +343,14 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
|||
baseLanguage, this));
|
||||
}
|
||||
|
||||
@DependentService
|
||||
protected DBTraceObjectManager createObjectManager()
|
||||
throws CancelledException, IOException {
|
||||
return createTraceManager("Object Manager",
|
||||
(openMode, monitor) -> new DBTraceObjectManager(dbh, openMode, rwLock, monitor,
|
||||
baseLanguage, this));
|
||||
}
|
||||
|
||||
@DependentService
|
||||
protected DBTraceOverlaySpaceAdapter createOverlaySpaceAdapter()
|
||||
throws CancelledException, IOException {
|
||||
|
@ -391,9 +402,11 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
|||
}
|
||||
|
||||
@DependentService
|
||||
protected DBTraceThreadManager createThreadManager() throws IOException, CancelledException {
|
||||
protected DBTraceThreadManager createThreadManager(DBTraceObjectManager objectManager)
|
||||
throws IOException, CancelledException {
|
||||
return createTraceManager("Thread Manager",
|
||||
(openMode, monitor) -> new DBTraceThreadManager(dbh, openMode, rwLock, monitor, this));
|
||||
(openMode, monitor) -> new DBTraceThreadManager(dbh, openMode, rwLock, monitor, this,
|
||||
objectManager));
|
||||
}
|
||||
|
||||
@DependentService
|
||||
|
@ -494,6 +507,11 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
|||
return moduleManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DBTraceObjectManager getObjectManager() {
|
||||
return objectManager;
|
||||
}
|
||||
|
||||
@Internal
|
||||
public DBTraceOverlaySpaceAdapter getOverlaySpaceAdapter() {
|
||||
return overlaySpaceAdapter;
|
||||
|
@ -716,29 +734,29 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
|||
}
|
||||
}
|
||||
|
||||
public void updateViewsAddRegionBlock(DBTraceMemoryRegion region) {
|
||||
public void updateViewsAddRegionBlock(TraceMemoryRegion region) {
|
||||
allViews(v -> v.updateMemoryAddRegionBlock(region));
|
||||
}
|
||||
|
||||
public void updateViewsChangeRegionBlockName(DBTraceMemoryRegion region) {
|
||||
public void updateViewsChangeRegionBlockName(TraceMemoryRegion region) {
|
||||
allViews(v -> v.updateMemoryChangeRegionBlockName(region));
|
||||
}
|
||||
|
||||
public void updateViewsChangeRegionBlockFlags(DBTraceMemoryRegion region) {
|
||||
allViews(v -> v.updateMemoryChangeRegionBlockFlags(region));
|
||||
public void updateViewsChangeRegionBlockFlags(TraceMemoryRegion region, Range<Long> lifespan) {
|
||||
allViews(v -> v.updateMemoryChangeRegionBlockFlags(region, lifespan));
|
||||
}
|
||||
|
||||
public void updateViewsChangeRegionBlockRange(DBTraceMemoryRegion region,
|
||||
public void updateViewsChangeRegionBlockRange(TraceMemoryRegion region,
|
||||
AddressRange oldRange, AddressRange newRange) {
|
||||
allViews(v -> v.updateMemoryChangeRegionBlockRange(region, oldRange, newRange));
|
||||
}
|
||||
|
||||
public void updateViewsChangeRegionBlockLifespan(DBTraceMemoryRegion region,
|
||||
public void updateViewsChangeRegionBlockLifespan(TraceMemoryRegion region,
|
||||
Range<Long> oldLifespan, Range<Long> newLifespan) {
|
||||
allViews(v -> v.updateMemoryChangeRegionBlockLifespan(region, oldLifespan, newLifespan));
|
||||
}
|
||||
|
||||
public void updateViewsDeleteRegionBlock(DBTraceMemoryRegion region) {
|
||||
public void updateViewsDeleteRegionBlock(TraceMemoryRegion region) {
|
||||
allViews(v -> v.updateMemoryDeleteRegionBlock(region));
|
||||
}
|
||||
|
||||
|
|
|
@ -19,13 +19,13 @@ import java.lang.reflect.Field;
|
|||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Iterator;
|
||||
import java.util.Objects;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.google.common.collect.BoundType;
|
||||
import com.google.common.collect.Range;
|
||||
import com.google.common.collect.*;
|
||||
|
||||
import db.*;
|
||||
import ghidra.program.model.address.*;
|
||||
|
@ -267,6 +267,155 @@ public enum DBTraceUtils {
|
|||
}
|
||||
}
|
||||
|
||||
public static abstract class RangeMapSetter<E, D extends Comparable<D>, R, V> {
|
||||
protected abstract R getRange(E entry);
|
||||
|
||||
protected abstract V getValue(E entry);
|
||||
|
||||
protected abstract void remove(E entry);
|
||||
|
||||
protected abstract D getLower(R range);
|
||||
|
||||
protected abstract D getUpper(R range);
|
||||
|
||||
protected abstract R toRange(D lower, D upper);
|
||||
|
||||
protected abstract D getPrevious(D d);
|
||||
|
||||
protected abstract D getNext(D d);
|
||||
|
||||
protected abstract Iterable<E> getIntersecting(D lower, D upper);
|
||||
|
||||
protected abstract E put(R range, V value);
|
||||
|
||||
protected D getPreviousOrSame(D d) {
|
||||
D prev = getPrevious(d);
|
||||
if (prev == null) {
|
||||
return d;
|
||||
}
|
||||
return prev;
|
||||
}
|
||||
|
||||
protected D getNextOrSame(D d) {
|
||||
D next = getNext(d);
|
||||
if (next == null) {
|
||||
return d;
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
protected boolean connects(R r1, R r2) {
|
||||
return getPreviousOrSame(getLower(r1)).compareTo(getUpper(r2)) <= 0 ||
|
||||
getPreviousOrSame(getLower(r2)).compareTo(getUpper(r1)) <= 0;
|
||||
}
|
||||
|
||||
public E set(R range, V value) {
|
||||
return set(getLower(range), getUpper(range), value);
|
||||
}
|
||||
|
||||
public E set(D lower, D upper, V value) {
|
||||
// Go one out to find abutting ranges, too.
|
||||
D prev = getPreviousOrSame(lower);
|
||||
D next = getNextOrSame(upper);
|
||||
Map<R, V> toPut = new HashMap<>();
|
||||
for (E entry : getIntersecting(prev, next)) {
|
||||
R r = getRange(entry);
|
||||
boolean precedesMin = getLower(r).compareTo(lower) < 0;
|
||||
boolean succeedsMax = getUpper(r).compareTo(upper) > 0;
|
||||
boolean sameVal = Objects.equals(getValue(entry), value);
|
||||
if (precedesMin && succeedsMax && sameVal) {
|
||||
return entry; // The value in this range is already set as specified
|
||||
}
|
||||
remove(entry);
|
||||
if (precedesMin) {
|
||||
if (sameVal) {
|
||||
lower = getLower(r);
|
||||
}
|
||||
else {
|
||||
toPut.put(toRange(getLower(r), prev), getValue(entry));
|
||||
}
|
||||
}
|
||||
if (succeedsMax) {
|
||||
if (sameVal) {
|
||||
upper = getUpper(r);
|
||||
}
|
||||
else {
|
||||
toPut.put(toRange(next, getUpper(r)), getValue(entry));
|
||||
}
|
||||
}
|
||||
}
|
||||
E result = put(toRange(lower, upper), value);
|
||||
assert toPut.size() <= 2;
|
||||
for (Entry<R, V> ent : toPut.entrySet()) {
|
||||
put(ent.getKey(), ent.getValue());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public static abstract class AddressRangeMapSetter<E, V>
|
||||
extends RangeMapSetter<E, Address, AddressRange, V> {
|
||||
@Override
|
||||
protected Address getLower(AddressRange range) {
|
||||
return range.getMinAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Address getUpper(AddressRange range) {
|
||||
return range.getMaxAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AddressRange toRange(Address lower, Address upper) {
|
||||
return new AddressRangeImpl(lower, upper);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Address getPrevious(Address d) {
|
||||
return d.previous();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Address getNext(Address d) {
|
||||
return d.next();
|
||||
}
|
||||
}
|
||||
|
||||
public static abstract class LifespanMapSetter<E, V>
|
||||
extends RangeMapSetter<E, Long, Range<Long>, V> {
|
||||
|
||||
@Override
|
||||
protected Long getLower(Range<Long> range) {
|
||||
return lowerEndpoint(range);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Long getUpper(Range<Long> range) {
|
||||
return upperEndpoint(range);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Range<Long> toRange(Long lower, Long upper) {
|
||||
return DBTraceUtils.toRange(lower, upper);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Long getPrevious(Long d) {
|
||||
if (d == null || d == Long.MIN_VALUE) {
|
||||
return null;
|
||||
}
|
||||
return d - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Long getNext(Long d) {
|
||||
if (d == null || d == Long.MAX_VALUE) {
|
||||
return null;
|
||||
}
|
||||
return d + 1;
|
||||
}
|
||||
}
|
||||
|
||||
public static long lowerEndpoint(Range<Long> range) {
|
||||
if (!range.hasLowerBound()) {
|
||||
return Long.MIN_VALUE;
|
||||
|
@ -386,6 +535,16 @@ public enum DBTraceUtils {
|
|||
lifespanSetter.accept(data, toRange(data.getY1(), lowerEndpoint(span) - 1));
|
||||
}
|
||||
|
||||
public static List<Range<Long>> subtract(Range<Long> a, Range<Long> b) {
|
||||
RangeSet<Long> set = TreeRangeSet.create();
|
||||
set.add(a);
|
||||
set.remove(b);
|
||||
return set.asRanges()
|
||||
.stream()
|
||||
.map(r -> toRange(lowerEndpoint(r), upperEndpoint(r)))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> Iterator<T> covariantIterator(Iterator<? extends T> it) {
|
||||
// Iterators only support read and remove, not insert. Safe to cast.
|
||||
|
|
|
@ -63,11 +63,7 @@ public class DBTraceOverlaySpaceAdapter implements DBTraceManager {
|
|||
extends AbstractDBFieldCodec<Address, OT, BinaryField> {
|
||||
static final Charset UTF8 = Charset.forName("UTF-8");
|
||||
|
||||
public AddressDBFieldCodec(Class<OT> objectType, Field field, int column) {
|
||||
super(Address.class, objectType, BinaryField.class, field, column);
|
||||
}
|
||||
|
||||
protected byte[] encode(Address address) {
|
||||
public static byte[] encode(Address address) {
|
||||
if (address == null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -86,6 +82,31 @@ public class DBTraceOverlaySpaceAdapter implements DBTraceManager {
|
|||
return buf.array();
|
||||
}
|
||||
|
||||
public static Address decode(byte[] enc, DBTraceOverlaySpaceAdapter osa) {
|
||||
if (enc == null) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
ByteBuffer buf = ByteBuffer.wrap(enc);
|
||||
byte overlay = buf.get();
|
||||
final AddressSpace as;
|
||||
if (overlay == 1) {
|
||||
short key = buf.getShort();
|
||||
as = osa.spacesByKey.get(key & 0xffffL);
|
||||
}
|
||||
else {
|
||||
short id = buf.getShort();
|
||||
as = osa.trace.getInternalAddressFactory().getAddressSpace(id);
|
||||
}
|
||||
long offset = buf.getLong();
|
||||
return as.getAddress(offset);
|
||||
}
|
||||
}
|
||||
|
||||
public AddressDBFieldCodec(Class<OT> objectType, Field field, int column) {
|
||||
super(Address.class, objectType, BinaryField.class, field, column);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void store(Address value, BinaryField f) {
|
||||
f.setBinaryData(encode(value));
|
||||
|
@ -101,25 +122,7 @@ public class DBTraceOverlaySpaceAdapter implements DBTraceManager {
|
|||
protected void doLoad(OT obj, DBRecord record)
|
||||
throws IllegalArgumentException, IllegalAccessException {
|
||||
byte[] data = record.getBinaryData(column);
|
||||
if (data == null) {
|
||||
setValue(obj, null);
|
||||
}
|
||||
else {
|
||||
ByteBuffer buf = ByteBuffer.wrap(data);
|
||||
byte overlay = buf.get();
|
||||
final AddressSpace as;
|
||||
if (overlay == 1) {
|
||||
short key = buf.getShort();
|
||||
as = obj.getOverlaySpaceAdapter().spacesByKey.get(key & 0xffffL);
|
||||
}
|
||||
else {
|
||||
short id = buf.getShort();
|
||||
as = obj.getOverlaySpaceAdapter().trace.getInternalAddressFactory()
|
||||
.getAddressSpace(id);
|
||||
}
|
||||
long offset = buf.getLong();
|
||||
setValue(obj, as.getAddress(offset));
|
||||
}
|
||||
setValue(obj, decode(data, obj.getOverlaySpaceAdapter()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,10 +25,10 @@ import ghidra.trace.database.DBTrace;
|
|||
import ghidra.trace.database.DBTraceUtils;
|
||||
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree;
|
||||
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.AbstractDBTraceAddressSnapRangePropertyMapData;
|
||||
import ghidra.trace.database.thread.DBTraceThread;
|
||||
import ghidra.trace.model.Trace.TraceBookmarkChangeType;
|
||||
import ghidra.trace.model.bookmark.TraceBookmark;
|
||||
import ghidra.trace.model.bookmark.TraceBookmarkType;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.trace.util.TraceChangeRecord;
|
||||
import ghidra.util.LockHold;
|
||||
import ghidra.util.database.DBCachedObjectStore;
|
||||
|
@ -99,7 +99,7 @@ public class DBTraceBookmark extends AbstractDBTraceAddressSnapRangePropertyMapD
|
|||
}
|
||||
|
||||
@Override
|
||||
public DBTraceThread getThread() {
|
||||
public TraceThread getThread() {
|
||||
return space.getThread();
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,6 @@ import ghidra.program.model.lang.Language;
|
|||
import ghidra.trace.database.DBTrace;
|
||||
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery;
|
||||
import ghidra.trace.database.space.*;
|
||||
import ghidra.trace.database.thread.DBTraceThread;
|
||||
import ghidra.trace.database.thread.DBTraceThreadManager;
|
||||
import ghidra.trace.model.Trace.TraceBookmarkChangeType;
|
||||
import ghidra.trace.model.bookmark.TraceBookmarkManager;
|
||||
|
@ -160,7 +159,7 @@ public class DBTraceBookmarkManager
|
|||
protected static DBTraceSpaceKey unpackRegSpaceKey(AddressSpace space,
|
||||
DBTraceThreadManager threadManager, long id) {
|
||||
long threadKey = unpackRegThread(id);
|
||||
DBTraceThread thread = threadManager.getThread(threadKey);
|
||||
TraceThread thread = threadManager.getThread(threadKey);
|
||||
assert thread != null;
|
||||
int frameLevel = unpackRegFrame(id);
|
||||
return DBTraceSpaceKey.create(space, thread, frameLevel);
|
||||
|
@ -186,7 +185,7 @@ public class DBTraceBookmarkManager
|
|||
|
||||
@Override
|
||||
protected DBTraceBookmarkRegisterSpace createRegisterSpace(AddressSpace space,
|
||||
DBTraceThread thread, DBTraceSpaceEntry ent) throws VersionException, IOException {
|
||||
TraceThread thread, DBTraceSpaceEntry ent) throws VersionException, IOException {
|
||||
return new DBTraceBookmarkRegisterSpace(this, space, thread, ent.getFrameLevel());
|
||||
}
|
||||
|
||||
|
|
|
@ -18,24 +18,24 @@ package ghidra.trace.database.bookmark;
|
|||
import java.io.IOException;
|
||||
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.trace.database.thread.DBTraceThread;
|
||||
import ghidra.trace.model.bookmark.TraceBookmarkRegisterSpace;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.util.exception.VersionException;
|
||||
|
||||
public class DBTraceBookmarkRegisterSpace extends DBTraceBookmarkSpace
|
||||
implements TraceBookmarkRegisterSpace {
|
||||
private final DBTraceThread thread;
|
||||
private final TraceThread thread;
|
||||
private final int frameLevel;
|
||||
|
||||
public DBTraceBookmarkRegisterSpace(DBTraceBookmarkManager manager, AddressSpace space,
|
||||
DBTraceThread thread, int frameLevel) throws VersionException, IOException {
|
||||
TraceThread thread, int frameLevel) throws VersionException, IOException {
|
||||
super(manager, space);
|
||||
this.thread = thread;
|
||||
this.frameLevel = frameLevel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DBTraceThread getThread() {
|
||||
public TraceThread getThread() {
|
||||
return thread;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,10 +26,10 @@ import ghidra.trace.database.DBTrace;
|
|||
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapSpace;
|
||||
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery;
|
||||
import ghidra.trace.database.space.DBTraceSpaceBased;
|
||||
import ghidra.trace.database.thread.DBTraceThread;
|
||||
import ghidra.trace.model.Trace.TraceBookmarkChangeType;
|
||||
import ghidra.trace.model.bookmark.TraceBookmarkSpace;
|
||||
import ghidra.trace.model.bookmark.TraceBookmarkType;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.trace.util.TraceChangeRecord;
|
||||
import ghidra.util.LockHold;
|
||||
import ghidra.util.database.DBCachedObjectIndex;
|
||||
|
@ -65,7 +65,7 @@ public class DBTraceBookmarkSpace implements TraceBookmarkSpace, DBTraceSpaceBas
|
|||
}
|
||||
|
||||
@Override
|
||||
public DBTraceThread getThread() {
|
||||
public TraceThread getThread() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@ import ghidra.trace.database.DBTrace;
|
|||
import ghidra.trace.database.DBTraceUtils;
|
||||
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree;
|
||||
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.AbstractDBTraceAddressSnapRangePropertyMapData;
|
||||
import ghidra.trace.database.thread.DBTraceThread;
|
||||
import ghidra.trace.database.thread.DBTraceThreadManager;
|
||||
import ghidra.trace.model.Trace.TraceBreakpointChangeType;
|
||||
import ghidra.trace.model.breakpoint.TraceBreakpoint;
|
||||
|
@ -128,7 +127,7 @@ public class DBTraceBreakpoint
|
|||
return this;
|
||||
}
|
||||
|
||||
public void set(String path, String name, Collection<DBTraceThread> threads,
|
||||
public void set(String path, String name, Collection<TraceThread> threads,
|
||||
Collection<TraceBreakpointKind> kinds, boolean enabled, String comment) {
|
||||
// TODO: Check that the threads exist and that each's lifespan covers the breakpoint's
|
||||
// TODO: This would require additional validation any time those are updated
|
||||
|
@ -140,7 +139,7 @@ public class DBTraceBreakpoint
|
|||
}
|
||||
this.threadKeys = new long[threads.size()];
|
||||
int i = 0;
|
||||
for (DBTraceThread t : threads) {
|
||||
for (TraceThread t : threads) {
|
||||
this.threadKeys[i++] = t.getKey();
|
||||
}
|
||||
this.flagsByte = 0;
|
||||
|
@ -386,7 +385,8 @@ public class DBTraceBreakpoint
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
public boolean isEnabled(long snap) {
|
||||
// NB. Only object mode support per-snap enablement
|
||||
try (LockHold hold = LockHold.lock(space.lock.readLock())) {
|
||||
return enabled;
|
||||
}
|
||||
|
|
|
@ -30,7 +30,6 @@ import ghidra.trace.database.DBTrace;
|
|||
import ghidra.trace.database.DBTraceUtils;
|
||||
import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager;
|
||||
import ghidra.trace.database.space.DBTraceDelegatingManager;
|
||||
import ghidra.trace.database.thread.DBTraceThread;
|
||||
import ghidra.trace.database.thread.DBTraceThreadManager;
|
||||
import ghidra.trace.model.breakpoint.*;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
|
@ -60,7 +59,7 @@ public class DBTraceBreakpointManager
|
|||
}
|
||||
|
||||
@Override
|
||||
protected DBTraceBreakpointSpace createRegisterSpace(AddressSpace space, DBTraceThread thread,
|
||||
protected DBTraceBreakpointSpace createRegisterSpace(AddressSpace space, TraceThread thread,
|
||||
DBTraceSpaceEntry ent) throws VersionException, IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
@ -80,9 +79,9 @@ public class DBTraceBreakpointManager
|
|||
return lock.writeLock();
|
||||
}
|
||||
|
||||
protected void checkDuplicatePath(DBTraceBreakpoint ignore, String path, Range<Long> lifespan)
|
||||
protected void checkDuplicatePath(TraceBreakpoint ignore, String path, Range<Long> lifespan)
|
||||
throws DuplicateNameException {
|
||||
for (DBTraceBreakpoint pc : getBreakpointsByPath(path)) {
|
||||
for (TraceBreakpoint pc : getBreakpointsByPath(path)) {
|
||||
if (pc == ignore) {
|
||||
continue;
|
||||
}
|
||||
|
@ -98,23 +97,38 @@ public class DBTraceBreakpointManager
|
|||
public TraceBreakpoint addBreakpoint(String path, Range<Long> lifespan, AddressRange range,
|
||||
Collection<TraceThread> threads, Collection<TraceBreakpointKind> kinds, boolean enabled,
|
||||
String comment) throws DuplicateNameException {
|
||||
if (trace.getObjectManager().hasSchema()) {
|
||||
return trace.getObjectManager()
|
||||
.addBreakpoint(path, lifespan, range, threads, kinds, enabled, comment);
|
||||
}
|
||||
checkDuplicatePath(null, path, lifespan);
|
||||
return delegateWrite(range.getAddressSpace(),
|
||||
m -> m.addBreakpoint(path, lifespan, range, threads, kinds, enabled, comment));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends DBTraceBreakpoint> getAllBreakpoints() {
|
||||
public Collection<? extends TraceBreakpoint> getAllBreakpoints() {
|
||||
if (trace.getObjectManager().hasSchema()) {
|
||||
return trace.getObjectManager().getAllObjects(TraceObjectBreakpointLocation.class);
|
||||
}
|
||||
return delegateCollection(getActiveMemorySpaces(), m -> m.getAllBreakpoints());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends DBTraceBreakpoint> getBreakpointsByPath(String path) {
|
||||
public Collection<? extends TraceBreakpoint> getBreakpointsByPath(String path) {
|
||||
if (trace.getObjectManager().hasSchema()) {
|
||||
return trace.getObjectManager()
|
||||
.getObjectsByPath(path, TraceObjectBreakpointLocation.class);
|
||||
}
|
||||
return delegateCollection(getActiveMemorySpaces(), m -> m.getBreakpointsByPath(path));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceBreakpoint getPlacedBreakpointByPath(long snap, String path) {
|
||||
if (trace.getObjectManager().hasSchema()) {
|
||||
return trace.getObjectManager()
|
||||
.getObjectByPath(snap, path, TraceObjectBreakpointLocation.class);
|
||||
}
|
||||
try (LockHold hold = LockHold.lock(lock.readLock())) {
|
||||
return getBreakpointsByPath(path)
|
||||
.stream()
|
||||
|
@ -125,14 +139,24 @@ public class DBTraceBreakpointManager
|
|||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends DBTraceBreakpoint> getBreakpointsAt(long snap, Address address) {
|
||||
public Collection<? extends TraceBreakpoint> getBreakpointsAt(long snap, Address address) {
|
||||
if (trace.getObjectManager().hasSchema()) {
|
||||
return trace.getObjectManager()
|
||||
.getObjectsContaining(snap, address, TraceObjectBreakpointLocation.KEY_RANGE,
|
||||
TraceObjectBreakpointLocation.class);
|
||||
}
|
||||
return delegateRead(address.getAddressSpace(), m -> m.getBreakpointsAt(snap, address),
|
||||
Collections.emptyList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends DBTraceBreakpoint> getBreakpointsIntersecting(Range<Long> span,
|
||||
public Collection<? extends TraceBreakpoint> getBreakpointsIntersecting(Range<Long> span,
|
||||
AddressRange range) {
|
||||
if (trace.getObjectManager().hasSchema()) {
|
||||
return trace.getObjectManager()
|
||||
.getObjectsIntersecting(span, range, TraceObjectBreakpointLocation.KEY_RANGE,
|
||||
TraceObjectBreakpointLocation.class);
|
||||
}
|
||||
return delegateRead(range.getAddressSpace(), m -> m.getBreakpointsIntersecting(span, range),
|
||||
Collections.emptyList());
|
||||
}
|
||||
|
|
|
@ -99,11 +99,9 @@ public class DBTraceBreakpointSpace implements DBTraceSpaceBased {
|
|||
for (TraceThread t : threads) {
|
||||
threadManager.assertIsMine(t);
|
||||
}
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" }) // checked by above assertIsMine
|
||||
Collection<DBTraceThread> dbThreads = (Collection) threads;
|
||||
DBTraceBreakpoint breakpoint =
|
||||
breakpointMapSpace.put(new ImmutableTraceAddressSnapRange(range, lifespan), null);
|
||||
breakpoint.set(path, path, dbThreads, kinds, enabled, comment);
|
||||
breakpoint.set(path, path, threads, kinds, enabled, comment);
|
||||
trace.setChanged(
|
||||
new TraceChangeRecord<>(TraceBreakpointChangeType.ADDED, this, breakpoint));
|
||||
return breakpoint;
|
||||
|
|
|
@ -0,0 +1,285 @@
|
|||
/* ###
|
||||
* 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.trace.database.breakpoint;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.google.common.collect.Range;
|
||||
|
||||
import ghidra.dbg.target.*;
|
||||
import ghidra.dbg.target.schema.TargetObjectSchema;
|
||||
import ghidra.dbg.util.PathMatcher;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressRange;
|
||||
import ghidra.trace.database.DBTraceUtils;
|
||||
import ghidra.trace.database.target.*;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.Trace.TraceBreakpointChangeType;
|
||||
import ghidra.trace.model.breakpoint.*;
|
||||
import ghidra.trace.model.target.TraceObject;
|
||||
import ghidra.trace.model.target.annot.TraceObjectInterfaceUtils;
|
||||
import ghidra.trace.model.thread.TraceObjectThread;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.trace.util.*;
|
||||
import ghidra.util.LockHold;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
public class DBTraceObjectBreakpointLocation
|
||||
implements TraceObjectBreakpointLocation, DBTraceObjectInterface {
|
||||
|
||||
protected class BreakpointChangeTranslator extends Translator<TraceBreakpoint> {
|
||||
protected BreakpointChangeTranslator(DBTraceObject object, TraceBreakpoint iface) {
|
||||
super(KEY_RANGE, object, iface);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TraceChangeType<TraceBreakpoint, Void> getAddedType() {
|
||||
return TraceBreakpointChangeType.ADDED;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TraceChangeType<TraceBreakpoint, Range<Long>> getLifespanChangedType() {
|
||||
return TraceBreakpointChangeType.LIFESPAN_CHANGED;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TraceChangeType<TraceBreakpoint, Void> getChangedType() {
|
||||
return TraceBreakpointChangeType.CHANGED;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean appliesToKey(String key) {
|
||||
return KEY_RANGE.equals(key) ||
|
||||
TargetObject.DISPLAY_ATTRIBUTE_NAME.equals(key) ||
|
||||
TargetBreakpointSpec.ENABLED_ATTRIBUTE_NAME.equals(key) ||
|
||||
KEY_COMMENT.equals(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TraceChangeType<TraceBreakpoint, Void> getDeletedType() {
|
||||
return TraceBreakpointChangeType.DELETED;
|
||||
}
|
||||
}
|
||||
|
||||
private final DBTraceObject object;
|
||||
private final BreakpointChangeTranslator translator;
|
||||
|
||||
// Keep copies here for when the object gets invalidated
|
||||
private AddressRange range;
|
||||
|
||||
public DBTraceObjectBreakpointLocation(DBTraceObject object) {
|
||||
this.object = object;
|
||||
|
||||
translator = new BreakpointChangeTranslator(object, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Trace getTrace() {
|
||||
return object.getTrace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
return object.getCanonicalPath().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(String name) {
|
||||
object.setValue(getLifespan(), TargetObject.DISPLAY_ATTRIBUTE_NAME, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return TraceObjectInterfaceUtils.getValue(object, getPlacedSnap(),
|
||||
TargetObject.DISPLAY_ATTRIBUTE_NAME, String.class, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRange(AddressRange range) {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
object.setValue(getLifespan(), KEY_RANGE, range);
|
||||
this.range = range;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddressRange getRange() {
|
||||
return range = TraceObjectInterfaceUtils.getValue(object, getPlacedSnap(), KEY_RANGE,
|
||||
AddressRange.class, range);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address getMinAddress() {
|
||||
AddressRange range = getRange();
|
||||
return range == null ? null : range.getMinAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address getMaxAddress() {
|
||||
AddressRange range = getRange();
|
||||
return range == null ? null : range.getMaxAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLength() {
|
||||
AddressRange range = getRange();
|
||||
return range == null ? 0 : range.getLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLifespan(Range<Long> lifespan) throws DuplicateNameException {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
TraceObjectInterfaceUtils.setLifespan(TraceObjectBreakpointLocation.class, object,
|
||||
lifespan);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Range<Long> getLifespan() {
|
||||
return object.getLifespan();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPlacedSnap() {
|
||||
return object.getMinSnap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClearedSnap(long clearedSnap) throws DuplicateNameException {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
setLifespan(DBTraceUtils.toRange(getPlacedSnap(), clearedSnap));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getClearedSnap() {
|
||||
return object.getMaxSnap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceBreakpoint splitAndSet(long snap, boolean enabled,
|
||||
Collection<TraceBreakpointKind> kinds) {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
if (enabled != isEnabled(snap)) {
|
||||
object.setValue(DBTraceUtils.toRange(snap, getClearedSnap()),
|
||||
TargetBreakpointSpec.ENABLED_ATTRIBUTE_NAME, enabled);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnabled(boolean enabled) {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
object.setValue(getLifespan(), TargetBreakpointSpec.ENABLED_ATTRIBUTE_NAME, enabled);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(long snap) {
|
||||
try (LockHold hold = object.getTrace().lockRead()) {
|
||||
Boolean locEn = TraceObjectInterfaceUtils.getValue(object, snap,
|
||||
TargetBreakpointSpec.ENABLED_ATTRIBUTE_NAME, Boolean.class, null);
|
||||
if (locEn != null) {
|
||||
return locEn;
|
||||
}
|
||||
return getSpecification().isEnabled(snap);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setKinds(Collection<TraceBreakpointKind> kinds) {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
TraceObjectBreakpointSpec spec = getSpecification();
|
||||
if (spec.getObject() != this.getObject()) {
|
||||
throw new UnsupportedOperationException("Set via the specification instead");
|
||||
}
|
||||
spec.setKinds(kinds);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<TraceBreakpointKind> getKinds() {
|
||||
try (LockHold hold = object.getTrace().lockRead()) {
|
||||
return getSpecification().getKinds();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<TraceThread> getThreads() {
|
||||
// TODO: Delete this? It's sort of deprecated out the gate anyway....
|
||||
DBTraceObjectManager manager = object.getManager();
|
||||
TargetObjectSchema schema = manager.getRootSchema();
|
||||
try (LockHold hold = object.getTrace().lockRead()) {
|
||||
Set<TraceThread> threads =
|
||||
object.queryAncestorsInterface(getLifespan(), TraceObjectThread.class)
|
||||
.collect(Collectors.toSet());
|
||||
if (!threads.isEmpty()) {
|
||||
return threads;
|
||||
}
|
||||
|
||||
PathMatcher procMatcher = schema.searchFor(TargetProcess.class, false);
|
||||
return object.getAncestors(getLifespan(), procMatcher)
|
||||
.flatMap(proc -> proc.getFirstParent(object)
|
||||
.querySuccessorsInterface(getLifespan(),
|
||||
TraceObjectThread.class))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setComment(String comment) {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
object.setValue(getLifespan(), KEY_COMMENT, comment);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getComment() {
|
||||
return TraceObjectInterfaceUtils.getValue(object, getPlacedSnap(), KEY_COMMENT,
|
||||
String.class, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() {
|
||||
object.deleteTree();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceObject getObject() {
|
||||
return object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceObjectBreakpointSpec getSpecification() {
|
||||
try (LockHold hold = object.getTrace().lockRead()) {
|
||||
return object.queryAncestorsInterface(getLifespan(), TraceObjectBreakpointSpec.class)
|
||||
.findAny()
|
||||
.orElseThrow();
|
||||
}
|
||||
}
|
||||
|
||||
public TraceAddressSpace getTraceAddressSpace() {
|
||||
return spaceForValue(object.getMinSnap(), KEY_RANGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceChangeRecord<?, ?> translateEvent(TraceChangeRecord<?, ?> rec) {
|
||||
return translator.translate(rec);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,231 @@
|
|||
/* ###
|
||||
* 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.trace.database.breakpoint;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.google.common.collect.Range;
|
||||
|
||||
import ghidra.dbg.target.TargetBreakpointSpec;
|
||||
import ghidra.dbg.target.TargetObject;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressRange;
|
||||
import ghidra.trace.database.DBTraceUtils;
|
||||
import ghidra.trace.database.target.DBTraceObject;
|
||||
import ghidra.trace.database.target.DBTraceObjectInterface;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.Trace.TraceBreakpointChangeType;
|
||||
import ghidra.trace.model.Trace.TraceObjectChangeType;
|
||||
import ghidra.trace.model.breakpoint.*;
|
||||
import ghidra.trace.model.target.TraceObject;
|
||||
import ghidra.trace.model.target.TraceObjectValue;
|
||||
import ghidra.trace.model.target.annot.TraceObjectInterfaceUtils;
|
||||
import ghidra.trace.model.thread.TraceObjectThread;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.trace.util.TraceAddressSpace;
|
||||
import ghidra.trace.util.TraceChangeRecord;
|
||||
import ghidra.util.LockHold;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
public class DBTraceObjectBreakpointSpec
|
||||
implements TraceObjectBreakpointSpec, DBTraceObjectInterface {
|
||||
private final DBTraceObject object;
|
||||
|
||||
private Set<TraceBreakpointKind> kinds;
|
||||
|
||||
public DBTraceObjectBreakpointSpec(DBTraceObject object) {
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Trace getTrace() {
|
||||
return object.getTrace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
return object.getCanonicalPath().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(String name) {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
object.setValue(getLifespan(), TargetObject.DISPLAY_ATTRIBUTE_NAME, name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return TraceObjectInterfaceUtils.getValue(object, getPlacedSnap(),
|
||||
TargetObject.DISPLAY_ATTRIBUTE_NAME, String.class, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddressRange getRange() {
|
||||
throw new UnsupportedOperationException("Ask a location instead");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address getMinAddress() {
|
||||
throw new UnsupportedOperationException("Ask a location instead");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address getMaxAddress() {
|
||||
throw new UnsupportedOperationException("Ask a location instead");
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLength() {
|
||||
throw new UnsupportedOperationException("Ask a location instead");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Range<Long> getLifespan() {
|
||||
return object.getLifespan();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getPlacedSnap() {
|
||||
return object.getMinSnap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClearedSnap(long clearedSnap) throws DuplicateNameException {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
setLifespan(DBTraceUtils.toRange(getPlacedSnap(), clearedSnap));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getClearedSnap() {
|
||||
return object.getMaxSnap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLifespan(Range<Long> lifespan) throws DuplicateNameException {
|
||||
TraceObjectInterfaceUtils.setLifespan(TraceObjectThread.class, object, lifespan);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceBreakpoint splitAndSet(long snap, boolean enabled,
|
||||
Collection<TraceBreakpointKind> kinds) {
|
||||
throw new UnsupportedOperationException("Only used by default trace recorder");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnabled(boolean enabled) {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
object.setValue(getLifespan(), TargetBreakpointSpec.ENABLED_ATTRIBUTE_NAME, enabled);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(long snap) {
|
||||
return TraceObjectInterfaceUtils.getValue(object, snap,
|
||||
TargetBreakpointSpec.ENABLED_ATTRIBUTE_NAME, Boolean.class, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setKinds(Collection<TraceBreakpointKind> kinds) {
|
||||
// TODO: More efficient encoding
|
||||
// TODO: Target-Trace mapping is implied by encoded name. Seems bad.
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
object.setValue(getLifespan(), TargetBreakpointSpec.KINDS_ATTRIBUTE_NAME,
|
||||
kinds.stream().map(k -> k.name()).collect(Collectors.joining(",")));
|
||||
this.kinds = Set.copyOf(kinds);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<TraceBreakpointKind> getKinds() {
|
||||
Set<TraceBreakpointKind> result = new HashSet<>();
|
||||
String kindsStr = TraceObjectInterfaceUtils.getValue(object, getPlacedSnap(),
|
||||
TargetBreakpointSpec.KINDS_ATTRIBUTE_NAME, String.class, null);
|
||||
if (kindsStr == null) {
|
||||
return kinds;
|
||||
}
|
||||
for (String name : kindsStr.split(",")) {
|
||||
try {
|
||||
result.add(TraceBreakpointKind.valueOf(name));
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
Msg.warn(this, "Could not decode breakpoint kind from trace database: " + name);
|
||||
}
|
||||
}
|
||||
return kinds = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<TraceThread> getThreads() {
|
||||
throw new UnsupportedOperationException("Ask a location instead");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setComment(String comment) {
|
||||
throw new UnsupportedOperationException("Set on a location instead");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getComment() {
|
||||
throw new UnsupportedOperationException("Ask a location instead");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() {
|
||||
object.deleteTree();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceObject getObject() {
|
||||
return object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends TraceObjectBreakpointLocation> getLocations() {
|
||||
try (LockHold hold = object.getTrace().lockRead()) {
|
||||
return object
|
||||
.querySuccessorsInterface(getLifespan(), TraceObjectBreakpointLocation.class)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceChangeRecord<?, ?> translateEvent(TraceChangeRecord<?, ?> rec) {
|
||||
if (rec.getEventType() == TraceObjectChangeType.VALUE_CHANGED.getType()) {
|
||||
TraceChangeRecord<TraceObjectValue, Object> cast =
|
||||
TraceObjectChangeType.VALUE_CHANGED.cast(rec);
|
||||
String key = cast.getAffectedObject().getEntryKey();
|
||||
boolean applies = TargetBreakpointSpec.KINDS_ATTRIBUTE_NAME.equals(key) ||
|
||||
TargetBreakpointSpec.ENABLED_ATTRIBUTE_NAME.equals(key);
|
||||
if (!applies) {
|
||||
return null;
|
||||
}
|
||||
assert cast.getAffectedObject().getParent() == object;
|
||||
for (TraceObjectBreakpointLocation loc : getLocations()) {
|
||||
DBTraceObjectBreakpointLocation dbLoc = (DBTraceObjectBreakpointLocation) loc;
|
||||
TraceAddressSpace space = dbLoc.getTraceAddressSpace();
|
||||
TraceChangeRecord<?, ?> evt = new TraceChangeRecord<>(
|
||||
TraceBreakpointChangeType.CHANGED, space, loc, null, null);
|
||||
object.getTrace().setChanged(evt);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -36,7 +36,6 @@ import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree;
|
|||
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.AbstractDBTraceAddressSnapRangePropertyMapData;
|
||||
import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager;
|
||||
import ghidra.trace.database.space.DBTraceDelegatingManager;
|
||||
import ghidra.trace.database.thread.DBTraceThread;
|
||||
import ghidra.trace.database.thread.DBTraceThreadManager;
|
||||
import ghidra.trace.model.TraceAddressSnapRange;
|
||||
import ghidra.trace.model.context.TraceRegisterContextManager;
|
||||
|
@ -106,7 +105,7 @@ public class DBTraceRegisterContextManager extends
|
|||
|
||||
@Override
|
||||
protected DBTraceRegisterContextRegisterSpace createRegisterSpace(AddressSpace space,
|
||||
DBTraceThread thread, DBTraceSpaceEntry ent) throws VersionException, IOException {
|
||||
TraceThread thread, DBTraceSpaceEntry ent) throws VersionException, IOException {
|
||||
// TODO: Should I just forbid this? It doesn't seem sane. Then again, what do I know?
|
||||
return new DBTraceRegisterContextRegisterSpace(this, dbh, space, ent, thread);
|
||||
}
|
||||
|
|
|
@ -20,17 +20,17 @@ import java.io.IOException;
|
|||
import db.DBHandle;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager.DBTraceSpaceEntry;
|
||||
import ghidra.trace.database.thread.DBTraceThread;
|
||||
import ghidra.trace.model.context.TraceRegisterContextRegisterSpace;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.util.exception.VersionException;
|
||||
|
||||
public class DBTraceRegisterContextRegisterSpace extends DBTraceRegisterContextSpace
|
||||
implements TraceRegisterContextRegisterSpace {
|
||||
private final DBTraceThread thread;
|
||||
private final TraceThread thread;
|
||||
private final int frameLevel;
|
||||
|
||||
public DBTraceRegisterContextRegisterSpace(DBTraceRegisterContextManager manager, DBHandle dbh,
|
||||
AddressSpace space, DBTraceSpaceEntry ent, DBTraceThread thread)
|
||||
AddressSpace space, DBTraceSpaceEntry ent, TraceThread thread)
|
||||
throws VersionException, IOException {
|
||||
super(manager, dbh, space, ent);
|
||||
this.thread = thread;
|
||||
|
@ -38,7 +38,7 @@ public class DBTraceRegisterContextRegisterSpace extends DBTraceRegisterContextS
|
|||
}
|
||||
|
||||
@Override
|
||||
public DBTraceThread getThread() {
|
||||
public TraceThread getThread() {
|
||||
return thread;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,10 +37,10 @@ import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapSpace;
|
|||
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery;
|
||||
import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager.DBTraceSpaceEntry;
|
||||
import ghidra.trace.database.space.DBTraceSpaceBased;
|
||||
import ghidra.trace.database.thread.DBTraceThread;
|
||||
import ghidra.trace.model.ImmutableTraceAddressSnapRange;
|
||||
import ghidra.trace.model.TraceAddressSnapRange;
|
||||
import ghidra.trace.model.context.TraceRegisterContextSpace;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.util.LockHold;
|
||||
import ghidra.util.database.*;
|
||||
import ghidra.util.database.annot.*;
|
||||
|
@ -126,12 +126,12 @@ public class DBTraceRegisterContextSpace implements TraceRegisterContextSpace, D
|
|||
}
|
||||
|
||||
@Override
|
||||
public DBTraceThread getThread() {
|
||||
public TraceThread getThread() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected long getThreadKey() {
|
||||
DBTraceThread thread = getThread();
|
||||
TraceThread thread = getThread();
|
||||
return thread == null ? -1 : thread.getKey();
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,6 @@ import ghidra.trace.database.DBTraceUtils;
|
|||
import ghidra.trace.database.data.DBTraceDataSettingsAdapter.DBTraceSettingsEntry;
|
||||
import ghidra.trace.database.map.*;
|
||||
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.AbstractDBTraceAddressSnapRangePropertyMapData;
|
||||
import ghidra.trace.database.thread.DBTraceThread;
|
||||
import ghidra.trace.database.thread.DBTraceThreadManager;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.trace.util.TraceAddressSpace;
|
||||
|
@ -183,7 +182,7 @@ public class DBTraceDataSettingsAdapter
|
|||
implements DBTraceDataSettingsOperations {
|
||||
public DBTraceDataSettingsRegisterSpace(String tableName,
|
||||
DBCachedObjectStoreFactory storeFactory, ReadWriteLock lock, AddressSpace space,
|
||||
DBTraceThread thread, int frameLevel, Class<DBTraceSettingsEntry> dataType,
|
||||
TraceThread thread, int frameLevel, Class<DBTraceSettingsEntry> dataType,
|
||||
DBTraceAddressSnapRangePropertyMapDataFactory<DBTraceSettingsEntry, DBTraceSettingsEntry> dataFactory)
|
||||
throws VersionException, IOException {
|
||||
super(tableName, storeFactory, lock, space, thread, frameLevel, dataType, dataFactory);
|
||||
|
@ -217,7 +216,7 @@ public class DBTraceDataSettingsAdapter
|
|||
|
||||
@Override
|
||||
protected DBTraceAddressSnapRangePropertyMapRegisterSpace<DBTraceSettingsEntry, DBTraceSettingsEntry> createRegisterSpace(
|
||||
AddressSpace space, DBTraceThread thread, DBTraceSpaceEntry ent)
|
||||
AddressSpace space, TraceThread thread, DBTraceSpaceEntry ent)
|
||||
throws VersionException, IOException {
|
||||
return new DBTraceDataSettingsRegisterSpace(
|
||||
tableName(space, ent.getThreadKey(), ent.getFrameLevel()),
|
||||
|
|
|
@ -46,7 +46,6 @@ import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAdd
|
|||
import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager;
|
||||
import ghidra.trace.database.space.DBTraceDelegatingManager;
|
||||
import ghidra.trace.database.symbol.DBTraceReferenceManager;
|
||||
import ghidra.trace.database.thread.DBTraceThread;
|
||||
import ghidra.trace.database.thread.DBTraceThreadManager;
|
||||
import ghidra.trace.model.AddressSnap;
|
||||
import ghidra.trace.model.DefaultAddressSnap;
|
||||
|
@ -222,7 +221,7 @@ public class DBTraceCodeManager
|
|||
|
||||
// Internal
|
||||
public UndefinedDBTraceData doCreateUndefinedUnit(long snap, Address address,
|
||||
DBTraceThread thread, int frameLevel) {
|
||||
TraceThread thread, int frameLevel) {
|
||||
return undefinedCache.computeIfAbsent(new DefaultAddressSnap(address, snap),
|
||||
ot -> new UndefinedDBTraceData(trace, snap, address, thread, frameLevel));
|
||||
}
|
||||
|
@ -279,7 +278,7 @@ public class DBTraceCodeManager
|
|||
}
|
||||
|
||||
@Override
|
||||
protected DBTraceCodeRegisterSpace createRegisterSpace(AddressSpace space, DBTraceThread thread,
|
||||
protected DBTraceCodeRegisterSpace createRegisterSpace(AddressSpace space, TraceThread thread,
|
||||
DBTraceSpaceEntry ent) throws VersionException, IOException {
|
||||
return new DBTraceCodeRegisterSpace(this, dbh, space, ent, thread);
|
||||
}
|
||||
|
|
|
@ -20,23 +20,23 @@ import java.io.IOException;
|
|||
import db.DBHandle;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager.DBTraceSpaceEntry;
|
||||
import ghidra.trace.database.thread.DBTraceThread;
|
||||
import ghidra.trace.model.listing.TraceCodeRegisterSpace;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.util.exception.VersionException;
|
||||
|
||||
public class DBTraceCodeRegisterSpace extends DBTraceCodeSpace implements TraceCodeRegisterSpace {
|
||||
protected final DBTraceThread thread;
|
||||
protected final TraceThread thread;
|
||||
private final int frameLevel;
|
||||
|
||||
public DBTraceCodeRegisterSpace(DBTraceCodeManager manager, DBHandle dbh, AddressSpace space,
|
||||
DBTraceSpaceEntry ent, DBTraceThread thread) throws VersionException, IOException {
|
||||
DBTraceSpaceEntry ent, TraceThread thread) throws VersionException, IOException {
|
||||
super(manager, dbh, space, ent);
|
||||
this.thread = thread;
|
||||
this.frameLevel = ent.getFrameLevel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DBTraceThread getThread() {
|
||||
public TraceThread getThread() {
|
||||
return thread;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,9 +37,9 @@ import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAdd
|
|||
import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager.DBTraceSpaceEntry;
|
||||
import ghidra.trace.database.space.DBTraceSpaceBased;
|
||||
import ghidra.trace.database.symbol.DBTraceReferenceManager;
|
||||
import ghidra.trace.database.thread.DBTraceThread;
|
||||
import ghidra.trace.model.TraceAddressSnapRange;
|
||||
import ghidra.trace.model.listing.TraceCodeSpace;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.trace.util.ByteArrayUtils;
|
||||
import ghidra.util.LockHold;
|
||||
import ghidra.util.database.DBCachedObjectStoreFactory;
|
||||
|
@ -169,7 +169,7 @@ public class DBTraceCodeSpace implements TraceCodeSpace, DBTraceSpaceBased {
|
|||
}
|
||||
|
||||
@Override
|
||||
public DBTraceThread getThread() {
|
||||
public TraceThread getThread() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -32,10 +32,10 @@ import ghidra.program.model.mem.Memory;
|
|||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.trace.database.DBTrace;
|
||||
import ghidra.trace.database.memory.DBTraceMemoryRegion;
|
||||
import ghidra.trace.database.symbol.DBTraceReference;
|
||||
import ghidra.trace.model.listing.TraceCodeUnit;
|
||||
import ghidra.trace.model.map.TracePropertyMap;
|
||||
import ghidra.trace.model.memory.TraceMemoryRegion;
|
||||
import ghidra.trace.model.program.TraceProgramView;
|
||||
import ghidra.trace.model.symbol.TraceReference;
|
||||
import ghidra.trace.model.symbol.TraceSymbol;
|
||||
|
@ -74,7 +74,7 @@ public interface DBTraceCodeUnitAdapter extends TraceCodeUnit, MemBufferAdapter
|
|||
if (!showBlockName) {
|
||||
return address.toString(false, pad);
|
||||
}
|
||||
DBTraceMemoryRegion region =
|
||||
TraceMemoryRegion region =
|
||||
getTrace().getMemoryManager().getRegionContaining(getStartSnap(), address);
|
||||
if (region == null) {
|
||||
return address.toString(showBlockName, pad);
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
*/
|
||||
package ghidra.trace.database.listing;
|
||||
|
||||
import ghidra.trace.database.thread.DBTraceThread;
|
||||
import ghidra.trace.model.listing.TraceCodeUnitsRegisterView;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
|
||||
public class DBTraceCodeUnitsRegisterView extends DBTraceCodeUnitsView
|
||||
implements TraceCodeUnitsRegisterView {
|
||||
|
@ -25,7 +25,7 @@ public class DBTraceCodeUnitsRegisterView extends DBTraceCodeUnitsView
|
|||
}
|
||||
|
||||
@Override
|
||||
public DBTraceThread getThread() {
|
||||
public TraceThread getThread() {
|
||||
return space.getThread();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
*/
|
||||
package ghidra.trace.database.listing;
|
||||
|
||||
import ghidra.trace.database.thread.DBTraceThread;
|
||||
import ghidra.trace.model.listing.TraceDataRegisterView;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
|
||||
public class DBTraceDataRegisterView extends DBTraceDataView implements TraceDataRegisterView {
|
||||
public DBTraceDataRegisterView(DBTraceCodeSpace space) {
|
||||
|
@ -24,7 +24,7 @@ public class DBTraceDataRegisterView extends DBTraceDataView implements TraceDat
|
|||
}
|
||||
|
||||
@Override
|
||||
public DBTraceThread getThread() {
|
||||
public TraceThread getThread() {
|
||||
return space.getThread();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
*/
|
||||
package ghidra.trace.database.listing;
|
||||
|
||||
import ghidra.trace.database.thread.DBTraceThread;
|
||||
import ghidra.trace.model.listing.TraceInstructionsRegisterView;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
|
||||
public class DBTraceInstructionsRegisterView extends DBTraceInstructionsView
|
||||
implements TraceInstructionsRegisterView {
|
||||
|
@ -26,7 +26,7 @@ public class DBTraceInstructionsRegisterView extends DBTraceInstructionsView
|
|||
}
|
||||
|
||||
@Override
|
||||
public DBTraceThread getThread() {
|
||||
public TraceThread getThread() {
|
||||
return space.getThread();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,6 @@ import ghidra.trace.model.listing.TraceInstructionsView;
|
|||
import ghidra.trace.util.OverlappingObjectIterator;
|
||||
import ghidra.trace.util.TraceChangeRecord;
|
||||
import ghidra.util.LockHold;
|
||||
import ghidra.util.SystemUtilities;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
|
|
|
@ -31,10 +31,10 @@ import ghidra.trace.database.DBTraceUtils;
|
|||
import ghidra.trace.database.data.DBTraceDataSettingsOperations;
|
||||
import ghidra.trace.database.memory.DBTraceMemorySpace;
|
||||
import ghidra.trace.database.space.DBTraceSpaceKey;
|
||||
import ghidra.trace.database.thread.DBTraceThread;
|
||||
import ghidra.trace.model.ImmutableTraceAddressSnapRange;
|
||||
import ghidra.trace.model.TraceAddressSnapRange;
|
||||
import ghidra.trace.model.listing.TraceData;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.trace.util.TraceAddressSpace;
|
||||
|
||||
public class UndefinedDBTraceData implements DBTraceDataAdapter, DBTraceSpaceKey {
|
||||
|
@ -42,10 +42,10 @@ public class UndefinedDBTraceData implements DBTraceDataAdapter, DBTraceSpaceKey
|
|||
protected final long snap;
|
||||
protected final Range<Long> lifespan;
|
||||
protected final Address address;
|
||||
protected final DBTraceThread thread;
|
||||
protected final TraceThread thread;
|
||||
protected final int frameLevel;
|
||||
|
||||
public UndefinedDBTraceData(DBTrace trace, long snap, Address address, DBTraceThread thread,
|
||||
public UndefinedDBTraceData(DBTrace trace, long snap, Address address, TraceThread thread,
|
||||
int frameLevel) {
|
||||
this.trace = trace;
|
||||
this.snap = snap;
|
||||
|
@ -118,7 +118,7 @@ public class UndefinedDBTraceData implements DBTraceDataAdapter, DBTraceSpaceKey
|
|||
}
|
||||
|
||||
@Override
|
||||
public DBTraceThread getThread() {
|
||||
public TraceThread getThread() {
|
||||
return thread;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,6 @@ import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.Abstract
|
|||
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery;
|
||||
import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager;
|
||||
import ghidra.trace.database.space.DBTraceDelegatingManager;
|
||||
import ghidra.trace.database.thread.DBTraceThread;
|
||||
import ghidra.trace.database.thread.DBTraceThreadManager;
|
||||
import ghidra.trace.model.TraceAddressSnapRange;
|
||||
import ghidra.trace.model.map.TraceAddressSnapRangePropertyMap;
|
||||
|
@ -89,7 +88,7 @@ public class DBTraceAddressSnapRangePropertyMap<T, DR extends AbstractDBTraceAdd
|
|||
|
||||
@Override
|
||||
protected DBTraceAddressSnapRangePropertyMapRegisterSpace<T, DR> createRegisterSpace(
|
||||
AddressSpace space, DBTraceThread thread, DBTraceSpaceEntry ent)
|
||||
AddressSpace space, TraceThread thread, DBTraceSpaceEntry ent)
|
||||
throws VersionException, IOException {
|
||||
return new DBTraceAddressSnapRangePropertyMapRegisterSpace<>(
|
||||
tableName(space, ent.getThreadKey(), ent.getFrameLevel()), trace.getStoreFactory(),
|
||||
|
|
|
@ -21,20 +21,20 @@ import java.util.concurrent.locks.ReadWriteLock;
|
|||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMap.DBTraceAddressSnapRangePropertyMapDataFactory;
|
||||
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.AbstractDBTraceAddressSnapRangePropertyMapData;
|
||||
import ghidra.trace.database.thread.DBTraceThread;
|
||||
import ghidra.trace.model.map.TraceAddressSnapRangePropertyMapRegisterSpace;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.util.database.DBCachedObjectStoreFactory;
|
||||
import ghidra.util.exception.VersionException;
|
||||
|
||||
public class DBTraceAddressSnapRangePropertyMapRegisterSpace<T, DR extends AbstractDBTraceAddressSnapRangePropertyMapData<T>>
|
||||
extends DBTraceAddressSnapRangePropertyMapSpace<T, DR>
|
||||
implements TraceAddressSnapRangePropertyMapRegisterSpace<T> {
|
||||
protected final DBTraceThread thread;
|
||||
protected final TraceThread thread;
|
||||
protected final int frameLevel;
|
||||
|
||||
public DBTraceAddressSnapRangePropertyMapRegisterSpace(String tableName,
|
||||
DBCachedObjectStoreFactory storeFactory, ReadWriteLock lock, AddressSpace space,
|
||||
DBTraceThread thread, int frameLevel, Class<DR> dataType,
|
||||
TraceThread thread, int frameLevel, Class<DR> dataType,
|
||||
DBTraceAddressSnapRangePropertyMapDataFactory<T, DR> dataFactory)
|
||||
throws VersionException, IOException {
|
||||
super(tableName, storeFactory, lock, space, dataType, dataFactory);
|
||||
|
@ -43,7 +43,7 @@ public class DBTraceAddressSnapRangePropertyMapRegisterSpace<T, DR extends Abstr
|
|||
}
|
||||
|
||||
@Override
|
||||
public DBTraceThread getThread() {
|
||||
public TraceThread getThread() {
|
||||
return thread;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,9 +29,9 @@ import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMap.DBTraceAddre
|
|||
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.AbstractDBTraceAddressSnapRangePropertyMapData;
|
||||
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery;
|
||||
import ghidra.trace.database.space.DBTraceSpaceBased;
|
||||
import ghidra.trace.database.thread.DBTraceThread;
|
||||
import ghidra.trace.model.TraceAddressSnapRange;
|
||||
import ghidra.trace.model.map.TraceAddressSnapRangePropertyMapSpace;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.util.LockHold;
|
||||
import ghidra.util.database.*;
|
||||
import ghidra.util.database.spatial.AbstractConstraintsTreeSpatialMap;
|
||||
|
@ -69,7 +69,7 @@ public class DBTraceAddressSnapRangePropertyMapSpace<T, DR extends AbstractDBTra
|
|||
}
|
||||
|
||||
@Override
|
||||
public DBTraceThread getThread() {
|
||||
public TraceThread getThread() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ import com.google.common.collect.Collections2;
|
|||
import com.google.common.collect.Range;
|
||||
|
||||
import db.DBHandle;
|
||||
import ghidra.dbg.target.TargetMemoryRegion;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
|
@ -36,7 +37,6 @@ import ghidra.trace.database.address.DBTraceOverlaySpaceAdapter;
|
|||
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery;
|
||||
import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager;
|
||||
import ghidra.trace.database.space.DBTraceDelegatingManager;
|
||||
import ghidra.trace.database.thread.DBTraceThread;
|
||||
import ghidra.trace.database.thread.DBTraceThreadManager;
|
||||
import ghidra.trace.model.TraceAddressSnapRange;
|
||||
import ghidra.trace.model.memory.*;
|
||||
|
@ -85,7 +85,7 @@ public class DBTraceMemoryManager
|
|||
|
||||
@Override
|
||||
protected DBTraceMemoryRegisterSpace createRegisterSpace(AddressSpace space,
|
||||
DBTraceThread thread, DBTraceSpaceEntry ent) throws VersionException, IOException {
|
||||
TraceThread thread, DBTraceSpaceEntry ent) throws VersionException, IOException {
|
||||
return new DBTraceMemoryRegisterSpace(this, dbh, space, ent, thread);
|
||||
}
|
||||
|
||||
|
@ -128,9 +128,12 @@ public class DBTraceMemoryManager
|
|||
}
|
||||
|
||||
@Override
|
||||
public DBTraceMemoryRegion addRegion(String path, Range<Long> lifespan,
|
||||
public TraceMemoryRegion addRegion(String path, Range<Long> lifespan,
|
||||
AddressRange range, Collection<TraceMemoryFlag> flags)
|
||||
throws TraceOverlappedRegionException, DuplicateNameException {
|
||||
if (trace.getObjectManager().hasSchema()) {
|
||||
return trace.getObjectManager().addMemoryRegion(path, lifespan, range, flags);
|
||||
}
|
||||
try {
|
||||
return delegateWrite(range.getAddressSpace(),
|
||||
m -> m.addRegion(path, lifespan, range, flags));
|
||||
|
@ -144,35 +147,50 @@ public class DBTraceMemoryManager
|
|||
}
|
||||
|
||||
@Override
|
||||
public Collection<TraceMemoryRegion> getAllRegions() {
|
||||
public Collection<? extends TraceMemoryRegion> getAllRegions() {
|
||||
if (trace.getObjectManager().hasSchema()) {
|
||||
return trace.getObjectManager().getAllObjects(TraceObjectMemoryRegion.class);
|
||||
}
|
||||
return delegateCollection(getActiveMemorySpaces(), m -> m.getAllRegions());
|
||||
}
|
||||
|
||||
// Internal
|
||||
public Collection<DBTraceMemoryRegion> getRegionsInternal() {
|
||||
return delegateCollection(getActiveMemorySpaces(), m -> m.regionMapSpace.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DBTraceMemoryRegion getLiveRegionByPath(long snap, String regionName) {
|
||||
public TraceMemoryRegion getLiveRegionByPath(long snap, String path) {
|
||||
if (trace.getObjectManager().hasSchema()) {
|
||||
return trace.getObjectManager()
|
||||
.getObjectByPath(snap, path, TraceObjectMemoryRegion.class);
|
||||
}
|
||||
// Not efficient, but I don't anticipate many regions
|
||||
return delegateFirst(getActiveMemorySpaces(), m -> m.getLiveRegionByPath(snap, regionName));
|
||||
return delegateFirst(getActiveMemorySpaces(), m -> m.getLiveRegionByPath(snap, path));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DBTraceMemoryRegion getRegionContaining(long snap, Address address) {
|
||||
public TraceMemoryRegion getRegionContaining(long snap, Address address) {
|
||||
if (trace.getObjectManager().hasSchema()) {
|
||||
return trace.getObjectManager()
|
||||
.getObjectContaining(snap, address, TargetMemoryRegion.RANGE_ATTRIBUTE_NAME,
|
||||
TraceObjectMemoryRegion.class);
|
||||
}
|
||||
return delegateRead(address.getAddressSpace(), m -> m.getRegionContaining(snap, address));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends DBTraceMemoryRegion> getRegionsIntersecting(Range<Long> lifespan,
|
||||
public Collection<? extends TraceMemoryRegion> getRegionsIntersecting(Range<Long> lifespan,
|
||||
AddressRange range) {
|
||||
if (trace.getObjectManager().hasSchema()) {
|
||||
return trace.getObjectManager()
|
||||
.getObjectsIntersecting(lifespan, range,
|
||||
TargetMemoryRegion.RANGE_ATTRIBUTE_NAME, TraceObjectMemoryRegion.class);
|
||||
}
|
||||
return delegateRead(range.getAddressSpace(), m -> m.getRegionsIntersecting(lifespan, range),
|
||||
Collections.emptyList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends DBTraceMemoryRegion> getRegionsAtSnap(long snap) {
|
||||
public Collection<? extends TraceMemoryRegion> getRegionsAtSnap(long snap) {
|
||||
if (trace.getObjectManager().hasSchema()) {
|
||||
return trace.getObjectManager().getObjectsAtSnap(snap, TraceObjectMemoryRegion.class);
|
||||
}
|
||||
return delegateCollection(memSpaces.values(), m -> m.getRegionsAtSnap(snap));
|
||||
}
|
||||
|
||||
|
@ -193,6 +211,11 @@ public class DBTraceMemoryManager
|
|||
|
||||
@Override
|
||||
public AddressSetView getRegionsAddressSet(long snap) {
|
||||
if (trace.getObjectManager().hasSchema()) {
|
||||
return trace.getObjectManager()
|
||||
.getObjectsAddressSet(snap, TargetMemoryRegion.RANGE_ATTRIBUTE_NAME,
|
||||
TraceObjectMemoryRegion.class, r -> true);
|
||||
}
|
||||
return new UnionAddressSetView(Collections2.transform(getActiveMemorySpaces(),
|
||||
m -> m.getRegionsAddressSet(snap)));
|
||||
}
|
||||
|
@ -200,6 +223,11 @@ public class DBTraceMemoryManager
|
|||
@Override
|
||||
public AddressSetView getRegionsAddressSetWith(long snap,
|
||||
Predicate<TraceMemoryRegion> predicate) {
|
||||
if (trace.getObjectManager().hasSchema()) {
|
||||
return trace.getObjectManager()
|
||||
.getObjectsAddressSet(snap, TargetMemoryRegion.RANGE_ATTRIBUTE_NAME,
|
||||
TraceObjectMemoryRegion.class, predicate);
|
||||
}
|
||||
return new UnionAddressSetView(Collections2.transform(getActiveMemorySpaces(),
|
||||
m -> m.getRegionsAddressSetWith(snap, predicate)));
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ public class DBTraceMemoryRegion
|
|||
|
||||
private final DBTraceMemorySpace space;
|
||||
|
||||
private final Set<TraceMemoryFlag> flags = EnumSet.noneOf(TraceMemoryFlag.class);
|
||||
private final EnumSet<TraceMemoryFlag> flags = EnumSet.noneOf(TraceMemoryFlag.class);
|
||||
|
||||
public DBTraceMemoryRegion(DBTraceMemorySpace space,
|
||||
DBTraceAddressSnapRangePropertyMapTree<DBTraceMemoryRegion, DBTraceMemoryRegion> tree,
|
||||
|
@ -81,11 +81,7 @@ public class DBTraceMemoryRegion
|
|||
return;
|
||||
}
|
||||
flags.clear();
|
||||
for (TraceMemoryFlag f : TraceMemoryFlag.values()) {
|
||||
if ((flagsByte & f.getBits()) != 0) {
|
||||
flags.add(f);
|
||||
}
|
||||
}
|
||||
TraceMemoryFlag.fromBits(flags, flagsByte);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -271,14 +267,11 @@ public class DBTraceMemoryRegion
|
|||
@Override
|
||||
public void setFlags(Collection<TraceMemoryFlag> flags) {
|
||||
try (LockHold hold = LockHold.lock(space.lock.writeLock())) {
|
||||
this.flagsByte = 0;
|
||||
this.flagsByte = TraceMemoryFlag.toBits(flags);
|
||||
this.flags.clear();
|
||||
for (TraceMemoryFlag f : flags) {
|
||||
this.flagsByte |= f.getBits();
|
||||
this.flags.add(f);
|
||||
}
|
||||
this.flags.addAll(flags);
|
||||
update(FLAGS_COLUMN);
|
||||
space.trace.updateViewsChangeRegionBlockFlags(this);
|
||||
space.trace.updateViewsChangeRegionBlockFlags(this, lifespan);
|
||||
}
|
||||
space.trace.setChanged(
|
||||
new TraceChangeRecord<>(TraceMemoryRegionChangeType.CHANGED, space, this));
|
||||
|
@ -288,12 +281,10 @@ public class DBTraceMemoryRegion
|
|||
@Override
|
||||
public void addFlags(Collection<TraceMemoryFlag> flags) {
|
||||
try (LockHold hold = LockHold.lock(space.lock.writeLock())) {
|
||||
for (TraceMemoryFlag f : flags) {
|
||||
this.flagsByte |= f.getBits();
|
||||
this.flags.add(f);
|
||||
}
|
||||
this.flagsByte |= TraceMemoryFlag.toBits(flags);
|
||||
this.flags.addAll(flags);
|
||||
update(FLAGS_COLUMN);
|
||||
space.trace.updateViewsChangeRegionBlockFlags(this);
|
||||
space.trace.updateViewsChangeRegionBlockFlags(this, lifespan);
|
||||
}
|
||||
space.trace.setChanged(
|
||||
new TraceChangeRecord<>(TraceMemoryRegionChangeType.CHANGED, space, this));
|
||||
|
@ -303,12 +294,10 @@ public class DBTraceMemoryRegion
|
|||
@Override
|
||||
public void clearFlags(Collection<TraceMemoryFlag> flags) {
|
||||
try (LockHold hold = LockHold.lock(space.lock.writeLock())) {
|
||||
for (TraceMemoryFlag f : flags) {
|
||||
this.flagsByte &= ~f.getBits();
|
||||
this.flags.remove(f);
|
||||
}
|
||||
this.flagsByte &= ~TraceMemoryFlag.toBits(flags);
|
||||
this.flags.removeAll(flags);
|
||||
update(FLAGS_COLUMN);
|
||||
space.trace.updateViewsChangeRegionBlockFlags(this);
|
||||
space.trace.updateViewsChangeRegionBlockFlags(this, lifespan);
|
||||
}
|
||||
space.trace.setChanged(
|
||||
new TraceChangeRecord<>(TraceMemoryRegionChangeType.CHANGED, space, this));
|
||||
|
|
|
@ -26,18 +26,18 @@ import ghidra.program.model.address.AddressRange;
|
|||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.trace.database.listing.DBTraceCodeRegisterSpace;
|
||||
import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager.DBTraceSpaceEntry;
|
||||
import ghidra.trace.database.thread.DBTraceThread;
|
||||
import ghidra.trace.model.memory.*;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.exception.VersionException;
|
||||
|
||||
public class DBTraceMemoryRegisterSpace extends DBTraceMemorySpace
|
||||
implements TraceMemoryRegisterSpace {
|
||||
protected final DBTraceThread thread;
|
||||
protected final TraceThread thread;
|
||||
private final int frameLevel;
|
||||
|
||||
public DBTraceMemoryRegisterSpace(DBTraceMemoryManager manager, DBHandle dbh,
|
||||
AddressSpace space, DBTraceSpaceEntry ent, DBTraceThread thread)
|
||||
AddressSpace space, DBTraceSpaceEntry ent, TraceThread thread)
|
||||
throws IOException, VersionException {
|
||||
super(manager, dbh, space, ent);
|
||||
this.thread = thread;
|
||||
|
@ -45,7 +45,7 @@ public class DBTraceMemoryRegisterSpace extends DBTraceMemorySpace
|
|||
}
|
||||
|
||||
@Override
|
||||
public DBTraceThread getThread() {
|
||||
public TraceThread getThread() {
|
||||
return thread;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,16 +33,17 @@ import ghidra.program.model.address.*;
|
|||
import ghidra.program.model.mem.MemBuffer;
|
||||
import ghidra.trace.database.DBTrace;
|
||||
import ghidra.trace.database.DBTraceUtils;
|
||||
import ghidra.trace.database.DBTraceUtils.AddressRangeMapSetter;
|
||||
import ghidra.trace.database.DBTraceUtils.OffsetSnap;
|
||||
import ghidra.trace.database.listing.DBTraceCodeSpace;
|
||||
import ghidra.trace.database.map.*;
|
||||
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery;
|
||||
import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager.DBTraceSpaceEntry;
|
||||
import ghidra.trace.database.space.DBTraceSpaceBased;
|
||||
import ghidra.trace.database.thread.DBTraceThread;
|
||||
import ghidra.trace.model.*;
|
||||
import ghidra.trace.model.Trace.*;
|
||||
import ghidra.trace.model.memory.*;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.trace.util.TraceChangeRecord;
|
||||
import ghidra.trace.util.TraceViewportSpanIterator;
|
||||
import ghidra.util.*;
|
||||
|
@ -261,7 +262,7 @@ public class DBTraceMemorySpace implements Unfinished, TraceMemorySpace, DBTrace
|
|||
}
|
||||
|
||||
@Override
|
||||
public DBTraceThread getThread() {
|
||||
public TraceThread getThread() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -274,55 +275,42 @@ public class DBTraceMemorySpace implements Unfinished, TraceMemorySpace, DBTrace
|
|||
if (state == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
// Go one out to find abutting ranges, too.
|
||||
Address prev = start.previous();
|
||||
if (prev == null) {
|
||||
prev = start;
|
||||
}
|
||||
Address next = end.next();
|
||||
if (next == null) {
|
||||
next = end;
|
||||
}
|
||||
Map<TraceAddressSnapRange, TraceMemoryState> toPut = new HashMap<>();
|
||||
for (Entry<TraceAddressSnapRange, TraceMemoryState> entry : stateMapSpace.reduce(
|
||||
TraceAddressSnapRangeQuery.intersecting(prev, next, snap, snap)).entries()) {
|
||||
// NOTE: Entries are in no particular order
|
||||
AddressRange range = entry.getKey().getRange();
|
||||
boolean precedesMin = range.getMinAddress().compareTo(start) < 0;
|
||||
boolean procedesMax = range.getMaxAddress().compareTo(end) > 0;
|
||||
boolean sameState = entry.getValue() == state;
|
||||
if (precedesMin && procedesMax && sameState) {
|
||||
return; // The value in this range is already the desired state
|
||||
|
||||
new AddressRangeMapSetter<Entry<TraceAddressSnapRange, TraceMemoryState>, TraceMemoryState>() {
|
||||
@Override
|
||||
protected AddressRange getRange(Entry<TraceAddressSnapRange, TraceMemoryState> entry) {
|
||||
return entry.getKey().getRange();
|
||||
}
|
||||
stateMapSpace.remove(entry);
|
||||
if (precedesMin) {
|
||||
if (sameState) {
|
||||
start = range.getMinAddress();
|
||||
}
|
||||
else {
|
||||
toPut.put(
|
||||
new ImmutableTraceAddressSnapRange(range.getMinAddress(), prev, snap, snap),
|
||||
entry.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TraceMemoryState getValue(
|
||||
Entry<TraceAddressSnapRange, TraceMemoryState> entry) {
|
||||
return entry.getValue();
|
||||
}
|
||||
if (procedesMax) {
|
||||
if (sameState) {
|
||||
end = range.getMaxAddress();
|
||||
}
|
||||
else {
|
||||
toPut.put(
|
||||
new ImmutableTraceAddressSnapRange(next, range.getMaxAddress(), snap, snap),
|
||||
entry.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void remove(Entry<TraceAddressSnapRange, TraceMemoryState> entry) {
|
||||
stateMapSpace.remove(entry);
|
||||
}
|
||||
}
|
||||
if (state != TraceMemoryState.UNKNOWN) {
|
||||
stateMapSpace.put(start, end, snap, state);
|
||||
}
|
||||
assert toPut.size() <= 2;
|
||||
for (Entry<TraceAddressSnapRange, TraceMemoryState> ent : toPut.entrySet()) {
|
||||
stateMapSpace.put(ent.getKey(), ent.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Iterable<Entry<TraceAddressSnapRange, TraceMemoryState>> getIntersecting(
|
||||
Address lower, Address upper) {
|
||||
return stateMapSpace
|
||||
.reduce(TraceAddressSnapRangeQuery.intersecting(lower, upper, snap, snap))
|
||||
.entries();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Entry<TraceAddressSnapRange, TraceMemoryState> put(AddressRange range,
|
||||
TraceMemoryState value) {
|
||||
if (value != TraceMemoryState.UNKNOWN) {
|
||||
stateMapSpace.put(new ImmutableTraceAddressSnapRange(range, snap), value);
|
||||
}
|
||||
return null; // Don't need to return it
|
||||
}
|
||||
}.set(start, end, state);
|
||||
|
||||
trace.setChanged(new TraceChangeRecord<>(TraceMemoryStateChangeType.CHANGED, this,
|
||||
new ImmutableTraceAddressSnapRange(start, end, snap, snap), state));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,312 @@
|
|||
/* ###
|
||||
* 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.trace.database.memory;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import com.google.common.collect.Range;
|
||||
|
||||
import ghidra.dbg.target.TargetMemoryRegion;
|
||||
import ghidra.dbg.target.TargetObject;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.trace.database.DBTraceUtils;
|
||||
import ghidra.trace.database.target.DBTraceObject;
|
||||
import ghidra.trace.database.target.DBTraceObjectInterface;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.Trace.TraceMemoryRegionChangeType;
|
||||
import ghidra.trace.model.memory.*;
|
||||
import ghidra.trace.model.target.TraceObject;
|
||||
import ghidra.trace.model.target.TraceObjectValue;
|
||||
import ghidra.trace.model.target.annot.TraceObjectInterfaceUtils;
|
||||
import ghidra.trace.util.TraceChangeRecord;
|
||||
import ghidra.trace.util.TraceChangeType;
|
||||
import ghidra.util.LockHold;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
public class DBTraceObjectMemoryRegion implements TraceObjectMemoryRegion, DBTraceObjectInterface {
|
||||
|
||||
protected class RegionChangeTranslator extends Translator<TraceMemoryRegion> {
|
||||
protected RegionChangeTranslator(DBTraceObject object, TraceMemoryRegion iface) {
|
||||
super(TargetMemoryRegion.RANGE_ATTRIBUTE_NAME, object, iface);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TraceChangeType<TraceMemoryRegion, Void> getAddedType() {
|
||||
return TraceMemoryRegionChangeType.ADDED;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TraceChangeType<TraceMemoryRegion, Range<Long>> getLifespanChangedType() {
|
||||
return TraceMemoryRegionChangeType.LIFESPAN_CHANGED;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TraceChangeType<TraceMemoryRegion, Void> getChangedType() {
|
||||
return TraceMemoryRegionChangeType.CHANGED;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean appliesToKey(String key) {
|
||||
return TargetMemoryRegion.RANGE_ATTRIBUTE_NAME.equals(key) ||
|
||||
TargetObject.DISPLAY_ATTRIBUTE_NAME.equals(key) ||
|
||||
TargetMemoryRegion.READABLE_ATTRIBUTE_NAME.equals(key) ||
|
||||
TargetMemoryRegion.WRITABLE_ATTRIBUTE_NAME.equals(key) ||
|
||||
TargetMemoryRegion.EXECUTABLE_ATTRIBUTE_NAME.equals(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TraceChangeType<TraceMemoryRegion, Void> getDeletedType() {
|
||||
return TraceMemoryRegionChangeType.DELETED;
|
||||
}
|
||||
}
|
||||
|
||||
private final DBTraceObject object;
|
||||
private final RegionChangeTranslator translator;
|
||||
|
||||
public DBTraceObjectMemoryRegion(DBTraceObject object) {
|
||||
this.object = object;
|
||||
|
||||
translator = new RegionChangeTranslator(object, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Trace getTrace() {
|
||||
return object.getTrace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
return object.getCanonicalPath().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(String name) {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
object.setValue(getLifespan(), TargetObject.DISPLAY_ATTRIBUTE_NAME, name);
|
||||
object.getTrace().updateViewsChangeRegionBlockName(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
TraceObjectValue value =
|
||||
object.getValue(getCreationSnap(), TargetObject.DISPLAY_ATTRIBUTE_NAME);
|
||||
return value == null ? "" : (String) value.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLifespan(Range<Long> newLifespan) throws DuplicateNameException {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
Range<Long> oldLifespan = getLifespan();
|
||||
if (Objects.equals(oldLifespan, newLifespan)) {
|
||||
return;
|
||||
}
|
||||
TraceObjectInterfaceUtils.setLifespan(TraceObjectMemoryRegion.class, object,
|
||||
newLifespan);
|
||||
object.getTrace().updateViewsChangeRegionBlockLifespan(this, oldLifespan, newLifespan);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Range<Long> getLifespan() {
|
||||
return object.getLifespan();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreationSnap(long creationSnap) throws DuplicateNameException {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
setLifespan(DBTraceUtils.toRange(creationSnap, getDestructionSnap()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCreationSnap() {
|
||||
return object.getMinSnap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDestructionSnap(long destructionSnap) throws DuplicateNameException {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
setLifespan(DBTraceUtils.toRange(getCreationSnap(), destructionSnap));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getDestructionSnap() {
|
||||
return object.getMaxSnap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRange(AddressRange newRange) {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
AddressRange oldRange = getRange();
|
||||
if (Objects.equals(oldRange, newRange)) {
|
||||
return;
|
||||
}
|
||||
object.setValue(getLifespan(), TargetMemoryRegion.RANGE_ATTRIBUTE_NAME, newRange);
|
||||
object.getTrace().updateViewsChangeRegionBlockRange(this, oldRange, newRange);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddressRange getRange() {
|
||||
try (LockHold hold = object.getTrace().lockRead()) {
|
||||
return TraceObjectInterfaceUtils.getValue(object, getCreationSnap(),
|
||||
TargetMemoryRegion.RANGE_ATTRIBUTE_NAME, AddressRange.class, null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMinAddress(Address min) {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
setRange(DBTraceUtils.toRange(min, getMaxAddress()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address getMinAddress() {
|
||||
AddressRange range = getRange();
|
||||
return range == null ? null : range.getMinAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxAddress(Address max) {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
setRange(DBTraceUtils.toRange(getMinAddress(), max));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address getMaxAddress() {
|
||||
AddressRange range = getRange();
|
||||
return range == null ? null : range.getMaxAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLength(long length) throws AddressOverflowException {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
setRange(new AddressRangeImpl(getMinAddress(), length));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLength() {
|
||||
return getRange().getLength();
|
||||
}
|
||||
|
||||
protected static String keyForFlag(TraceMemoryFlag flag) {
|
||||
switch (flag) {
|
||||
case READ:
|
||||
return TargetMemoryRegion.READABLE_ATTRIBUTE_NAME;
|
||||
case WRITE:
|
||||
return TargetMemoryRegion.WRITABLE_ATTRIBUTE_NAME;
|
||||
case EXECUTE:
|
||||
return TargetMemoryRegion.EXECUTABLE_ATTRIBUTE_NAME;
|
||||
case VOLATILE:
|
||||
return KEY_VOLATILE;
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFlags(Range<Long> lifespan, Collection<TraceMemoryFlag> flags) {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
for (TraceMemoryFlag flag : TraceMemoryFlag.values()) {
|
||||
Boolean val = flags.contains(flag) ? true : null;
|
||||
object.setValue(lifespan, keyForFlag(flag), val);
|
||||
}
|
||||
object.getTrace().updateViewsChangeRegionBlockFlags(this, lifespan);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addFlags(Range<Long> lifespan, Collection<TraceMemoryFlag> flags) {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
for (TraceMemoryFlag flag : flags) {
|
||||
object.setValue(lifespan, keyForFlag(flag), true);
|
||||
}
|
||||
object.getTrace().updateViewsChangeRegionBlockFlags(this, lifespan);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearFlags(Range<Long> lifespan, Collection<TraceMemoryFlag> flags) {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
for (TraceMemoryFlag flag : flags) {
|
||||
object.setValue(lifespan, keyForFlag(flag), null);
|
||||
}
|
||||
object.getTrace().updateViewsChangeRegionBlockFlags(this, lifespan);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFlags(Collection<TraceMemoryFlag> flags) {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
setFlags(getLifespan(), flags);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addFlags(Collection<TraceMemoryFlag> flags) {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
addFlags(getLifespan(), flags);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearFlags(Collection<TraceMemoryFlag> flags) {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
clearFlags(getLifespan(), flags);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<TraceMemoryFlag> getFlags(long snap) {
|
||||
EnumSet<TraceMemoryFlag> result = EnumSet.noneOf(TraceMemoryFlag.class);
|
||||
for (TraceMemoryFlag flag : TraceMemoryFlag.values()) {
|
||||
if (object.getValue(snap, keyForFlag(flag)) != null) {
|
||||
result.add(flag);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<TraceMemoryFlag> getFlags() {
|
||||
try (LockHold hold = object.getTrace().lockRead()) {
|
||||
return getFlags(getCreationSnap());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
object.deleteTree();
|
||||
object.getTrace().updateViewsDeleteRegionBlock(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceObject getObject() {
|
||||
return object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceChangeRecord<?, ?> translateEvent(TraceChangeRecord<?, ?> rec) {
|
||||
return translator.translate(rec);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
/* ###
|
||||
* 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.trace.database.memory;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import com.google.common.collect.Range;
|
||||
|
||||
import ghidra.dbg.target.TargetRegister;
|
||||
import ghidra.dbg.util.PathUtils;
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.trace.database.target.DBTraceObject;
|
||||
import ghidra.trace.model.memory.TraceMemoryState;
|
||||
import ghidra.trace.model.memory.TraceObjectRegister;
|
||||
import ghidra.trace.model.target.*;
|
||||
import ghidra.trace.model.target.annot.TraceObjectInterfaceUtils;
|
||||
import ghidra.trace.model.thread.TraceObjectThread;
|
||||
|
||||
public class DBTraceObjectRegister implements TraceObjectRegister {
|
||||
private final DBTraceObject object;
|
||||
|
||||
public DBTraceObjectRegister(DBTraceObject object) {
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceObject getObject() {
|
||||
return object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceObjectThread getThread() {
|
||||
return object.queryAncestorsInterface(object.getLifespan(), TraceObjectThread.class)
|
||||
.findAny()
|
||||
.orElseThrow();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
TraceObjectKeyPath path = object.getCanonicalPath();
|
||||
if (PathUtils.isIndex(path.key())) {
|
||||
return path.index();
|
||||
}
|
||||
return path.key();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return TraceObjectInterfaceUtils.getValue(object, object.getMinSnap(),
|
||||
TargetRegister.LENGTH_ATTRIBUTE_NAME, Integer.class, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(Range<Long> lifespan, byte[] value) {
|
||||
int length = getLength();
|
||||
if (length != 0 && value.length != length) {
|
||||
throw new IllegalArgumentException("Length must match the register");
|
||||
}
|
||||
object.setValue(lifespan, TargetRegister.VALUE_ATTRIBUTE_NAME, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getValue(long snap) {
|
||||
TraceObjectValue ov = object.getValue(snap, TargetRegister.VALUE_ATTRIBUTE_NAME);
|
||||
if (ov == null) {
|
||||
return null;
|
||||
}
|
||||
Object val = ov.getValue();
|
||||
if (val instanceof byte[]) {
|
||||
// TODO: Should I correct mismatched size?
|
||||
return (byte[]) val;
|
||||
}
|
||||
if (val instanceof String) {
|
||||
// Always base 16. Model API says byte array for register value is big endian.
|
||||
BigInteger bigVal = new BigInteger((String) val, 16);
|
||||
return Utils.bigIntegerToBytes(bigVal, getLength(), true);
|
||||
}
|
||||
throw new ClassCastException("Cannot convert " + val + " to byte array for register value");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setState(Range<Long> lifespan, TraceMemoryState state) {
|
||||
// NB. There's no model equivalent, so encode using ordinal
|
||||
object.setValue(lifespan, KEY_STATE, state.ordinal());
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceMemoryState getState(long snap) {
|
||||
return TraceMemoryState.values()[TraceObjectInterfaceUtils.getValue(object, snap, KEY_STATE,
|
||||
Integer.class, TraceMemoryState.UNKNOWN.ordinal())];
|
||||
}
|
||||
}
|
|
@ -23,16 +23,16 @@ import java.util.concurrent.locks.ReadWriteLock;
|
|||
import com.google.common.collect.Range;
|
||||
|
||||
import db.DBHandle;
|
||||
import ghidra.dbg.target.TargetModule;
|
||||
import ghidra.dbg.target.TargetSection;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.trace.database.DBTrace;
|
||||
import ghidra.trace.database.DBTraceUtils;
|
||||
import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager;
|
||||
import ghidra.trace.database.space.DBTraceDelegatingManager;
|
||||
import ghidra.trace.database.thread.DBTraceThread;
|
||||
import ghidra.trace.model.Trace.TraceModuleChangeType;
|
||||
import ghidra.trace.model.modules.TraceModuleManager;
|
||||
import ghidra.trace.model.modules.TraceSection;
|
||||
import ghidra.trace.model.modules.*;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.trace.util.TraceChangeRecord;
|
||||
import ghidra.util.LockHold;
|
||||
|
@ -64,9 +64,9 @@ public class DBTraceModuleManager
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
protected void checkModulePathConflicts(DBTraceModule ignore, String modulePath,
|
||||
protected void checkModulePathConflicts(TraceModule ignore, String modulePath,
|
||||
Range<Long> moduleLifespan) throws DuplicateNameException {
|
||||
for (DBTraceModule pc : doGetModulesByPath(modulePath)) {
|
||||
for (TraceModule pc : doGetModulesByPath(modulePath)) {
|
||||
if (pc == ignore) {
|
||||
continue;
|
||||
}
|
||||
|
@ -80,12 +80,17 @@ public class DBTraceModuleManager
|
|||
|
||||
protected void checkSectionPathConflicts(DBTraceSection ignore, String sectionPath,
|
||||
Range<Long> moduleLifespan) throws DuplicateNameException {
|
||||
Collection<? extends DBTraceSection> pathConflicts = doGetSectionsByPath(sectionPath);
|
||||
for (DBTraceSection pc : pathConflicts) {
|
||||
Collection<? extends TraceSection> pathConflicts = doGetSectionsByPath(sectionPath);
|
||||
for (TraceSection pc : pathConflicts) {
|
||||
if (pc == ignore) {
|
||||
continue;
|
||||
}
|
||||
if (!DBTraceUtils.intersect(pc.getLifespan(), moduleLifespan)) {
|
||||
/**
|
||||
* TODO: Certainly, any two sections at the same path will belong to the same module and
|
||||
* so have the same lifespan, no? I suppose this logic is only true in objects mode...,
|
||||
* and there, the logic is performed by the value key duplicate check.
|
||||
*/
|
||||
if (!DBTraceUtils.intersect(pc.getModule().getLifespan(), moduleLifespan)) {
|
||||
continue;
|
||||
}
|
||||
throw new DuplicateNameException("Section with path '" + sectionPath +
|
||||
|
@ -94,31 +99,41 @@ public class DBTraceModuleManager
|
|||
}
|
||||
|
||||
@Override
|
||||
public DBTraceModule addModule(String modulePath, String moduleName, AddressRange range,
|
||||
public TraceModule addModule(String modulePath, String moduleName, AddressRange range,
|
||||
Range<Long> lifespan) throws DuplicateNameException {
|
||||
try (LockHold hold = LockHold.lock(lock.writeLock())) {
|
||||
return doAddModule(modulePath, moduleName, range, lifespan);
|
||||
}
|
||||
}
|
||||
|
||||
protected DBTraceModule doAddModule(String modulePath, String moduleName, AddressRange range,
|
||||
protected TraceModule doAddModule(String modulePath, String moduleName, AddressRange range,
|
||||
Range<Long> lifespan) throws DuplicateNameException {
|
||||
if (trace.getObjectManager().hasSchema()) {
|
||||
return trace.getObjectManager().addModule(modulePath, moduleName, lifespan, range);
|
||||
}
|
||||
checkModulePathConflicts(null, modulePath, lifespan);
|
||||
return delegateWrite(range.getAddressSpace(),
|
||||
m -> m.doAddModule(modulePath, moduleName, range, lifespan));
|
||||
}
|
||||
|
||||
protected Collection<? extends DBTraceModule> doGetModulesByPath(String modulePath) {
|
||||
protected Collection<? extends TraceModule> doGetModulesByPath(String modulePath) {
|
||||
if (trace.getObjectManager().hasSchema()) {
|
||||
return trace.getObjectManager().getObjectsByPath(modulePath, TraceObjectModule.class);
|
||||
}
|
||||
return delegateCollection(memSpaces.values(), m -> m.doGetModulesByPath(modulePath));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends DBTraceModule> getModulesByPath(String modulePath) {
|
||||
public Collection<? extends TraceModule> getModulesByPath(String modulePath) {
|
||||
return Collections.unmodifiableCollection(doGetModulesByPath(modulePath));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DBTraceModule getLoadedModuleByPath(long snap, String modulePath) {
|
||||
public TraceModule getLoadedModuleByPath(long snap, String modulePath) {
|
||||
if (trace.getObjectManager().hasSchema()) {
|
||||
return trace.getObjectManager()
|
||||
.getObjectByPath(snap, modulePath, TraceObjectModule.class);
|
||||
}
|
||||
try (LockHold hold = LockHold.lock(lock.readLock())) {
|
||||
return doGetModulesByPath(modulePath)
|
||||
.stream()
|
||||
|
@ -129,24 +144,40 @@ public class DBTraceModuleManager
|
|||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends DBTraceModule> getAllModules() {
|
||||
public Collection<? extends TraceModule> getAllModules() {
|
||||
if (trace.getObjectManager().hasSchema()) {
|
||||
return trace.getObjectManager().getAllObjects(TraceObjectModule.class);
|
||||
}
|
||||
return delegateCollection(memSpaces.values(), m -> m.getAllModules());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends DBTraceModule> getLoadedModules(long snap) {
|
||||
public Collection<? extends TraceModule> getLoadedModules(long snap) {
|
||||
if (trace.getObjectManager().hasSchema()) {
|
||||
return trace.getObjectManager().getObjectsAtSnap(snap, TraceObjectModule.class);
|
||||
}
|
||||
return delegateCollection(memSpaces.values(), m -> m.getLoadedModules(snap));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends DBTraceModule> getModulesAt(long snap, Address address) {
|
||||
public Collection<? extends TraceModule> getModulesAt(long snap, Address address) {
|
||||
if (trace.getObjectManager().hasSchema()) {
|
||||
return trace.getObjectManager()
|
||||
.getObjectsContaining(snap, address, TargetModule.RANGE_ATTRIBUTE_NAME,
|
||||
TraceObjectModule.class);
|
||||
}
|
||||
return delegateRead(address.getAddressSpace(),
|
||||
m -> m.getModulesAt(snap, address), Set.of());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends DBTraceModule> getModulesIntersecting(Range<Long> lifespan,
|
||||
public Collection<? extends TraceModule> getModulesIntersecting(Range<Long> lifespan,
|
||||
AddressRange range) {
|
||||
if (trace.getObjectManager().hasSchema()) {
|
||||
return trace.getObjectManager()
|
||||
.getObjectsIntersecting(lifespan, range, TargetModule.RANGE_ATTRIBUTE_NAME,
|
||||
TraceObjectModule.class);
|
||||
}
|
||||
return delegateRead(range.getAddressSpace(),
|
||||
m -> m.getModulesIntersecting(lifespan, range), Set.of());
|
||||
}
|
||||
|
@ -157,14 +188,24 @@ public class DBTraceModuleManager
|
|||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends DBTraceSection> getSectionsAt(long snap, Address address) {
|
||||
public Collection<? extends TraceSection> getSectionsAt(long snap, Address address) {
|
||||
if (trace.getObjectManager().hasSchema()) {
|
||||
return trace.getObjectManager()
|
||||
.getObjectsContaining(snap, address, TargetSection.RANGE_ATTRIBUTE_NAME,
|
||||
TraceObjectSection.class);
|
||||
}
|
||||
return delegateRead(address.getAddressSpace(),
|
||||
m -> m.getSectionsAt(snap, address), Set.of());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends DBTraceSection> getSectionsIntersecting(Range<Long> lifespan,
|
||||
public Collection<? extends TraceSection> getSectionsIntersecting(Range<Long> lifespan,
|
||||
AddressRange range) {
|
||||
if (trace.getObjectManager().hasSchema()) {
|
||||
return trace.getObjectManager()
|
||||
.getObjectsIntersecting(lifespan, range, TargetSection.RANGE_ATTRIBUTE_NAME,
|
||||
TraceObjectSection.class);
|
||||
}
|
||||
return delegateRead(range.getAddressSpace(),
|
||||
m -> m.getSectionsIntersecting(lifespan, range), Set.of());
|
||||
}
|
||||
|
@ -186,7 +227,7 @@ public class DBTraceModuleManager
|
|||
}
|
||||
|
||||
@Override
|
||||
protected DBTraceModuleSpace createRegisterSpace(AddressSpace space, DBTraceThread thread,
|
||||
protected DBTraceModuleSpace createRegisterSpace(AddressSpace space, TraceThread thread,
|
||||
DBTraceSpaceEntry ent) throws VersionException, IOException {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
@ -204,7 +245,10 @@ public class DBTraceModuleManager
|
|||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends DBTraceSection> getAllSections() {
|
||||
public Collection<? extends TraceSection> getAllSections() {
|
||||
if (trace.getObjectManager().hasSchema()) {
|
||||
return trace.getObjectManager().getAllObjects(TraceObjectSection.class);
|
||||
}
|
||||
return delegateCollection(memSpaces.values(), m -> m.getAllSections());
|
||||
}
|
||||
|
||||
|
@ -212,12 +256,15 @@ public class DBTraceModuleManager
|
|||
return delegateCollection(memSpaces.values(), m -> m.doGetSectionsByModuleId(key));
|
||||
}
|
||||
|
||||
protected Collection<? extends DBTraceSection> doGetSectionsByPath(String sectionPath) {
|
||||
protected Collection<? extends TraceSection> doGetSectionsByPath(String sectionPath) {
|
||||
if (trace.getObjectManager().hasSchema()) {
|
||||
return trace.getObjectManager().getObjectsByPath(sectionPath, TraceObjectSection.class);
|
||||
}
|
||||
return delegateCollection(memSpaces.values(), m -> m.doGetSectionsByPath(sectionPath));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends DBTraceSection> getSectionsByPath(String sectionPath) {
|
||||
public Collection<? extends TraceSection> getSectionsByPath(String sectionPath) {
|
||||
try (LockHold hold = LockHold.lock(lock.readLock())) {
|
||||
return Collections.unmodifiableCollection(doGetSectionsByPath(sectionPath));
|
||||
}
|
||||
|
@ -225,10 +272,14 @@ public class DBTraceModuleManager
|
|||
|
||||
@Override
|
||||
public TraceSection getLoadedSectionByPath(long snap, String sectionPath) {
|
||||
if (trace.getObjectManager().hasSchema()) {
|
||||
return trace.getObjectManager()
|
||||
.getObjectByPath(snap, sectionPath, TraceObjectSection.class);
|
||||
}
|
||||
try (LockHold hold = LockHold.lock(lock.readLock())) {
|
||||
return doGetSectionsByPath(sectionPath)
|
||||
.stream()
|
||||
.filter(s -> s.getLifespan().contains(snap))
|
||||
.filter(s -> s.getModule().getLifespan().contains(snap))
|
||||
.findAny()
|
||||
.orElse(null);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,242 @@
|
|||
/* ###
|
||||
* 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.trace.database.module;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.google.common.collect.Range;
|
||||
|
||||
import ghidra.dbg.target.*;
|
||||
import ghidra.dbg.util.PathMatcher;
|
||||
import ghidra.dbg.util.PathUtils;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.trace.database.DBTraceUtils;
|
||||
import ghidra.trace.database.target.*;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.Trace.TraceModuleChangeType;
|
||||
import ghidra.trace.model.modules.*;
|
||||
import ghidra.trace.model.target.TraceObject;
|
||||
import ghidra.trace.model.target.annot.TraceObjectInterfaceUtils;
|
||||
import ghidra.trace.util.TraceChangeRecord;
|
||||
import ghidra.trace.util.TraceChangeType;
|
||||
import ghidra.util.LockHold;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
public class DBTraceObjectModule implements TraceObjectModule, DBTraceObjectInterface {
|
||||
|
||||
protected class ModuleChangeTranslator extends Translator<TraceModule> {
|
||||
protected ModuleChangeTranslator(DBTraceObject object, TraceModule iface) {
|
||||
super(TargetModule.RANGE_ATTRIBUTE_NAME, object, iface);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TraceChangeType<TraceModule, Void> getAddedType() {
|
||||
return TraceModuleChangeType.ADDED;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TraceChangeType<TraceModule, Range<Long>> getLifespanChangedType() {
|
||||
return TraceModuleChangeType.LIFESPAN_CHANGED;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TraceChangeType<TraceModule, Void> getChangedType() {
|
||||
return TraceModuleChangeType.CHANGED;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean appliesToKey(String key) {
|
||||
return TargetModule.RANGE_ATTRIBUTE_NAME.equals(key) ||
|
||||
TargetObject.DISPLAY_ATTRIBUTE_NAME.equals(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TraceChangeType<TraceModule, Void> getDeletedType() {
|
||||
return TraceModuleChangeType.DELETED;
|
||||
}
|
||||
}
|
||||
|
||||
private final DBTraceObject object;
|
||||
private final ModuleChangeTranslator translator;
|
||||
|
||||
public DBTraceObjectModule(DBTraceObject object) {
|
||||
this.object = object;
|
||||
|
||||
translator = new ModuleChangeTranslator(object, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Trace getTrace() {
|
||||
return object.getTrace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceSection addSection(String sectionPath, String sectionName, AddressRange range)
|
||||
throws DuplicateNameException {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
DBTraceObjectManager manager = object.getManager();
|
||||
List<String> sectionKeyList = PathUtils.parse(sectionPath);
|
||||
if (!PathUtils.isAncestor(object.getCanonicalPath().getKeyList(), sectionKeyList)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Section path must be a successor of this module's path");
|
||||
}
|
||||
return manager.addSection(sectionPath, sectionName, getLifespan(), range);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
return object.getCanonicalPath().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(String name) {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
object.setValue(getLifespan(), TargetObject.DISPLAY_ATTRIBUTE_NAME, name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return TraceObjectInterfaceUtils.getValue(object, getLoadedSnap(),
|
||||
TargetObject.DISPLAY_ATTRIBUTE_NAME, String.class, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRange(AddressRange range) {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
object.setValue(getLifespan(), TargetModule.RANGE_ATTRIBUTE_NAME, range);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddressRange getRange() {
|
||||
return TraceObjectInterfaceUtils.getValue(object, getLoadedSnap(),
|
||||
TargetModule.RANGE_ATTRIBUTE_NAME, AddressRange.class, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBase(Address base) {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
setRange(DBTraceUtils.toRange(base, getMaxAddress()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address getBase() {
|
||||
AddressRange range = getRange();
|
||||
return range == null ? null : range.getMinAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxAddress(Address max) {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
setRange(DBTraceUtils.toRange(getBase(), max));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address getMaxAddress() {
|
||||
AddressRange range = getRange();
|
||||
return range == null ? null : range.getMaxAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLength(long length) throws AddressOverflowException {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
setRange(new AddressRangeImpl(getBase(), length));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLength() {
|
||||
return getRange().getLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLifespan(Range<Long> lifespan) throws DuplicateNameException {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
TraceObjectInterfaceUtils.setLifespan(TraceObjectModule.class, object, lifespan);
|
||||
for (TraceObjectSection section : getSections()) {
|
||||
section.getObject().setLifespan(lifespan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Range<Long> getLifespan() {
|
||||
return object.getLifespan();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLoadedSnap(long loadedSnap) throws DuplicateNameException {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
setLifespan(DBTraceUtils.toRange(loadedSnap, getUnloadedSnap()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLoadedSnap() {
|
||||
return object.getMinSnap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUnloadedSnap(long unloadedSnap) throws DuplicateNameException {
|
||||
try (LockHold hold = object.getTrace().lockWrite()) {
|
||||
setLifespan(DBTraceUtils.toRange(getLoadedSnap(), unloadedSnap));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getUnloadedSnap() {
|
||||
return object.getMaxSnap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends TraceObjectSection> getSections() {
|
||||
try (LockHold hold = object.getTrace().lockRead()) {
|
||||
return object.querySuccessorsInterface(getLifespan(), TraceObjectSection.class)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceObjectSection getSectionByName(String sectionName) {
|
||||
PathMatcher matcher = object.getTargetSchema().searchFor(TargetSection.class, true);
|
||||
PathMatcher applied = matcher.applyKeys(List.of(sectionName));
|
||||
return object.getSuccessors(getLifespan(), applied)
|
||||
.map(p -> p.getLastChild(object).queryInterface(TraceObjectSection.class))
|
||||
.findAny()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() {
|
||||
object.deleteTree();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceObject getObject() {
|
||||
return object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceChangeRecord<?, ?> translateEvent(TraceChangeRecord<?, ?> rec) {
|
||||
return translator.translate(rec);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
/* ###
|
||||
* 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.trace.database.module;
|
||||
|
||||
import com.google.common.collect.Range;
|
||||
|
||||
import ghidra.dbg.target.*;
|
||||
import ghidra.program.model.address.AddressRange;
|
||||
import ghidra.trace.database.target.DBTraceObject;
|
||||
import ghidra.trace.database.target.DBTraceObjectInterface;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.Trace.TraceSectionChangeType;
|
||||
import ghidra.trace.model.modules.*;
|
||||
import ghidra.trace.model.target.TraceObject;
|
||||
import ghidra.trace.model.target.annot.TraceObjectInterfaceUtils;
|
||||
import ghidra.trace.util.TraceChangeRecord;
|
||||
import ghidra.trace.util.TraceChangeType;
|
||||
import ghidra.util.LockHold;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
public class DBTraceObjectSection implements TraceObjectSection, DBTraceObjectInterface {
|
||||
|
||||
protected class SectionTranslator extends Translator<TraceSection> {
|
||||
protected SectionTranslator(DBTraceObject object, TraceSection iface) {
|
||||
super(TargetSection.RANGE_ATTRIBUTE_NAME, object, iface);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TraceChangeType<TraceSection, Void> getAddedType() {
|
||||
return TraceSectionChangeType.ADDED;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TraceChangeType<TraceSection, Range<Long>> getLifespanChangedType() {
|
||||
return null; // it's the module's lifespan that matters.
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TraceChangeType<TraceSection, Void> getChangedType() {
|
||||
return TraceSectionChangeType.CHANGED;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean appliesToKey(String key) {
|
||||
return TargetSection.RANGE_ATTRIBUTE_NAME.equals(key) ||
|
||||
TargetObject.DISPLAY_ATTRIBUTE_NAME.equals(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TraceChangeType<TraceSection, Void> getDeletedType() {
|
||||
return TraceSectionChangeType.DELETED;
|
||||
}
|
||||
}
|
||||
|
||||
private final DBTraceObject object;
|
||||
private final SectionTranslator translator;
|
||||
|
||||
public DBTraceObjectSection(DBTraceObject object) {
|
||||
this.object = object;
|
||||
|
||||
translator = new SectionTranslator(object, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Trace getTrace() {
|
||||
return object.getTrace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceModule getModule() {
|
||||
try (LockHold hold = object.getTrace().lockRead()) {
|
||||
return object.queryAncestorsInterface(object.getLifespan(), TraceObjectModule.class)
|
||||
.findAny()
|
||||
.orElseThrow();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
return object.getCanonicalPath().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(String name) throws DuplicateNameException {
|
||||
object.setValue(object.getLifespan(), TargetObject.DISPLAY_ATTRIBUTE_NAME, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return TraceObjectInterfaceUtils.getValue(object, object.getMinSnap(),
|
||||
TargetObject.DISPLAY_ATTRIBUTE_NAME, String.class, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRange(AddressRange range) {
|
||||
object.setValue(object.getLifespan(), TargetModule.RANGE_ATTRIBUTE_NAME, range);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddressRange getRange() {
|
||||
return TraceObjectInterfaceUtils.getValue(object, object.getMinSnap(),
|
||||
TargetModule.RANGE_ATTRIBUTE_NAME, AddressRange.class, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() {
|
||||
object.deleteTree();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceObject getObject() {
|
||||
return object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceChangeRecord<?, ?> translateEvent(TraceChangeRecord<?, ?> rec) {
|
||||
return translator.translate(rec);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/* ###
|
||||
* 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.trace.database.module;
|
||||
|
||||
import ghidra.dbg.target.TargetObject;
|
||||
import ghidra.dbg.target.TargetSection;
|
||||
import ghidra.program.model.address.AddressRange;
|
||||
import ghidra.trace.model.modules.TraceSection;
|
||||
import ghidra.trace.model.target.TraceObjectInterface;
|
||||
import ghidra.trace.model.target.annot.TraceObjectInfo;
|
||||
|
||||
@TraceObjectInfo(
|
||||
targetIf = TargetSection.class,
|
||||
shortName = "section",
|
||||
fixedKeys = {
|
||||
TargetObject.DISPLAY_ATTRIBUTE_NAME,
|
||||
TargetSection.RANGE_ATTRIBUTE_NAME
|
||||
})
|
||||
public interface TraceObjectSection extends TraceSection, TraceObjectInterface {
|
||||
void setRange(AddressRange range);
|
||||
}
|
|
@ -38,13 +38,13 @@ import ghidra.program.model.util.CodeUnitInsertionException;
|
|||
import ghidra.program.model.util.PropertyMap;
|
||||
import ghidra.trace.database.DBTrace;
|
||||
import ghidra.trace.database.listing.UndefinedDBTraceData;
|
||||
import ghidra.trace.database.memory.DBTraceMemoryRegion;
|
||||
import ghidra.trace.database.memory.DBTraceMemorySpace;
|
||||
import ghidra.trace.database.symbol.DBTraceFunctionSymbol;
|
||||
import ghidra.trace.database.thread.DBTraceThread;
|
||||
import ghidra.trace.model.*;
|
||||
import ghidra.trace.model.listing.*;
|
||||
import ghidra.trace.model.map.TracePropertyMap;
|
||||
import ghidra.trace.model.memory.TraceMemoryRegion;
|
||||
import ghidra.trace.model.program.TraceProgramView;
|
||||
import ghidra.trace.model.program.TraceProgramViewListing;
|
||||
import ghidra.trace.model.symbol.TraceFunctionSymbol;
|
||||
|
@ -79,7 +79,7 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV
|
|||
protected final TraceCodeOperations codeOperations;
|
||||
|
||||
protected final DBTraceProgramViewRootModule rootModule;
|
||||
protected final Map<DBTraceMemoryRegion, DBTraceProgramViewFragment> fragmentsByRegion =
|
||||
protected final Map<TraceMemoryRegion, DBTraceProgramViewFragment> fragmentsByRegion =
|
||||
new HashMap<>();
|
||||
|
||||
protected final Map<AddressSnap, UndefinedDBTraceData> undefinedCache =
|
||||
|
@ -779,7 +779,7 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV
|
|||
|
||||
@Override
|
||||
public ProgramFragment getFragment(String treeName, Address addr) {
|
||||
DBTraceMemoryRegion region = program.memory.getTopRegion(
|
||||
TraceMemoryRegion region = program.memory.getTopRegion(
|
||||
s -> program.trace.getMemoryManager().getRegionContaining(s, addr));
|
||||
if (region == null) {
|
||||
return null;
|
||||
|
@ -798,7 +798,7 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV
|
|||
|
||||
@Override
|
||||
public ProgramFragment getFragment(String treeName, String name) {
|
||||
DBTraceMemoryRegion region = program.memory.getTopRegion(
|
||||
TraceMemoryRegion region = program.memory.getTopRegion(
|
||||
s -> program.trace.getMemoryManager().getLiveRegionByPath(s, name));
|
||||
if (region == null) {
|
||||
return null;
|
||||
|
|
|
@ -29,6 +29,7 @@ import ghidra.program.model.address.*;
|
|||
import ghidra.program.model.mem.*;
|
||||
import ghidra.trace.database.memory.*;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.memory.TraceMemoryRegion;
|
||||
import ghidra.trace.model.program.TraceProgramView;
|
||||
import ghidra.trace.model.program.TraceProgramViewMemory;
|
||||
import ghidra.trace.util.MemoryAdapter;
|
||||
|
@ -53,7 +54,7 @@ public abstract class AbstractDBTraceProgramViewMemory
|
|||
}
|
||||
|
||||
protected void regionBlockRemoved(
|
||||
RemovalNotification<DBTraceMemoryRegion, DBTraceProgramViewMemoryRegionBlock> rn) {
|
||||
RemovalNotification<TraceMemoryRegion, DBTraceProgramViewMemoryRegionBlock> rn) {
|
||||
// Nothing
|
||||
}
|
||||
|
||||
|
@ -138,7 +139,7 @@ public abstract class AbstractDBTraceProgramViewMemory
|
|||
@Override
|
||||
public AddressSetView getExecuteSet() {
|
||||
AddressSet result = new AddressSet();
|
||||
for (DBTraceMemoryRegion region : memoryManager.getRegionsInternal()) {
|
||||
for (TraceMemoryRegion region : memoryManager.getAllRegions()) {
|
||||
if (!region.isExecute() || !program.isRegionVisible(region, region.getLifespan())) {
|
||||
continue;
|
||||
}
|
||||
|
@ -520,8 +521,12 @@ public abstract class AbstractDBTraceProgramViewMemory
|
|||
protected synchronized void changeRange(AddressRange remove, AddressRange add) {
|
||||
if (!forceFullView) {
|
||||
AddressSet temp = new AddressSet(addressSet);
|
||||
temp.delete(remove);
|
||||
temp.add(add);
|
||||
if (remove != null) {
|
||||
temp.delete(remove);
|
||||
}
|
||||
if (add != null) {
|
||||
temp.add(add);
|
||||
}
|
||||
addressSet = temp;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1562,37 +1562,36 @@ public class DBTraceProgramView implements TraceProgramView {
|
|||
trace.removeTransactionListener(listener);
|
||||
}
|
||||
|
||||
public void updateMemoryAddRegionBlock(DBTraceMemoryRegion region) {
|
||||
public void updateMemoryAddRegionBlock(TraceMemoryRegion region) {
|
||||
if (!isRegionVisible(region)) {
|
||||
return;
|
||||
}
|
||||
memory.updateAddRegionBlock(region);
|
||||
}
|
||||
|
||||
public void updateMemoryChangeRegionBlockName(DBTraceMemoryRegion region) {
|
||||
public void updateMemoryChangeRegionBlockName(TraceMemoryRegion region) {
|
||||
if (!isRegionVisible(region)) {
|
||||
return;
|
||||
}
|
||||
memory.updateChangeRegionBlockName(region);
|
||||
}
|
||||
|
||||
public void updateMemoryChangeRegionBlockFlags(DBTraceMemoryRegion region) {
|
||||
if (!isRegionVisible(region)) {
|
||||
public void updateMemoryChangeRegionBlockFlags(TraceMemoryRegion region, Range<Long> lifespan) {
|
||||
if (!isRegionVisible(region, lifespan)) {
|
||||
return;
|
||||
}
|
||||
memory.updateChangeRegionBlockFlags(region);
|
||||
}
|
||||
|
||||
public void updateMemoryChangeRegionBlockRange(DBTraceMemoryRegion region,
|
||||
AddressRange oldRange,
|
||||
AddressRange newRange) {
|
||||
public void updateMemoryChangeRegionBlockRange(TraceMemoryRegion region,
|
||||
AddressRange oldRange, AddressRange newRange) {
|
||||
if (!isRegionVisible(region)) {
|
||||
return;
|
||||
}
|
||||
memory.updateChangeRegionBlockRange(region, oldRange, newRange);
|
||||
}
|
||||
|
||||
public void updateMemoryChangeRegionBlockLifespan(DBTraceMemoryRegion region,
|
||||
public void updateMemoryChangeRegionBlockLifespan(TraceMemoryRegion region,
|
||||
Range<Long> oldLifespan, Range<Long> newLifespan) {
|
||||
boolean inOld = isRegionVisible(region, oldLifespan);
|
||||
boolean inNew = isRegionVisible(region, newLifespan);
|
||||
|
@ -1604,7 +1603,7 @@ public class DBTraceProgramView implements TraceProgramView {
|
|||
}
|
||||
}
|
||||
|
||||
public void updateMemoryDeleteRegionBlock(DBTraceMemoryRegion region) {
|
||||
public void updateMemoryDeleteRegionBlock(TraceMemoryRegion region) {
|
||||
if (!isRegionVisible(region)) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -19,24 +19,24 @@ import java.util.Iterator;
|
|||
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.trace.database.memory.DBTraceMemoryRegion;
|
||||
import ghidra.trace.model.memory.TraceMemoryRegion;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.exception.NotFoundException;
|
||||
|
||||
// TODO: Destroy this in favor of databased trees?
|
||||
public class DBTraceProgramViewFragment implements ProgramFragment {
|
||||
protected final AbstractDBTraceProgramViewListing listing;
|
||||
protected final DBTraceMemoryRegion region;
|
||||
protected final TraceMemoryRegion region;
|
||||
|
||||
public DBTraceProgramViewFragment(AbstractDBTraceProgramViewListing listing,
|
||||
DBTraceMemoryRegion region) {
|
||||
TraceMemoryRegion region) {
|
||||
this.listing = listing;
|
||||
this.region = region;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getComment() {
|
||||
return region.description();
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -76,22 +76,27 @@ public class DBTraceProgramViewFragment implements ProgramFragment {
|
|||
|
||||
@Override
|
||||
public boolean contains(Address addr) {
|
||||
return region.contains(addr, listing.program.snap);
|
||||
return region.getRange().contains(addr) &&
|
||||
region.getLifespan().contains(listing.program.snap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Address start, Address end) {
|
||||
// Regions are contiguous
|
||||
long snap = listing.program.snap;
|
||||
return region.contains(start, snap) && region.contains(end, snap);
|
||||
AddressRange range = region.getRange();
|
||||
return range.contains(start) && range.contains(end) &&
|
||||
region.getLifespan().contains(listing.program.snap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(AddressSetView rangeSet) {
|
||||
long snap = listing.program.snap;
|
||||
if (!region.getLifespan().contains(listing.program.snap)) {
|
||||
return false;
|
||||
}
|
||||
for (AddressRange range : rangeSet) {
|
||||
if (!region.contains(range.getMinAddress(), snap) ||
|
||||
!region.contains(range.getMaxAddress(), snap)) {
|
||||
AddressRange regionRange = region.getRange();
|
||||
if (!regionRange.contains(range.getMinAddress()) ||
|
||||
!regionRange.contains(range.getMaxAddress())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,12 +23,12 @@ import com.google.common.cache.CacheBuilder;
|
|||
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.mem.MemoryBlock;
|
||||
import ghidra.trace.database.memory.DBTraceMemoryRegion;
|
||||
import ghidra.trace.model.memory.TraceMemoryRegion;
|
||||
|
||||
public class DBTraceProgramViewMemory extends AbstractDBTraceProgramViewMemory {
|
||||
|
||||
// NB. Keep both per-region and force-full (per-space) block sets ready
|
||||
private final Map<DBTraceMemoryRegion, DBTraceProgramViewMemoryRegionBlock> regionBlocks =
|
||||
private final Map<TraceMemoryRegion, DBTraceProgramViewMemoryRegionBlock> regionBlocks =
|
||||
CacheBuilder.newBuilder()
|
||||
.removalListener(this::regionBlockRemoved)
|
||||
.weakValues()
|
||||
|
@ -45,10 +45,10 @@ public class DBTraceProgramViewMemory extends AbstractDBTraceProgramViewMemory {
|
|||
super(program);
|
||||
}
|
||||
|
||||
protected DBTraceMemoryRegion getTopRegion(Function<Long, DBTraceMemoryRegion> regFunc) {
|
||||
protected TraceMemoryRegion getTopRegion(Function<Long, TraceMemoryRegion> regFunc) {
|
||||
return program.viewport.getTop(s -> {
|
||||
// TODO: There is probably an early-bail condition I can check for.
|
||||
DBTraceMemoryRegion reg = regFunc.apply(s);
|
||||
TraceMemoryRegion reg = regFunc.apply(s);
|
||||
if (reg != null && program.isRegionVisible(reg)) {
|
||||
return reg;
|
||||
}
|
||||
|
@ -56,10 +56,10 @@ public class DBTraceProgramViewMemory extends AbstractDBTraceProgramViewMemory {
|
|||
});
|
||||
}
|
||||
|
||||
protected void forVisibleRegions(Consumer<? super DBTraceMemoryRegion> action) {
|
||||
protected void forVisibleRegions(Consumer<? super TraceMemoryRegion> action) {
|
||||
for (long s : program.viewport.getOrderedSnaps()) {
|
||||
// NOTE: This is slightly faster than new AddressSet(mm.getRegionsAddressSet(snap))
|
||||
for (DBTraceMemoryRegion reg : memoryManager.getRegionsAtSnap(s)) {
|
||||
for (TraceMemoryRegion reg : memoryManager.getRegionsAtSnap(s)) {
|
||||
if (program.isRegionVisible(reg)) {
|
||||
action.accept(reg);
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ public class DBTraceProgramViewMemory extends AbstractDBTraceProgramViewMemory {
|
|||
addressSet = temp;
|
||||
}
|
||||
|
||||
protected MemoryBlock getRegionBlock(DBTraceMemoryRegion region) {
|
||||
protected MemoryBlock getRegionBlock(TraceMemoryRegion region) {
|
||||
return regionBlocks.computeIfAbsent(region,
|
||||
r -> new DBTraceProgramViewMemoryRegionBlock(program, region));
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ public class DBTraceProgramViewMemory extends AbstractDBTraceProgramViewMemory {
|
|||
if (forceFullView) {
|
||||
return getSpaceBlock(addr.getAddressSpace());
|
||||
}
|
||||
DBTraceMemoryRegion region = getTopRegion(s -> memoryManager.getRegionContaining(s, addr));
|
||||
TraceMemoryRegion region = getTopRegion(s -> memoryManager.getRegionContaining(s, addr));
|
||||
return region == null ? null : getRegionBlock(region);
|
||||
}
|
||||
|
||||
|
@ -100,7 +100,7 @@ public class DBTraceProgramViewMemory extends AbstractDBTraceProgramViewMemory {
|
|||
AddressSpace space = program.getAddressFactory().getAddressSpace(blockName);
|
||||
return space == null ? null : getSpaceBlock(space);
|
||||
}
|
||||
DBTraceMemoryRegion region =
|
||||
TraceMemoryRegion region =
|
||||
getTopRegion(s -> memoryManager.getLiveRegionByPath(s, blockName));
|
||||
return region == null ? null : getRegionBlock(region);
|
||||
}
|
||||
|
@ -118,26 +118,26 @@ public class DBTraceProgramViewMemory extends AbstractDBTraceProgramViewMemory {
|
|||
return result.toArray(new MemoryBlock[result.size()]);
|
||||
}
|
||||
|
||||
public void updateAddRegionBlock(DBTraceMemoryRegion region) {
|
||||
public void updateAddRegionBlock(TraceMemoryRegion region) {
|
||||
// TODO: add block to cache?
|
||||
addRange(region.getRange());
|
||||
}
|
||||
|
||||
public void updateChangeRegionBlockName(DBTraceMemoryRegion region) {
|
||||
public void updateChangeRegionBlockName(TraceMemoryRegion region) {
|
||||
// Nothing. Block name is taken from region, uncached
|
||||
}
|
||||
|
||||
public void updateChangeRegionBlockFlags(DBTraceMemoryRegion region) {
|
||||
public void updateChangeRegionBlockFlags(TraceMemoryRegion region) {
|
||||
// Nothing. Block flags are taken from region, uncached
|
||||
}
|
||||
|
||||
public void updateChangeRegionBlockRange(DBTraceMemoryRegion region, AddressRange oldRange,
|
||||
public void updateChangeRegionBlockRange(TraceMemoryRegion region, AddressRange oldRange,
|
||||
AddressRange newRange) {
|
||||
// TODO: update cached block? Nothing to update.
|
||||
changeRange(oldRange, newRange);
|
||||
}
|
||||
|
||||
public void updateDeleteRegionBlock(DBTraceMemoryRegion region) {
|
||||
public void updateDeleteRegionBlock(TraceMemoryRegion region) {
|
||||
regionBlocks.remove(region);
|
||||
removeRange(region.getRange());
|
||||
}
|
||||
|
|
|
@ -20,18 +20,16 @@ import java.math.BigInteger;
|
|||
|
||||
import ghidra.framework.store.LockException;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.trace.database.memory.DBTraceMemoryRegion;
|
||||
import ghidra.trace.database.memory.DBTraceMemorySpace;
|
||||
import ghidra.trace.model.memory.TraceMemoryFlag;
|
||||
import ghidra.trace.model.memory.TraceMemorySpaceInputStream;
|
||||
import ghidra.trace.model.memory.*;
|
||||
|
||||
// TODO: Proper locking all over here
|
||||
public class DBTraceProgramViewMemoryRegionBlock extends AbstractDBTraceProgramViewMemoryBlock {
|
||||
|
||||
private final DBTraceMemoryRegion region;
|
||||
private final TraceMemoryRegion region;
|
||||
|
||||
public DBTraceProgramViewMemoryRegionBlock(DBTraceProgramView program,
|
||||
DBTraceMemoryRegion region) {
|
||||
TraceMemoryRegion region) {
|
||||
super(program);
|
||||
this.region = region;
|
||||
}
|
||||
|
|
|
@ -20,14 +20,14 @@ import com.google.common.collect.Range;
|
|||
import ghidra.program.model.address.*;
|
||||
import ghidra.trace.database.listing.DBTraceCodeRegisterSpace;
|
||||
import ghidra.trace.database.listing.UndefinedDBTraceData;
|
||||
import ghidra.trace.database.thread.DBTraceThread;
|
||||
import ghidra.trace.model.program.TraceProgramViewRegisterListing;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class DBTraceProgramViewRegisterListing extends AbstractDBTraceProgramViewListing
|
||||
implements TraceProgramViewRegisterListing {
|
||||
private final DBTraceThread thread;
|
||||
private final TraceThread thread;
|
||||
private Address minAddr;
|
||||
private Address maxAddr;
|
||||
|
||||
|
@ -42,7 +42,7 @@ public class DBTraceProgramViewRegisterListing extends AbstractDBTraceProgramVie
|
|||
}
|
||||
|
||||
@Override
|
||||
public DBTraceThread getThread() {
|
||||
public TraceThread getThread() {
|
||||
return thread;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,6 @@ import ghidra.program.model.util.AddressSetPropertyMap;
|
|||
import ghidra.program.model.util.PropertyMapManager;
|
||||
import ghidra.trace.database.listing.DBTraceCodeRegisterSpace;
|
||||
import ghidra.trace.database.memory.DBTraceMemoryRegisterSpace;
|
||||
import ghidra.trace.database.thread.DBTraceThread;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.data.TraceBasedDataTypeManager;
|
||||
import ghidra.trace.model.program.TraceProgramView;
|
||||
|
@ -50,7 +49,7 @@ public class DBTraceProgramViewRegisters implements TraceProgramView {
|
|||
protected final DomainObjectEventQueues eventQueues;
|
||||
|
||||
private final DBTraceProgramView view;
|
||||
private final DBTraceThread thread;
|
||||
private final TraceThread thread;
|
||||
|
||||
private final DBTraceProgramViewRegisterListing listing;
|
||||
private final DBTraceProgramViewRegisterMemory memory;
|
||||
|
|
|
@ -15,17 +15,17 @@
|
|||
*/
|
||||
package ghidra.trace.database.program;
|
||||
|
||||
import ghidra.trace.database.thread.DBTraceThread;
|
||||
import ghidra.trace.model.listing.TraceCodeOperations;
|
||||
import ghidra.trace.model.symbol.TraceReferenceOperations;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
|
||||
public class DBTraceProgramViewRegistersReferenceManager
|
||||
extends AbstractDBTraceProgramViewReferenceManager {
|
||||
|
||||
private final DBTraceThread thread;
|
||||
private final TraceThread thread;
|
||||
|
||||
public DBTraceProgramViewRegistersReferenceManager(DBTraceProgramView program,
|
||||
DBTraceThread thread) {
|
||||
TraceThread thread) {
|
||||
super(program);
|
||||
this.thread = thread;
|
||||
}
|
||||
|
|
|
@ -29,7 +29,6 @@ import ghidra.program.model.address.AddressFactory;
|
|||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.trace.database.*;
|
||||
import ghidra.trace.database.thread.DBTraceThread;
|
||||
import ghidra.trace.database.thread.DBTraceThreadManager;
|
||||
import ghidra.trace.model.stack.TraceStackFrame;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
|
@ -134,7 +133,11 @@ public abstract class AbstractDBTraceSpaceBasedManager<M extends DBTraceSpaceBas
|
|||
baseLanguage + ").");
|
||||
}
|
||||
else if (space.isRegisterSpace()) {
|
||||
DBTraceThread thread = threadManager.getThread(ent.threadKey);
|
||||
if (threadManager == null) {
|
||||
Msg.error(this, "Register spaces are not allowed without a thread manager.");
|
||||
continue;
|
||||
}
|
||||
TraceThread thread = threadManager.getThread(ent.threadKey);
|
||||
R regSpace;
|
||||
if (ent.space == null) {
|
||||
regSpace = createRegisterSpace(space, thread, ent);
|
||||
|
@ -190,7 +193,7 @@ public abstract class AbstractDBTraceSpaceBasedManager<M extends DBTraceSpaceBas
|
|||
}
|
||||
|
||||
protected R getForRegisterSpace(TraceThread thread, int frameLevel, boolean createIfAbsent) {
|
||||
DBTraceThread dbThread = trace.getThreadManager().assertIsMine(thread);
|
||||
trace.getThreadManager().assertIsMine(thread);
|
||||
// TODO: What if registers are memory mapped?
|
||||
Pair<TraceThread, Integer> frame = ImmutablePair.of(thread, frameLevel);
|
||||
if (!createIfAbsent) {
|
||||
|
@ -203,8 +206,8 @@ public abstract class AbstractDBTraceSpaceBasedManager<M extends DBTraceSpaceBas
|
|||
AddressSpace regSpace = baseLanguage.getAddressFactory().getRegisterSpace();
|
||||
try {
|
||||
DBTraceSpaceEntry ent = spaceStore.create();
|
||||
ent.set(regSpace.getName(), dbThread.getKey(), frameLevel);
|
||||
return createRegisterSpace(regSpace, dbThread, ent);
|
||||
ent.set(regSpace.getName(), thread.getKey(), frameLevel);
|
||||
return createRegisterSpace(regSpace, thread, ent);
|
||||
}
|
||||
catch (VersionException e) {
|
||||
throw new AssertionError(e);
|
||||
|
@ -256,7 +259,7 @@ public abstract class AbstractDBTraceSpaceBasedManager<M extends DBTraceSpaceBas
|
|||
protected abstract M createSpace(AddressSpace space, DBTraceSpaceEntry ent)
|
||||
throws VersionException, IOException;
|
||||
|
||||
protected abstract R createRegisterSpace(AddressSpace space, DBTraceThread thread,
|
||||
protected abstract R createRegisterSpace(AddressSpace space, TraceThread thread,
|
||||
DBTraceSpaceEntry ent) throws VersionException, IOException;
|
||||
|
||||
@Override
|
||||
|
|
|
@ -16,16 +16,16 @@
|
|||
package ghidra.trace.database.space;
|
||||
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.trace.database.thread.DBTraceThread;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.trace.util.TraceAddressSpace;
|
||||
|
||||
public interface DBTraceSpaceKey extends TraceAddressSpace {
|
||||
static class DefaultDBTraceSpaceKey implements DBTraceSpaceKey {
|
||||
private final DBTraceThread thread;
|
||||
private final TraceThread thread;
|
||||
private final AddressSpace space;
|
||||
private final int frameLevel;
|
||||
|
||||
private DefaultDBTraceSpaceKey(DBTraceThread thread, AddressSpace space, int frameLevel) {
|
||||
private DefaultDBTraceSpaceKey(TraceThread thread, AddressSpace space, int frameLevel) {
|
||||
this.thread = thread;
|
||||
this.space = space;
|
||||
this.frameLevel = frameLevel;
|
||||
|
@ -37,7 +37,7 @@ public interface DBTraceSpaceKey extends TraceAddressSpace {
|
|||
}
|
||||
|
||||
@Override
|
||||
public DBTraceThread getThread() {
|
||||
public TraceThread getThread() {
|
||||
return thread;
|
||||
}
|
||||
|
||||
|
@ -47,10 +47,7 @@ public interface DBTraceSpaceKey extends TraceAddressSpace {
|
|||
}
|
||||
}
|
||||
|
||||
static DBTraceSpaceKey create(AddressSpace space, DBTraceThread thread, int frameLevel) {
|
||||
static DBTraceSpaceKey create(AddressSpace space, TraceThread thread, int frameLevel) {
|
||||
return new DefaultDBTraceSpaceKey(thread, space, frameLevel);
|
||||
}
|
||||
|
||||
@Override
|
||||
DBTraceThread getThread();
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue