Merge remote-tracking branch 'origin/GP-1386_Dan_DBTraceObjectModel-REBASED-1--SQUASHED'

This commit is contained in:
ghidra1 2022-01-06 15:26:51 -05:00
commit 8e59d0e673
179 changed files with 9971 additions and 797 deletions

View file

@ -121,28 +121,28 @@ public abstract class AbstractModelForDbgengBreakpointsTest
@Override @Override
protected void disableViaInterpreter(TargetTogglable t, TargetInterpreter interpreter) protected void disableViaInterpreter(TargetTogglable t, TargetInterpreter interpreter)
throws Throwable { 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)); waitOn(interpreter.execute("bd " + bpId));
} }
@Override @Override
protected void enableViaInterpreter(TargetTogglable t, TargetInterpreter interpreter) protected void enableViaInterpreter(TargetTogglable t, TargetInterpreter interpreter)
throws Throwable { 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)); waitOn(interpreter.execute("be " + bpId));
} }
@Override @Override
protected void deleteViaInterpreter(TargetDeletable d, TargetInterpreter interpreter) protected void deleteViaInterpreter(TargetDeletable d, TargetInterpreter interpreter)
throws Throwable { 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)); waitOn(interpreter.execute("bc " + bpId));
} }
@Override @Override
protected void assertLocCoversViaInterpreter(AddressRange range, TargetBreakpointKind kind, protected void assertLocCoversViaInterpreter(AddressRange range, TargetBreakpointKind kind,
TargetBreakpointLocation loc, TargetInterpreter interpreter) throws Throwable { 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(); String line = waitOn(interpreter.executeCapture("bl " + bpId)).trim();
assertFalse(line.contains("\n")); assertFalse(line.contains("\n"));
// NB. WinDbg numbers breakpoints in base 10, by default // NB. WinDbg numbers breakpoints in base 10, by default
@ -153,7 +153,7 @@ public abstract class AbstractModelForDbgengBreakpointsTest
@Override @Override
protected void assertEnabledViaInterpreter(TargetTogglable t, boolean enabled, protected void assertEnabledViaInterpreter(TargetTogglable t, boolean enabled,
TargetInterpreter interpreter) throws Throwable { 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(); String line = waitOn(interpreter.executeCapture("bl " + bpId)).trim();
assertFalse(line.contains("\n")); assertFalse(line.contains("\n"));
assertTrue(line.startsWith(bpId)); assertTrue(line.startsWith(bpId));
@ -164,7 +164,7 @@ public abstract class AbstractModelForDbgengBreakpointsTest
@Override @Override
protected void assertDeletedViaInterpreter(TargetDeletable d, TargetInterpreter interpreter) protected void assertDeletedViaInterpreter(TargetDeletable d, TargetInterpreter interpreter)
throws Throwable { 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(); String line = waitOn(interpreter.executeCapture("bl " + bpId)).trim();
assertEquals("", line); assertEquals("", line);
} }

View file

@ -72,7 +72,7 @@ public abstract class AbstractModelForDbgengFrameActivationTest
String line = waitOn(interpreter.executeCapture(".frame")).trim(); String line = waitOn(interpreter.executeCapture(".frame")).trim();
assertFalse(line.contains("\n")); assertFalse(line.contains("\n"));
int frameId = Integer.parseInt(line.split("\\s+")[0], 16); 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); assertEquals(expId, frameId);
} }

View file

@ -63,7 +63,7 @@ public abstract class AbstractModelForDbgengProcessActivationTest
@Override @Override
protected void activateViaInterpreter(TargetObject obj, TargetInterpreter interpreter) protected void activateViaInterpreter(TargetObject obj, TargetInterpreter interpreter)
throws Throwable { throws Throwable {
String id = Unique.assertOne(getProcessPattern().matchIndices(obj.getPath())); String id = Unique.assertOne(getProcessPattern().matchKeys(obj.getPath()));
waitOn(interpreter.execute("|" + id + " s")); waitOn(interpreter.execute("|" + id + " s"));
} }

View file

@ -63,7 +63,7 @@ public abstract class AbstractModelForDbgengThreadActivationTest
@Override @Override
protected void activateViaInterpreter(TargetObject obj, TargetInterpreter interpreter) protected void activateViaInterpreter(TargetObject obj, TargetInterpreter interpreter)
throws Throwable { 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 // TODO: This test is imperfect, since processes are activated as well
waitOn(interpreter.execute("~" + threadId + " s")); waitOn(interpreter.execute("~" + threadId + " s"));
} }
@ -78,7 +78,7 @@ public abstract class AbstractModelForDbgengThreadActivationTest
.filter(l -> l.trim().startsWith(".")) .filter(l -> l.trim().startsWith("."))
.collect(Collectors.toList())).trim(); .collect(Collectors.toList())).trim();
String threadId = getIdFromCapture(line); String threadId = getIdFromCapture(line);
String expId = getThreadPattern().matchIndices(expected.getPath()).get(1); String expId = getThreadPattern().matchKeys(expected.getPath()).get(1);
assertEquals(expId, threadId); assertEquals(expId, threadId);
} }
} }

View file

@ -119,7 +119,7 @@ public abstract class AbstractModelForGdbBreakpointsTest
protected void disableViaInterpreter(TargetTogglable t, TargetInterpreter interpreter) protected void disableViaInterpreter(TargetTogglable t, TargetInterpreter interpreter)
throws Throwable { throws Throwable {
assert t instanceof TargetBreakpointSpec; // TODO: or Location 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)); waitOn(interpreter.execute("disable " + index));
} }
@ -127,7 +127,7 @@ public abstract class AbstractModelForGdbBreakpointsTest
protected void enableViaInterpreter(TargetTogglable t, TargetInterpreter interpreter) protected void enableViaInterpreter(TargetTogglable t, TargetInterpreter interpreter)
throws Throwable { throws Throwable {
assert t instanceof TargetBreakpointSpec; // TODO: or Location 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)); waitOn(interpreter.execute("enable " + index));
} }
@ -135,7 +135,7 @@ public abstract class AbstractModelForGdbBreakpointsTest
protected void deleteViaInterpreter(TargetDeletable d, TargetInterpreter interpreter) protected void deleteViaInterpreter(TargetDeletable d, TargetInterpreter interpreter)
throws Throwable { throws Throwable {
assert d instanceof TargetBreakpointSpec; // TODO: or Location 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)); waitOn(interpreter.execute("delete " + index));
} }
@ -143,7 +143,7 @@ public abstract class AbstractModelForGdbBreakpointsTest
protected void assertLocCoversViaInterpreter(AddressRange range, TargetBreakpointKind kind, protected void assertLocCoversViaInterpreter(AddressRange range, TargetBreakpointKind kind,
TargetBreakpointLocation loc, TargetInterpreter interpreter) throws Throwable { TargetBreakpointLocation loc, TargetInterpreter interpreter) throws Throwable {
String index = 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 output = waitOn(interpreter.executeCapture("info break " + index));
String line = Unique.assertOne(Stream.of(output.split("\n")) String line = Unique.assertOne(Stream.of(output.split("\n"))
.filter(l -> !l.trim().startsWith("Num")) .filter(l -> !l.trim().startsWith("Num"))
@ -156,7 +156,7 @@ public abstract class AbstractModelForGdbBreakpointsTest
protected void assertEnabledViaInterpreter(TargetTogglable t, boolean enabled, protected void assertEnabledViaInterpreter(TargetTogglable t, boolean enabled,
TargetInterpreter interpreter) throws Throwable { TargetInterpreter interpreter) throws Throwable {
assert t instanceof TargetBreakpointSpec; // TODO: or Location 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 output = waitOn(interpreter.executeCapture("info break " + index));
String line = Unique.assertOne(Stream.of(output.split("\n")) String line = Unique.assertOne(Stream.of(output.split("\n"))
.filter(l -> !l.trim().startsWith("Num")) .filter(l -> !l.trim().startsWith("Num"))
@ -170,7 +170,7 @@ public abstract class AbstractModelForGdbBreakpointsTest
protected void assertDeletedViaInterpreter(TargetDeletable d, TargetInterpreter interpreter) protected void assertDeletedViaInterpreter(TargetDeletable d, TargetInterpreter interpreter)
throws Throwable { throws Throwable {
assert d instanceof TargetBreakpointSpec; // TODO: or Location 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)); String output = waitOn(interpreter.executeCapture("info break " + index));
assertTrue(output.contains("No breakpoint")); assertTrue(output.contains("No breakpoint"));
} }

View file

@ -72,7 +72,7 @@ public abstract class AbstractModelForGdbFrameActivationTest
@Override @Override
protected void activateViaInterpreter(TargetObject obj, TargetInterpreter interpreter) protected void activateViaInterpreter(TargetObject obj, TargetInterpreter interpreter)
throws Throwable { 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)); waitOn(interpreter.execute("frame " + index));
} }

View file

@ -62,7 +62,7 @@ public abstract class AbstractModelForGdbInferiorActivationTest
@Override @Override
protected void activateViaInterpreter(TargetObject obj, TargetInterpreter interpreter) protected void activateViaInterpreter(TargetObject obj, TargetInterpreter interpreter)
throws Throwable { 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)); waitOn(interpreter.execute("inferior " + index));
} }

View file

@ -73,7 +73,7 @@ public abstract class AbstractModelForGdbThreadActivationTest
@Override @Override
protected void activateViaInterpreter(TargetObject obj, TargetInterpreter interpreter) protected void activateViaInterpreter(TargetObject obj, TargetInterpreter interpreter)
throws Throwable { 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 // TODO: This test is imperfect, since inferiors are activated as well
waitOn(interpreter.execute("thread " + index + ".1")); waitOn(interpreter.execute("thread " + index + ".1"));
} }

View file

@ -145,7 +145,7 @@ public abstract class AbstractModelForLldbBreakpointsTest
@Override @Override
protected void disableViaInterpreter(TargetTogglable t, TargetInterpreter interpreter) protected void disableViaInterpreter(TargetTogglable t, TargetInterpreter interpreter)
throws Throwable { 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 type = getTypeFromSpec(t);
waitOn(interpreter.execute(getCommand("disable", type, bpId))); waitOn(interpreter.execute(getCommand("disable", type, bpId)));
} }
@ -153,7 +153,7 @@ public abstract class AbstractModelForLldbBreakpointsTest
@Override @Override
protected void enableViaInterpreter(TargetTogglable t, TargetInterpreter interpreter) protected void enableViaInterpreter(TargetTogglable t, TargetInterpreter interpreter)
throws Throwable { 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 type = getTypeFromSpec(t);
waitOn(interpreter.execute(getCommand("enable", type, bpId))); waitOn(interpreter.execute(getCommand("enable", type, bpId)));
} }
@ -161,7 +161,7 @@ public abstract class AbstractModelForLldbBreakpointsTest
@Override @Override
protected void deleteViaInterpreter(TargetDeletable d, TargetInterpreter interpreter) protected void deleteViaInterpreter(TargetDeletable d, TargetInterpreter interpreter)
throws Throwable { 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 type = getTypeFromSpec(d);
waitOn(interpreter.execute(getCommand("delete", type, bpId))); waitOn(interpreter.execute(getCommand("delete", type, bpId)));
} }
@ -169,7 +169,7 @@ public abstract class AbstractModelForLldbBreakpointsTest
@Override @Override
protected void assertLocCoversViaInterpreter(AddressRange range, TargetBreakpointKind kind, protected void assertLocCoversViaInterpreter(AddressRange range, TargetBreakpointKind kind,
TargetBreakpointLocation loc, TargetInterpreter interpreter) throws Throwable { 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 bpId = matchIndices.get(BREAK_ID_POS);
String type = getTypeFromKind(kind); String type = getTypeFromKind(kind);
String line = waitOn(interpreter.executeCapture(getCommand("list", type, bpId))).trim(); String line = waitOn(interpreter.executeCapture(getCommand("list", type, bpId))).trim();
@ -182,7 +182,7 @@ public abstract class AbstractModelForLldbBreakpointsTest
@Override @Override
protected void assertEnabledViaInterpreter(TargetTogglable t, boolean enabled, protected void assertEnabledViaInterpreter(TargetTogglable t, boolean enabled,
TargetInterpreter interpreter) throws Throwable { 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 type = getTypeFromSpec(t);
String line = waitOn(interpreter.executeCapture(getCommand("list", type, bpId))).trim(); String line = waitOn(interpreter.executeCapture(getCommand("list", type, bpId))).trim();
assertTrue(line.contains(bpId.substring(1)+":")); assertTrue(line.contains(bpId.substring(1)+":"));
@ -192,7 +192,7 @@ public abstract class AbstractModelForLldbBreakpointsTest
@Override @Override
protected void assertDeletedViaInterpreter(TargetDeletable d, TargetInterpreter interpreter) protected void assertDeletedViaInterpreter(TargetDeletable d, TargetInterpreter interpreter)
throws Throwable { 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 type = getTypeFromSpec(d);
String line = waitOn(interpreter.executeCapture(type + " list ")).trim(); String line = waitOn(interpreter.executeCapture(type + " list ")).trim();
assertFalse(line.contains(bpId+":")); assertFalse(line.contains(bpId+":"));

View file

@ -57,7 +57,7 @@ public abstract class AbstractModelForLldbFrameActivationTest
protected void activateViaInterpreter(TargetObject obj, TargetInterpreter interpreter) protected void activateViaInterpreter(TargetObject obj, TargetInterpreter interpreter)
throws Throwable { throws Throwable {
String index = getStackPattern().matchIndices(obj.getPath()).get(3); String index = getStackPattern().matchKeys(obj.getPath()).get(3);
waitOn(interpreter.execute("frame select " + index)); waitOn(interpreter.execute("frame select " + index));
} }
@ -70,7 +70,7 @@ public abstract class AbstractModelForLldbFrameActivationTest
assertFalse(line.contains("\n")); assertFalse(line.contains("\n"));
String id = getIdFromCapture(line); String id = getIdFromCapture(line);
int frameId = Integer.parseInt(id, 10); 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); assertEquals(expId, frameId);
} }

View file

@ -94,7 +94,7 @@ public abstract class AbstractModelForLldbProcessActivationTest
.filter(l -> l.trim().startsWith("*")) .filter(l -> l.trim().startsWith("*"))
.collect(Collectors.toList())).trim(); .collect(Collectors.toList())).trim();
String procId = getIdFromCapture(line); 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)); assertEquals(Long.parseLong(expId, 16), Long.parseLong(procId));
} }

View file

@ -97,7 +97,7 @@ public abstract class AbstractModelForLldbSessionActivationTest
.filter(l -> l.trim().startsWith("*")) .filter(l -> l.trim().startsWith("*"))
.collect(Collectors.toList())).trim(); .collect(Collectors.toList())).trim();
String procId = getIdFromCapture(line); 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)); assertEquals(Long.parseLong(expId, 16), Long.parseLong(procId));
} }

View file

@ -80,7 +80,7 @@ public abstract class AbstractModelForLldbThreadActivationTest
.filter(l -> l.trim().startsWith("*")) .filter(l -> l.trim().startsWith("*"))
.collect(Collectors.toList())).trim(); .collect(Collectors.toList())).trim();
String threadId = getIdFromCapture(line); String threadId = getIdFromCapture(line);
String expId = getThreadPattern().matchIndices(expected.getPath()).get(2); String expId = getThreadPattern().matchKeys(expected.getPath()).get(2);
assertEquals(expId, threadId); assertEquals(expId, threadId);
} }

View file

@ -38,7 +38,8 @@ public class BreakpointLocationRow {
} }
public boolean isEnabled() { 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) { public void setEnabled(boolean enabled) {

View file

@ -210,8 +210,8 @@ public class DebuggerConsoleProvider extends ComponentProviderAdapter
} }
@Override @Override
public java.util.List<LogTableColumns> defaultSortOrder() { public List<LogTableColumns> defaultSortOrder() {
return java.util.List.of(LogTableColumns.ACTIONS, LogTableColumns.TIME); return List.of(LogTableColumns.ACTIONS, LogTableColumns.TIME);
} }
} }

View file

@ -228,7 +228,7 @@ public class DebuggerCopyPlan {
Address dest = intoAddress.add(off); Address dest = intoAddress.add(off);
ProgramBreakpoint pb = ProgramBreakpoint pb =
new ProgramBreakpoint(into, dest, bpt.getLength(), bpt.getKinds()); new ProgramBreakpoint(into, dest, bpt.getLength(), bpt.getKinds());
if (bpt.isEnabled()) { if (bpt.isEnabled(from.getSnap())) {
pb.enable(); pb.enable();
} }
else { else {

View file

@ -210,6 +210,11 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
public ModuleTableModel() { public ModuleTableModel() {
super("Modules", ModuleTableColumns.class, TraceModule::getObjectKey, ModuleRow::new); super("Modules", ModuleTableColumns.class, TraceModule::getObjectKey, ModuleRow::new);
} }
@Override
public List<ModuleTableColumns> defaultSortOrder() {
return List.of(ModuleTableColumns.BASE);
}
} }
protected static class SectionTableModel protected static class SectionTableModel
@ -220,6 +225,11 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
super("Sections", SectionTableColumns.class, TraceSection::getObjectKey, super("Sections", SectionTableColumns.class, TraceSection::getObjectKey,
SectionRow::new); SectionRow::new);
} }
@Override
public List<SectionTableColumns> defaultSortOrder() {
return List.of(SectionTableColumns.START);
}
} }
protected static Set<TraceModule> getSelectedModulesFromModuleContext( protected static Set<TraceModule> getSelectedModulesFromModuleContext(

View file

@ -22,6 +22,7 @@ import ghidra.app.services.TraceRecorder;
import ghidra.dbg.target.TargetExecutionStateful.TargetExecutionState; import ghidra.dbg.target.TargetExecutionStateful.TargetExecutionState;
import ghidra.trace.model.Trace; import ghidra.trace.model.Trace;
import ghidra.trace.model.thread.TraceThread; import ghidra.trace.model.thread.TraceThread;
import ghidra.util.Msg;
import ghidra.util.database.UndoableTransaction; import ghidra.util.database.UndoableTransaction;
public class ThreadRow { public class ThreadRow {
@ -109,6 +110,12 @@ public class ThreadRow {
@Override @Override
public String toString() { public String toString() {
return getName(); try {
return getName();
}
catch (Exception e) {
Msg.error(this, "Error rendering as string: " + e);
return "<ERROR>";
}
} }
} }

View file

@ -288,7 +288,7 @@ public interface LogicalBreakpointInternal extends LogicalBreakpoint {
public TraceEnablement computeEnablement() { public TraceEnablement computeEnablement() {
TraceEnablement en = TraceEnablement.MISSING; TraceEnablement en = TraceEnablement.MISSING;
for (IDHashed<TraceBreakpoint> bpt : breakpoints) { 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) { if (en == TraceEnablement.MIXED) {
return en; return en;
} }

View file

@ -167,7 +167,7 @@ public class DefaultBreakpointRecorder implements ManagedBreakpointRecorder {
traceBpt.setClearedSnap(snap - 1); traceBpt.setClearedSnap(snap - 1);
} }
breakpointManager.placeBreakpoint(path, snap, range, breakpointManager.placeBreakpoint(path, snap, range,
traceBpt.getThreads(), traceBpt.getKinds(), traceBpt.isEnabled(), traceBpt.getThreads(), traceBpt.getKinds(), traceBpt.isEnabled(snap),
traceBpt.getComment()); traceBpt.getComment());
} }
catch (DuplicateNameException e) { catch (DuplicateNameException e) {

View file

@ -173,7 +173,7 @@ public class DebuggerBreakpointsPluginScreenShots extends GhidraScreenShotGenera
assertEquals(3, allBreakpoints.size()); assertEquals(3, allBreakpoints.size());
}); });
waitForPass(() -> { waitForPass(() -> {
assertFalse(bpt.isEnabled()); assertFalse(bpt.isEnabled(0));
}); });
/** /**
* TODO: Might be necessary to debounce and wait for service callbacks to settle. Sometimes, * TODO: Might be necessary to debounce and wait for service callbacks to settle. Sometimes,

View file

@ -31,9 +31,9 @@ import ghidra.async.AsyncTestUtils;
import ghidra.test.ToyProgramBuilder; import ghidra.test.ToyProgramBuilder;
import ghidra.trace.database.ToyDBTraceBuilder; import ghidra.trace.database.ToyDBTraceBuilder;
import ghidra.trace.database.memory.DBTraceMemoryManager; import ghidra.trace.database.memory.DBTraceMemoryManager;
import ghidra.trace.database.thread.DBTraceThread;
import ghidra.trace.database.time.DBTraceTimeManager; import ghidra.trace.database.time.DBTraceTimeManager;
import ghidra.trace.model.memory.TraceMemoryFlag; import ghidra.trace.model.memory.TraceMemoryFlag;
import ghidra.trace.model.thread.TraceThread;
import ghidra.trace.model.time.schedule.TraceSchedule; import ghidra.trace.model.time.schedule.TraceSchedule;
import ghidra.util.Swing; import ghidra.util.Swing;
import ghidra.util.database.UndoableTransaction; import ghidra.util.database.UndoableTransaction;
@ -105,7 +105,7 @@ public class DebuggerTraceViewDiffPluginScreenShots extends GhidraScreenShotGene
@Test @Test
public void testCaptureDebuggerTimeSelectionDialog() throws Throwable { public void testCaptureDebuggerTimeSelectionDialog() throws Throwable {
DBTraceThread thread; TraceThread thread;
try (UndoableTransaction tid = tb.startTransaction()) { try (UndoableTransaction tid = tb.startTransaction()) {
DBTraceTimeManager tm = tb.trace.getTimeManager(); DBTraceTimeManager tm = tb.trace.getTimeManager();
thread = tb.getOrAddThread("main", 0); thread = tb.getOrAddThread("main", 0);

View file

@ -30,7 +30,6 @@ import ghidra.framework.model.DomainFolder;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.test.ToyProgramBuilder; import ghidra.test.ToyProgramBuilder;
import ghidra.trace.database.ToyDBTraceBuilder; import ghidra.trace.database.ToyDBTraceBuilder;
import ghidra.trace.database.thread.DBTraceThread;
import ghidra.trace.model.breakpoint.TraceBreakpointKind; import ghidra.trace.model.breakpoint.TraceBreakpointKind;
import ghidra.trace.model.memory.TraceMemoryFlag; import ghidra.trace.model.memory.TraceMemoryFlag;
import ghidra.trace.model.thread.TraceThread; import ghidra.trace.model.thread.TraceThread;
@ -80,7 +79,7 @@ public class DebuggerMemviewPluginScreenShots extends GhidraScreenShotGenerator
private void populateTraceAndPrograms() throws Exception { private void populateTraceAndPrograms() throws Exception {
DomainFolder root = tool.getProject().getProjectData().getRootFolder(); DomainFolder root = tool.getProject().getProjectData().getRootFolder();
DBTraceThread thread1; TraceThread thread1;
try (UndoableTransaction tid = tb.startTransaction()) { try (UndoableTransaction tid = tb.startTransaction()) {
thread1 = tb.trace.getThreadManager().addThread("[0]", Range.openClosed(0L, 40L)); thread1 = tb.trace.getThreadManager().addThread("[0]", Range.openClosed(0L, 40L));
tb.trace.getThreadManager().addThread("[1]", Range.openClosed(3L, 50L)); tb.trace.getThreadManager().addThread("[1]", Range.openClosed(3L, 50L));

View file

@ -43,8 +43,7 @@ import docking.widgets.tree.GTreeNode;
import generic.Unique; import generic.Unique;
import ghidra.app.plugin.core.debug.gui.action.*; import ghidra.app.plugin.core.debug.gui.action.*;
import ghidra.app.plugin.core.debug.mapping.*; import ghidra.app.plugin.core.debug.mapping.*;
import ghidra.app.plugin.core.debug.service.model.DebuggerModelServiceInternal; import ghidra.app.plugin.core.debug.service.model.*;
import ghidra.app.plugin.core.debug.service.model.DebuggerModelServiceProxyPlugin;
import ghidra.app.plugin.core.debug.service.tracemgr.DebuggerTraceManagerServicePlugin; import ghidra.app.plugin.core.debug.service.tracemgr.DebuggerTraceManagerServicePlugin;
import ghidra.app.services.*; import ghidra.app.services.*;
import ghidra.app.util.viewer.listingpanel.ListingPanel; import ghidra.app.util.viewer.listingpanel.ListingPanel;
@ -521,6 +520,8 @@ public abstract class AbstractGhidraHeadedDebuggerGUITest
@After @After
public void tearDown() { public void tearDown() {
runSwing(() -> traceManager.setSaveTracesByDefault(false));
if (tb != null) { if (tb != null) {
if (traceManager != null && traceManager.getOpenTraces().contains(tb.trace)) { if (traceManager != null && traceManager.getOpenTraces().contains(tb.trace)) {
traceManager.closeTrace(tb.trace); traceManager.closeTrace(tb.trace);
@ -531,8 +532,6 @@ public abstract class AbstractGhidraHeadedDebuggerGUITest
if (mb != null) { if (mb != null) {
if (mb.testModel != null) { if (mb.testModel != null) {
modelService.removeModel(mb.testModel); modelService.removeModel(mb.testModel);
runSwing(() -> traceManager.setSaveTracesByDefault(false));
for (TraceRecorder recorder : modelService.getTraceRecorders()) { for (TraceRecorder recorder : modelService.getTraceRecorders()) {
recorder.stopRecording(); recorder.stopRecording();
} }
@ -588,6 +587,17 @@ public abstract class AbstractGhidraHeadedDebuggerGUITest
tb = new ToyDBTraceBuilder(trace); 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 { protected void createAndOpenTrace(String langID) throws IOException {
createTrace(langID); createTrace(langID);
traceManager.openTrace(tb.trace); traceManager.openTrace(tb.trace);

View file

@ -137,7 +137,7 @@ public class DebuggerBreakpointMarkerPluginTest extends AbstractGhidraHeadedDebu
createTestModel(); createTestModel();
mb.createTestProcessesAndThreads(); mb.createTestProcessesAndThreads();
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1, TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
Trace trace = recorder.getTrace(); Trace trace = recorder.getTrace();
createProgramFromTrace(trace); createProgramFromTrace(trace);
intoProject(trace); intoProject(trace);

View file

@ -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")));
}
}
}

View file

@ -121,7 +121,7 @@ public class DebuggerBreakpointsProviderTest extends AbstractGhidraHeadedDebugge
createTestModel(); createTestModel();
mb.createTestProcessesAndThreads(); mb.createTestProcessesAndThreads();
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1, TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
Trace trace = recorder.getTrace(); Trace trace = recorder.getTrace();
addLiveMemoryAndBreakpoint(mb.testProcess1, recorder); addLiveMemoryAndBreakpoint(mb.testProcess1, recorder);
@ -145,7 +145,7 @@ public class DebuggerBreakpointsProviderTest extends AbstractGhidraHeadedDebugge
createTestModel(); createTestModel();
mb.createTestProcessesAndThreads(); mb.createTestProcessesAndThreads();
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1, TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
Trace trace = recorder.getTrace(); Trace trace = recorder.getTrace();
addLiveMemoryAndBreakpoint(mb.testProcess1, recorder); addLiveMemoryAndBreakpoint(mb.testProcess1, recorder);
@ -210,7 +210,7 @@ public class DebuggerBreakpointsProviderTest extends AbstractGhidraHeadedDebugge
createTestModel(); createTestModel();
mb.createTestProcessesAndThreads(); mb.createTestProcessesAndThreads();
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1, TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
Trace trace = recorder.getTrace(); Trace trace = recorder.getTrace();
createProgramFromTrace(trace); createProgramFromTrace(trace);
intoProject(trace); intoProject(trace);
@ -471,7 +471,7 @@ public class DebuggerBreakpointsProviderTest extends AbstractGhidraHeadedDebugge
createTestModel(); createTestModel();
mb.createTestProcessesAndThreads(); mb.createTestProcessesAndThreads();
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1, TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
Trace trace = recorder.getTrace(); Trace trace = recorder.getTrace();
createProgramFromTrace(trace); createProgramFromTrace(trace);
intoProject(trace); intoProject(trace);
@ -512,12 +512,15 @@ public class DebuggerBreakpointsProviderTest extends AbstractGhidraHeadedDebugge
public void testActionFilters() throws Exception { public void testActionFilters() throws Exception {
createTestModel(); createTestModel();
mb.createTestProcessesAndThreads(); mb.createTestProcessesAndThreads();
TraceRecorder recorder1 = modelService.recordTarget(mb.testProcess1, TraceRecorder recorder1 = modelService.recordTarget(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
Trace trace1 = recorder1.getTrace(); Trace trace1 = recorder1.getTrace();
TraceRecorder recorder3 = modelService.recordTarget(mb.testProcess3, TraceRecorder recorder3 = modelService.recordTarget(mb.testProcess3,
new TestDebuggerTargetTraceMapper(mb.testProcess3)); createTargetTraceMapper(mb.testProcess3));
Trace trace3 = recorder3.getTrace(); Trace trace3 = recorder3.getTrace();
createProgramFromTrace(trace1); createProgramFromTrace(trace1);
intoProject(trace1); intoProject(trace1);
intoProject(trace3); intoProject(trace3);

View file

@ -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.gui.listing.DebuggerListingProvider;
import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingServicePlugin; import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingServicePlugin;
import ghidra.app.services.DebuggerStaticMappingService; import ghidra.app.services.DebuggerStaticMappingService;
import ghidra.app.services.TraceRecorder;
import ghidra.dbg.DebuggerModelListener; import ghidra.dbg.DebuggerModelListener;
import ghidra.dbg.target.TargetObject; import ghidra.dbg.target.TargetObject;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
@ -457,9 +456,7 @@ public class DebuggerCopyActionsPluginTest extends AbstractGhidraHeadedDebuggerG
mb.testModel.addModelListener(listener); mb.testModel.addModelListener(listener);
mb.createTestProcessesAndThreads(); mb.createTestProcessesAndThreads();
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1, modelService.recordTarget(mb.testProcess1, createTargetTraceMapper(mb.testProcess1));
new TestDebuggerTargetTraceMapper(mb.testProcess1));
useTrace(recorder.getTrace());
mb.testProcess1.memory.addRegion(".text", mb.rng(0x55550000, 0x5555ffff), "rx"); 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)); mb.testProcess1.memory.setMemory(mb.addr(0x55550000), mb.arr(1, 2, 3, 4, 5, 6, 7, 8));
waitForPass(() -> { waitForPass(() -> {

View file

@ -53,11 +53,11 @@ import ghidra.program.util.ProgramLocation;
import ghidra.program.util.ProgramSelection; import ghidra.program.util.ProgramSelection;
import ghidra.trace.database.ToyDBTraceBuilder; import ghidra.trace.database.ToyDBTraceBuilder;
import ghidra.trace.database.memory.DBTraceMemoryManager; import ghidra.trace.database.memory.DBTraceMemoryManager;
import ghidra.trace.database.stack.DBTraceStack;
import ghidra.trace.database.stack.DBTraceStackManager; import ghidra.trace.database.stack.DBTraceStackManager;
import ghidra.trace.model.*; import ghidra.trace.model.*;
import ghidra.trace.model.memory.*; import ghidra.trace.model.memory.*;
import ghidra.trace.model.modules.TraceModule; import ghidra.trace.model.modules.TraceModule;
import ghidra.trace.model.stack.TraceStack;
import ghidra.trace.model.thread.TraceThread; import ghidra.trace.model.thread.TraceThread;
import ghidra.trace.model.time.TraceSnapshot; import ghidra.trace.model.time.TraceSnapshot;
import ghidra.util.database.UndoableTransaction; import ghidra.util.database.UndoableTransaction;
@ -632,7 +632,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
mb.createTestProcessesAndThreads(); mb.createTestProcessesAndThreads();
TraceRecorder recorder = modelService.recordTargetAndActivateTrace(mb.testProcess1, TraceRecorder recorder = modelService.recordTargetAndActivateTrace(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
Trace trace = recorder.getTrace(); Trace trace = recorder.getTrace();
mb.testProcess1.addRegion("exe:.text", mb.rng(0x55550000, 0x5555ffff), "rx"); mb.testProcess1.addRegion("exe:.text", mb.rng(0x55550000, 0x5555ffff), "rx");
@ -960,7 +960,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
mb.createTestProcessesAndThreads(); mb.createTestProcessesAndThreads();
TraceRecorder recorder = modelService.recordTargetAndActivateTrace(mb.testProcess1, TraceRecorder recorder = modelService.recordTargetAndActivateTrace(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
Trace trace = recorder.getTrace(); Trace trace = recorder.getTrace();
mb.testProcess1.addRegion("exe:.text", mb.rng(0x55550000, 0x555500ff), "rx"); mb.testProcess1.addRegion("exe:.text", mb.rng(0x55550000, 0x555500ff), "rx");
@ -1256,7 +1256,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE); TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
thread = tb.getOrAddThread("Thread 1", 0); thread = tb.getOrAddThread("Thread 1", 0);
DBTraceStackManager sm = tb.trace.getStackManager(); 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(0, true).setProgramCounter(tb.addr(0x00401234));
stack.getFrame(1, true).setProgramCounter(tb.addr(0x00404321)); 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))); regs.setValue(0, new RegisterValue(pc, new BigInteger("00401234", 16)));
DBTraceStackManager sm = tb.trace.getStackManager(); DBTraceStackManager sm = tb.trace.getStackManager();
DBTraceStack stack = sm.getStack(thread, 0, true); TraceStack stack = sm.getStack(thread, 0, true);
stack.getFrame(0, true); stack.getFrame(0, true);
} }
waitForDomainObject(tb.trace); waitForDomainObject(tb.trace);
@ -1348,7 +1348,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
mm.addRegion("exe:.text", Range.atLeast(0L), tb.range(0x00400000, 0x0040ffff), mm.addRegion("exe:.text", Range.atLeast(0L), tb.range(0x00400000, 0x0040ffff),
TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE); TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
thread = tb.getOrAddThread("Thread 1", 0); 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)); stack.getFrame(0, true).setProgramCounter(tb.addr(0x00401234));
} }
waitForDomainObject(tb.trace); waitForDomainObject(tb.trace);
@ -1358,7 +1358,7 @@ public class DebuggerListingProviderTest extends AbstractGhidraHeadedDebuggerGUI
assertEquals(tb.addr(0x00401234), listingProvider.getLocation().getAddress()); assertEquals(tb.addr(0x00401234), listingProvider.getLocation().getAddress());
try (UndoableTransaction tid = tb.startTransaction()) { 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)); stack.getFrame(0, true).setProgramCounter(tb.addr(0x00404321));
} }
waitForDomainObject(tb.trace); waitForDomainObject(tb.trace);

View file

@ -15,7 +15,7 @@
*/ */
package ghidra.app.plugin.core.debug.gui.memory; 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 static org.junit.Assert.*;
import java.awt.*; import java.awt.*;
@ -55,11 +55,11 @@ import ghidra.program.util.ProgramLocation;
import ghidra.program.util.ProgramSelection; import ghidra.program.util.ProgramSelection;
import ghidra.trace.database.ToyDBTraceBuilder; import ghidra.trace.database.ToyDBTraceBuilder;
import ghidra.trace.database.memory.DBTraceMemoryManager; import ghidra.trace.database.memory.DBTraceMemoryManager;
import ghidra.trace.database.stack.DBTraceStack;
import ghidra.trace.database.stack.DBTraceStackManager; import ghidra.trace.database.stack.DBTraceStackManager;
import ghidra.trace.model.Trace; import ghidra.trace.model.Trace;
import ghidra.trace.model.memory.*; import ghidra.trace.model.memory.*;
import ghidra.trace.model.modules.TraceModule; import ghidra.trace.model.modules.TraceModule;
import ghidra.trace.model.stack.TraceStack;
import ghidra.trace.model.thread.TraceThread; import ghidra.trace.model.thread.TraceThread;
import ghidra.trace.model.time.TraceSnapshot; import ghidra.trace.model.time.TraceSnapshot;
import ghidra.util.database.UndoableTransaction; import ghidra.util.database.UndoableTransaction;
@ -468,7 +468,7 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge
mb.createTestProcessesAndThreads(); mb.createTestProcessesAndThreads();
TraceRecorder recorder = modelService.recordTargetAndActivateTrace(mb.testProcess1, TraceRecorder recorder = modelService.recordTargetAndActivateTrace(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
Trace trace = recorder.getTrace(); Trace trace = recorder.getTrace();
mb.testProcess1.addRegion("exe:.text", mb.rng(0x55550000, 0x5555ffff), "rx"); mb.testProcess1.addRegion("exe:.text", mb.rng(0x55550000, 0x5555ffff), "rx");
@ -762,7 +762,7 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge
mb.createTestProcessesAndThreads(); mb.createTestProcessesAndThreads();
TraceRecorder recorder = modelService.recordTargetAndActivateTrace(mb.testProcess1, TraceRecorder recorder = modelService.recordTargetAndActivateTrace(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
Trace trace = recorder.getTrace(); Trace trace = recorder.getTrace();
mb.testProcess1.addRegion("exe:.text", mb.rng(0x55550000, 0x555500ff), "rx"); mb.testProcess1.addRegion("exe:.text", mb.rng(0x55550000, 0x555500ff), "rx");
@ -957,7 +957,7 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge
TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE); TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
thread = tb.getOrAddThread("Thread 1", 0); thread = tb.getOrAddThread("Thread 1", 0);
DBTraceStackManager sm = tb.trace.getStackManager(); 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(0, true).setProgramCounter(tb.addr(0x00401234));
stack.getFrame(1, true).setProgramCounter(tb.addr(0x00404321)); 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))); regs.setValue(0, new RegisterValue(pc, new BigInteger("00401234", 16)));
DBTraceStackManager sm = tb.trace.getStackManager(); DBTraceStackManager sm = tb.trace.getStackManager();
DBTraceStack stack = sm.getStack(thread, 0, true); TraceStack stack = sm.getStack(thread, 0, true);
stack.getFrame(0, true); stack.getFrame(0, true);
} }
waitForDomainObject(tb.trace); waitForDomainObject(tb.trace);
@ -1049,7 +1049,7 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge
mm.addRegion("exe:.text", Range.atLeast(0L), tb.range(0x00400000, 0x0040ffff), mm.addRegion("exe:.text", Range.atLeast(0L), tb.range(0x00400000, 0x0040ffff),
TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE); TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
thread = tb.getOrAddThread("Thread 1", 0); 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)); stack.getFrame(0, true).setProgramCounter(tb.addr(0x00401234));
} }
waitForDomainObject(tb.trace); waitForDomainObject(tb.trace);
@ -1059,7 +1059,7 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge
assertEquals(tb.addr(0x00401234), memBytesProvider.getLocation().getAddress()); assertEquals(tb.addr(0x00401234), memBytesProvider.getLocation().getAddress());
try (UndoableTransaction tid = tb.startTransaction()) { 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)); stack.getFrame(0, true).setProgramCounter(tb.addr(0x00404321));
} }
waitForDomainObject(tb.trace); waitForDomainObject(tb.trace);
@ -1074,7 +1074,7 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge
mb.createTestProcessesAndThreads(); mb.createTestProcessesAndThreads();
TraceRecorder recorder = modelService.recordTargetAndActivateTrace(mb.testProcess1, TraceRecorder recorder = modelService.recordTargetAndActivateTrace(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
Trace trace = recorder.getTrace(); Trace trace = recorder.getTrace();
mb.testProcess1.addRegion("exe:.text", mb.rng(0x55550000, 0x5555ffff), "rx"); mb.testProcess1.addRegion("exe:.text", mb.rng(0x55550000, 0x5555ffff), "rx");
@ -1106,7 +1106,7 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge
mb.createTestProcessesAndThreads(); mb.createTestProcessesAndThreads();
TraceRecorder recorder = modelService.recordTargetAndActivateTrace(mb.testProcess1, TraceRecorder recorder = modelService.recordTargetAndActivateTrace(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
Trace trace = recorder.getTrace(); Trace trace = recorder.getTrace();
mb.testProcess1.addRegion("exe:.text", mb.rng(0x55550000, 0x5555ffff), "rx"); mb.testProcess1.addRegion("exe:.text", mb.rng(0x55550000, 0x5555ffff), "rx");
@ -1150,7 +1150,7 @@ public class DebuggerMemoryBytesProviderTest extends AbstractGhidraHeadedDebugge
mb.createTestProcessesAndThreads(); mb.createTestProcessesAndThreads();
TraceRecorder recorder = modelService.recordTargetAndActivateTrace(mb.testProcess1, TraceRecorder recorder = modelService.recordTargetAndActivateTrace(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
Trace trace = recorder.getTrace(); Trace trace = recorder.getTrace();
mb.testProcess1.addRegion("exe:.text", mb.rng(0x55550000, 0x5555ffff), "rx"); mb.testProcess1.addRegion("exe:.text", mb.rng(0x55550000, 0x5555ffff), "rx");

View file

@ -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")));
}
}
}

View file

@ -62,13 +62,13 @@ public class DebuggerRegionsProviderTest extends AbstractGhidraHeadedDebuggerGUI
protected void addRegions() throws Exception { protected void addRegions() throws Exception {
TraceMemoryManager mm = tb.trace.getMemoryManager(); TraceMemoryManager mm = tb.trace.getMemoryManager();
try (UndoableTransaction tid = tb.startTransaction()) { 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); 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); 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); 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); tb.range(0x7f100000, 0x7f10003f), TraceMemoryFlag.READ, TraceMemoryFlag.WRITE);
} }
} }
@ -104,7 +104,8 @@ public class DebuggerRegionsProviderTest extends AbstractGhidraHeadedDebuggerGUI
TraceMemoryRegion region; TraceMemoryRegion region;
try (UndoableTransaction tid = tb.startTransaction()) { try (UndoableTransaction tid = tb.startTransaction()) {
TraceMemoryManager mm = tb.trace.getMemoryManager(); 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); TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
} }
@ -114,7 +115,7 @@ public class DebuggerRegionsProviderTest extends AbstractGhidraHeadedDebuggerGUI
RegionRow row = Unique.assertOne(provider.regionTableModel.getModelData()); RegionRow row = Unique.assertOne(provider.regionTableModel.getModelData());
assertEquals(region, row.getRegion()); assertEquals(region, row.getRegion());
assertEquals("bin:.text", row.getName()); assertEquals("Memory[bin:.text]", row.getName());
assertEquals(tb.addr(0x00400000), row.getMinAddress()); assertEquals(tb.addr(0x00400000), row.getMinAddress());
assertEquals(tb.addr(0x0040ffff), row.getMaxAddress()); assertEquals(tb.addr(0x0040ffff), row.getMaxAddress());
assertEquals(tb.range(0x00400000, 0x0040ffff), row.getRange()); assertEquals(tb.range(0x00400000, 0x0040ffff), row.getRange());
@ -132,7 +133,8 @@ public class DebuggerRegionsProviderTest extends AbstractGhidraHeadedDebuggerGUI
TraceMemoryRegion region; TraceMemoryRegion region;
try (UndoableTransaction tid = tb.startTransaction()) { try (UndoableTransaction tid = tb.startTransaction()) {
TraceMemoryManager mm = tb.trace.getMemoryManager(); 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); TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
} }
@ -149,7 +151,8 @@ public class DebuggerRegionsProviderTest extends AbstractGhidraHeadedDebuggerGUI
TraceMemoryRegion region; TraceMemoryRegion region;
try (UndoableTransaction tid = tb.startTransaction()) { try (UndoableTransaction tid = tb.startTransaction()) {
TraceMemoryManager mm = tb.trace.getMemoryManager(); 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); TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
} }
@ -174,7 +177,7 @@ public class DebuggerRegionsProviderTest extends AbstractGhidraHeadedDebuggerGUI
try (UndoableTransaction tid = tb.startTransaction()) { try (UndoableTransaction tid = tb.startTransaction()) {
TraceMemoryManager mm = tb.trace.getMemoryManager(); 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); TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
} }
@ -197,7 +200,7 @@ public class DebuggerRegionsProviderTest extends AbstractGhidraHeadedDebuggerGUI
try (UndoableTransaction tid = tb.startTransaction()) { try (UndoableTransaction tid = tb.startTransaction()) {
TraceMemoryManager mm = tb.trace.getMemoryManager(); 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); TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
waitForDomainObject(tb.trace); waitForDomainObject(tb.trace);
@ -218,7 +221,8 @@ public class DebuggerRegionsProviderTest extends AbstractGhidraHeadedDebuggerGUI
TraceMemoryRegion region; TraceMemoryRegion region;
try (UndoableTransaction tid = tb.startTransaction()) { try (UndoableTransaction tid = tb.startTransaction()) {
TraceMemoryManager mm = tb.trace.getMemoryManager(); 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); TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
} }
@ -333,7 +337,8 @@ public class DebuggerRegionsProviderTest extends AbstractGhidraHeadedDebuggerGUI
TraceMemoryRegion region; TraceMemoryRegion region;
try (UndoableTransaction tid = tb.startTransaction()) { try (UndoableTransaction tid = tb.startTransaction()) {
TraceMemoryManager mm = tb.trace.getMemoryManager(); 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); TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
} }
@ -365,7 +370,8 @@ public class DebuggerRegionsProviderTest extends AbstractGhidraHeadedDebuggerGUI
TraceMemoryRegion region; TraceMemoryRegion region;
try (UndoableTransaction tid = tb.startTransaction()) { try (UndoableTransaction tid = tb.startTransaction()) {
TraceMemoryManager mm = tb.trace.getMemoryManager(); 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); TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
} }

View file

@ -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")));
}
}
}

View file

@ -100,7 +100,8 @@ public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerGUI
else { else {
throw new AssertionError(); throw new AssertionError();
} }
manager.addRegion(module.getName() + ":" + section.getName(), manager.addRegion(
"Processes[1].Memory[" + module.getName() + ":" + section.getName() + "]",
module.getLifespan(), section.getRange(), flags); module.getLifespan(), section.getRange(), flags);
} }
} }
@ -110,19 +111,19 @@ public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerGUI
protected void addModules() throws Exception { protected void addModules() throws Exception {
TraceModuleManager manager = tb.trace.getModuleManager(); TraceModuleManager manager = tb.trace.getModuleManager();
try (UndoableTransaction tid = tb.startTransaction()) { 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); tb.range(0x55550000, 0x5575007f), 0);
secExeText = secExeText = modExe.addSection("Processes[1].Modules[first_proc].Sections[.text]",
modExe.addSection("first_proc[.text]", ".text", tb.range(0x55550000, 0x555500ff)); ".text", tb.range(0x55550000, 0x555500ff));
secExeData = secExeData = modExe.addSection("Processes[1].Modules[first_proc].Sections[.data]",
modExe.addSection("first_proc[.data]", ".data", tb.range(0x55750000, 0x5575007f)); ".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); tb.range(0x7f000000, 0x7f10003f), 0);
secLibText = secLibText = modLib.addSection("Processes[1].Modules[some_lib].Sections[.text]",
modLib.addSection("some_lib[.text]", ".text", tb.range(0x7f000000, 0x7f0003ff)); ".text", tb.range(0x7f000000, 0x7f0003ff));
secLibData = secLibData = modLib.addSection("Processes[1].Modules[some_lib].Sections[.data]",
modLib.addSection("some_lib[.data]", ".data", tb.range(0x7f100000, 0x7f10003f)); ".data", tb.range(0x7f100000, 0x7f10003f));
} }
} }
@ -144,8 +145,10 @@ public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerGUI
} }
protected void assertProviderPopulated() { protected void assertProviderPopulated() {
List<ModuleRow> modulesDisplayed = modulesProvider.moduleTableModel.getModelData(); List<ModuleRow> modulesDisplayed =
// I should be able to assume this is sorted by base address 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()); assertEquals(2, modulesDisplayed.size());
ModuleRow execRow = modulesDisplayed.get(0); ModuleRow execRow = modulesDisplayed.get(0);
@ -156,7 +159,9 @@ public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerGUI
ModuleRow libRow = modulesDisplayed.get(1); ModuleRow libRow = modulesDisplayed.get(1);
assertEquals(tb.addr(0x7f000000), libRow.getBase()); 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()); assertEquals(4, sectionsDisplayed.size());
SectionRow execTextRow = sectionsDisplayed.get(0); SectionRow execTextRow = sectionsDisplayed.get(0);
@ -261,13 +266,17 @@ public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerGUI
} }
waitForDomainObject(tb.trace); 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()); assertEquals(1, modulesDisplayed.size());
ModuleRow libRow = modulesDisplayed.get(0); ModuleRow libRow = modulesDisplayed.get(0);
assertEquals("some_lib", libRow.getName()); 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()); assertEquals(2, sectionsDisplayed.size());
SectionRow libTextRow = sectionsDisplayed.get(0); SectionRow libTextRow = sectionsDisplayed.get(0);
@ -543,13 +552,15 @@ public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerGUI
mb.createTestProcessesAndThreads(); mb.createTestProcessesAndThreads();
TraceRecorder recorder = modelService.recordTargetAndActivateTrace(mb.testProcess1, TraceRecorder recorder = modelService.recordTargetAndActivateTrace(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
Trace trace = recorder.getTrace(); Trace trace = recorder.getTrace();
// TODO: A region should not be required first. Just to get a memMapper? // 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 = 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. // NOTE: A section should not be required at this point.
TestTargetTypedefDataType typedef = module.types.addTypedefDataType("myInt", TestTargetTypedefDataType typedef = module.types.addTypedefDataType("myInt",
new DefaultTargetPrimitiveDataType(PrimitiveKind.SINT, 4)); new DefaultTargetPrimitiveDataType(PrimitiveKind.SINT, 4));
@ -577,7 +588,7 @@ public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerGUI
conv.convertTargetDataType(typedef).get(DEFAULT_WAIT_TIMEOUT, TimeUnit.MILLISECONDS); conv.convertTargetDataType(typedef).get(DEFAULT_WAIT_TIMEOUT, TimeUnit.MILLISECONDS);
// TODO: Some heuristic or convention to extract the module name, if applicable // TODO: Some heuristic or convention to extract the module name, if applicable
waitForPass(() -> { waitForPass(() -> {
DataType actType = dtm.getDataType("/Processes[1].Modules[first_proc].Types/myInt"); DataType actType = dtm.getDataType("/Modules[first_proc].Types/myInt");
assertTypeEquals(expType, actType); assertTypeEquals(expType, actType);
}); });
@ -596,11 +607,12 @@ public class DebuggerModulesProviderTest extends AbstractGhidraHeadedDebuggerGUI
mb.createTestProcessesAndThreads(); mb.createTestProcessesAndThreads();
TraceRecorder recorder = modelService.recordTargetAndActivateTrace(mb.testProcess1, TraceRecorder recorder = modelService.recordTargetAndActivateTrace(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
Trace trace = recorder.getTrace(); Trace trace = recorder.getTrace();
// TODO: A region should not be required first. Just to get a memMapper? // 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 = TestTargetModule module =
mb.testProcess1.modules.addModule("first_proc", mb.rng(0x55550000, 0x555500ff)); mb.testProcess1.modules.addModule("first_proc", mb.rng(0x55550000, 0x555500ff));
// NOTE: A section should not be required at this point. // NOTE: A section should not be required at this point.

View file

@ -146,7 +146,7 @@ public class DebuggerRegistersProviderTest extends AbstractGhidraHeadedDebuggerG
Register::isBaseRegister); Register::isBaseRegister);
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1, TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
waitFor(() -> { waitFor(() -> {
TraceThread thread = recorder.getTraceThread(mb.testThread1); TraceThread thread = recorder.getTraceThread(mb.testThread1);

View file

@ -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")));
}
}
}

View file

@ -155,7 +155,7 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerGUITe
public void testActivateThreadNoStackNoRegsEmpty() throws Exception { public void testActivateThreadNoStackNoRegsEmpty() throws Exception {
createAndOpenTrace(); createAndOpenTrace();
TraceThread thread = addThread("Thread 1"); TraceThread thread = addThread("Processes[1].Threads[1]");
waitForDomainObject(tb.trace); waitForDomainObject(tb.trace);
traceManager.activateThread(thread); traceManager.activateThread(thread);
@ -168,7 +168,7 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerGUITe
public void testActivateThreadNoStackRegsSynthetic() throws Exception { public void testActivateThreadNoStackRegsSynthetic() throws Exception {
createAndOpenTrace(); createAndOpenTrace();
TraceThread thread = addThread("Thread 1"); TraceThread thread = addThread("Processes[1].Threads[1]");
addRegVals(thread); addRegVals(thread);
waitForDomainObject(tb.trace); waitForDomainObject(tb.trace);
@ -182,7 +182,7 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerGUITe
public void testActivateThreadRegsThenAddEmptyStackEmpty() throws Exception { public void testActivateThreadRegsThenAddEmptyStackEmpty() throws Exception {
createAndOpenTrace(); createAndOpenTrace();
TraceThread thread = addThread("Thread 1"); TraceThread thread = addThread("Processes[1].Threads[1]");
addRegVals(thread); addRegVals(thread);
addStack(thread); addStack(thread);
waitForDomainObject(tb.trace); waitForDomainObject(tb.trace);
@ -197,7 +197,7 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerGUITe
public void testActivateThreadThenAddStackPopulatesProvider() throws Exception { public void testActivateThreadThenAddStackPopulatesProvider() throws Exception {
createAndOpenTrace(); createAndOpenTrace();
TraceThread thread = addThread("Thread 1"); TraceThread thread = addThread("Processes[1].Threads[1]");
traceManager.activateThread(thread); traceManager.activateThread(thread);
TraceStack stack = addStack(thread); TraceStack stack = addStack(thread);
addStackFrames(stack); addStackFrames(stack);
@ -210,7 +210,7 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerGUITe
public void testAddStackThenActivateThreadPopulatesProvider() throws Exception { public void testAddStackThenActivateThreadPopulatesProvider() throws Exception {
createAndOpenTrace(); createAndOpenTrace();
TraceThread thread = addThread("Thread 1"); TraceThread thread = addThread("Processes[1].Threads[1]");
TraceStack stack = addStack(thread); TraceStack stack = addStack(thread);
addStackFrames(stack); addStackFrames(stack);
waitForDomainObject(tb.trace); waitForDomainObject(tb.trace);
@ -225,7 +225,7 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerGUITe
public void testAppendStackUpdatesProvider() throws Exception { public void testAppendStackUpdatesProvider() throws Exception {
createAndOpenTrace(); createAndOpenTrace();
TraceThread thread = addThread("Thread 1"); TraceThread thread = addThread("Processes[1].Threads[1]");
TraceStack stack = addStack(thread); TraceStack stack = addStack(thread);
addStackFrames(stack); addStackFrames(stack);
waitForDomainObject(tb.trace); waitForDomainObject(tb.trace);
@ -250,7 +250,7 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerGUITe
public void testPushStackUpdatesProvider() throws Exception { public void testPushStackUpdatesProvider() throws Exception {
createAndOpenTrace(); createAndOpenTrace();
TraceThread thread = addThread("Thread 1"); TraceThread thread = addThread("Processes[1].Threads[1]");
TraceStack stack = addStack(thread); TraceStack stack = addStack(thread);
addStackFrames(stack); addStackFrames(stack);
waitForDomainObject(tb.trace); waitForDomainObject(tb.trace);
@ -275,7 +275,7 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerGUITe
public void testTruncateStackUpdatesProvider() throws Exception { public void testTruncateStackUpdatesProvider() throws Exception {
createAndOpenTrace(); createAndOpenTrace();
TraceThread thread = addThread("Thread 1"); TraceThread thread = addThread("Processes[1].Threads[1]");
TraceStack stack = addStack(thread); TraceStack stack = addStack(thread);
addStackFrames(stack); addStackFrames(stack);
waitForDomainObject(tb.trace); waitForDomainObject(tb.trace);
@ -298,7 +298,7 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerGUITe
public void testPopStackUpdatesProvider() throws Exception { public void testPopStackUpdatesProvider() throws Exception {
createAndOpenTrace(); createAndOpenTrace();
TraceThread thread = addThread("Thread 1"); TraceThread thread = addThread("Processes[1].Threads[1]");
TraceStack stack = addStack(thread); TraceStack stack = addStack(thread);
addStackFrames(stack); addStackFrames(stack);
waitForDomainObject(tb.trace); waitForDomainObject(tb.trace);
@ -321,7 +321,7 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerGUITe
public void testDeleteStackUpdatesProvider() throws Exception { public void testDeleteStackUpdatesProvider() throws Exception {
createAndOpenTrace(); createAndOpenTrace();
TraceThread thread = addThread("Thread 1"); TraceThread thread = addThread("Processes[1].Threads[1]");
TraceStack stack = addStack(thread); TraceStack stack = addStack(thread);
addStackFrames(stack); addStackFrames(stack);
waitForDomainObject(tb.trace); waitForDomainObject(tb.trace);
@ -343,8 +343,8 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerGUITe
public void testActivateOtherThread() throws Exception { public void testActivateOtherThread() throws Exception {
createAndOpenTrace(); createAndOpenTrace();
TraceThread thread1 = addThread("Thread 1"); TraceThread thread1 = addThread("Processes[1].Threads[1]");
TraceThread thread2 = addThread("Thread 2"); TraceThread thread2 = addThread("Processes[1].Threads[2]");
TraceStack stack = addStack(thread1); TraceStack stack = addStack(thread1);
addStackFrames(stack); addStackFrames(stack);
waitForDomainObject(tb.trace); waitForDomainObject(tb.trace);
@ -364,7 +364,7 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerGUITe
public void testActivateSnap() throws Exception { public void testActivateSnap() throws Exception {
createAndOpenTrace(); createAndOpenTrace();
TraceThread thread = addThread("Thread 1"); TraceThread thread = addThread("Processes[1].Threads[1]");
TraceStack stack = addStack(thread); TraceStack stack = addStack(thread);
addStackFrames(stack); addStackFrames(stack);
waitForDomainObject(tb.trace); waitForDomainObject(tb.trace);
@ -389,7 +389,7 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerGUITe
public void testCloseCurrentTraceEmpty() throws Exception { public void testCloseCurrentTraceEmpty() throws Exception {
createAndOpenTrace(); createAndOpenTrace();
TraceThread thread = addThread("Thread 1"); TraceThread thread = addThread("Processes[1].Threads[1]");
TraceStack stack = addStack(thread); TraceStack stack = addStack(thread);
addStackFrames(stack); addStackFrames(stack);
waitForDomainObject(tb.trace); waitForDomainObject(tb.trace);
@ -410,7 +410,7 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerGUITe
public void testSelectRowActivatesFrame() throws Exception { public void testSelectRowActivatesFrame() throws Exception {
createAndOpenTrace(); createAndOpenTrace();
TraceThread thread = addThread("Thread 1"); TraceThread thread = addThread("Processes[1].Threads[1]");
TraceStack stack = addStack(thread); TraceStack stack = addStack(thread);
addStackFrames(stack); addStackFrames(stack);
waitForDomainObject(tb.trace); waitForDomainObject(tb.trace);
@ -435,7 +435,7 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerGUITe
public void testActivateFrameSelectsRow() throws Exception { public void testActivateFrameSelectsRow() throws Exception {
createAndOpenTrace(); createAndOpenTrace();
TraceThread thread = addThread("Thread 1"); TraceThread thread = addThread("Processes[1].Threads[1]");
TraceStack stack = addStack(thread); TraceStack stack = addStack(thread);
addStackFrames(stack); addStackFrames(stack);
waitForDomainObject(tb.trace); waitForDomainObject(tb.trace);
@ -467,7 +467,7 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerGUITe
traceManager.openTrace(tb.trace); traceManager.openTrace(tb.trace);
programManager.openProgram(program); programManager.openProgram(program);
TraceThread thread = addThread("Thread 1"); TraceThread thread = addThread("Processes[1].Threads[1]");
TraceStack stack = addStack(thread); TraceStack stack = addStack(thread);
addStackFrames(stack); addStackFrames(stack);
waitForDomainObject(tb.trace); waitForDomainObject(tb.trace);
@ -491,7 +491,8 @@ public class DebuggerStackProviderTest extends AbstractGhidraHeadedDebuggerGUITe
try (UndoableTransaction tid = tb.startTransaction()) { try (UndoableTransaction tid = tb.startTransaction()) {
tb.trace.getMemoryManager() 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); TraceMemoryFlag.READ, TraceMemoryFlag.EXECUTE);
TraceLocation dloc = TraceLocation dloc =

View file

@ -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")));
}
}
}

View file

@ -55,9 +55,9 @@ public class DebuggerThreadsProviderTest extends AbstractGhidraHeadedDebuggerGUI
protected void addThreads() throws Exception { protected void addThreads() throws Exception {
TraceThreadManager manager = tb.trace.getThreadManager(); TraceThreadManager manager = tb.trace.getThreadManager();
try (UndoableTransaction tid = tb.startTransaction()) { 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"); 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"); thread2.setComment("Another comment");
} }
} }
@ -99,7 +99,7 @@ public class DebuggerThreadsProviderTest extends AbstractGhidraHeadedDebuggerGUI
ThreadRow thread1Record = threadsDisplayed.get(0); ThreadRow thread1Record = threadsDisplayed.get(0);
assertEquals(thread1, thread1Record.getThread()); assertEquals(thread1, thread1Record.getThread());
assertEquals("Thread 1", thread1Record.getName()); assertEquals("Processes[1].Threads[1]", thread1Record.getName());
assertEquals(Range.atLeast(0L), thread1Record.getLifespan()); assertEquals(Range.atLeast(0L), thread1Record.getLifespan());
assertEquals(0, thread1Record.getCreationSnap()); assertEquals(0, thread1Record.getCreationSnap());
assertEquals("", thread1Record.getDestructionSnap()); assertEquals("", thread1Record.getDestructionSnap());
@ -475,13 +475,15 @@ public class DebuggerThreadsProviderTest extends AbstractGhidraHeadedDebuggerGUI
// Not live, so no seek // Not live, so no seek
assertEquals(0, traceManager.getCurrentSnap()); assertEquals(0, traceManager.getCurrentSnap());
tb.close();
createTestModel(); createTestModel();
mb.createTestProcessesAndThreads(); mb.createTestProcessesAndThreads();
// Threads needs registers to be recognized by the recorder // Threads needs registers to be recognized by the recorder
mb.createTestThreadRegisterBanks(); mb.createTestThreadRegisterBanks();
TraceRecorder recorder = modelService.recordTargetAndActivateTrace(mb.testProcess1, TraceRecorder recorder = modelService.recordTargetAndActivateTrace(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
Trace trace = recorder.getTrace(); Trace trace = recorder.getTrace();
// Wait till two threads are observed in the database // Wait till two threads are observed in the database

View file

@ -208,7 +208,7 @@ public class DebuggerWatchesProviderTest extends AbstractGhidraHeadedDebuggerGUI
mb.testProcess1.memory.writeMemory(mb.addr(0x00400000), tb.arr(1, 2, 3, 4)); mb.testProcess1.memory.writeMemory(mb.addr(0x00400000), tb.arr(1, 2, 3, 4));
recorder = modelService.recordTarget(mb.testProcess1, recorder = modelService.recordTarget(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
Trace trace = recorder.getTrace(); Trace trace = recorder.getTrace();
TraceThread thread = waitForValue(() -> recorder.getTraceThread(mb.testThread1)); 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"); mb.testProcess1.addRegion(".text", mb.rng(0x00400000, 0x00401000), "rx");
recorder = modelService.recordTarget(mb.testProcess1, recorder = modelService.recordTarget(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
Trace trace = recorder.getTrace(); Trace trace = recorder.getTrace();
TraceThread thread = waitForValue(() -> recorder.getTraceThread(mb.testThread1)); TraceThread thread = waitForValue(() -> recorder.getTraceThread(mb.testThread1));

View file

@ -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")));
}
}
}

View file

@ -74,7 +74,8 @@ public class DebuggerLogicalBreakpointServiceTest extends AbstractGhidraHeadedDe
@Override @Override
public synchronized void breakpointUpdated(LogicalBreakpoint lb) { 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)); assertTrue(current.contains(lb));
} }
@ -165,12 +166,12 @@ public class DebuggerLogicalBreakpointServiceTest extends AbstractGhidraHeadedDe
public void startRecorder1() throws Throwable { public void startRecorder1() throws Throwable {
recorder1 = modelService.recordTarget(mb.testProcess1, recorder1 = modelService.recordTarget(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
} }
public void startRecorder3() throws Throwable { public void startRecorder3() throws Throwable {
recorder3 = modelService.recordTarget(mb.testProcess3, recorder3 = modelService.recordTarget(mb.testProcess3,
new TestDebuggerTargetTraceMapper(mb.testProcess3)); createTargetTraceMapper(mb.testProcess3));
} }
@After @After

View file

@ -213,7 +213,7 @@ public class DebuggerModelServiceTest extends AbstractGhidraHeadedDebuggerGUITes
assertEquals(Set.of(), Set.copyOf(modelService.getTraceRecorders())); assertEquals(Set.of(), Set.copyOf(modelService.getTraceRecorders()));
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1, TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
assertEquals(Set.of(recorder), Set.copyOf(modelService.getTraceRecorders())); assertEquals(Set.of(recorder), Set.copyOf(modelService.getTraceRecorders()));
} }
@ -228,7 +228,7 @@ public class DebuggerModelServiceTest extends AbstractGhidraHeadedDebuggerGUITes
new CollectionChangeDelegateWrapper<>(recorderChangeListener); new CollectionChangeDelegateWrapper<>(recorderChangeListener);
modelService.addTraceRecordersChangedListener(wrapper); modelService.addTraceRecordersChangedListener(wrapper);
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1, TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
new VerificationsInOrder() { new VerificationsInOrder() {
{ {
@ -243,7 +243,7 @@ public class DebuggerModelServiceTest extends AbstractGhidraHeadedDebuggerGUITes
mb.createTestProcessesAndThreads(); mb.createTestProcessesAndThreads();
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1, TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
// Strong ref // Strong ref
CollectionChangeDelegateWrapper<TraceRecorder> wrapper = CollectionChangeDelegateWrapper<TraceRecorder> wrapper =
new CollectionChangeDelegateWrapper<>(recorderChangeListener); new CollectionChangeDelegateWrapper<>(recorderChangeListener);
@ -265,7 +265,7 @@ public class DebuggerModelServiceTest extends AbstractGhidraHeadedDebuggerGUITes
mb.createTestProcessesAndThreads(); mb.createTestProcessesAndThreads();
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1, TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
assertNotNull(recorder); assertNotNull(recorder);
waitOn(recorder.init()); // Already initializing, just wait for it to complete waitOn(recorder.init()); // Already initializing, just wait for it to complete
@ -281,7 +281,7 @@ public class DebuggerModelServiceTest extends AbstractGhidraHeadedDebuggerGUITes
mb.createTestProcessesAndThreads(); mb.createTestProcessesAndThreads();
modelService.recordTargetAndActivateTrace(mb.testProcess1, modelService.recordTargetAndActivateTrace(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
waitForSwing(); waitForSwing();
Trace trace = traceManager.getCurrentTrace(); Trace trace = traceManager.getCurrentTrace();
@ -290,7 +290,7 @@ public class DebuggerModelServiceTest extends AbstractGhidraHeadedDebuggerGUITes
traceManager.closeTrace(trace); traceManager.closeTrace(trace);
waitOn(mb.testModel.close()); waitOn(mb.testModel.close());
waitForPass(() -> { waitForPass(() -> {
assertEquals(List.of(), trace.getConsumerList()); assertEquals(List.of(tb), trace.getConsumerList());
}); });
} }
@ -300,7 +300,7 @@ public class DebuggerModelServiceTest extends AbstractGhidraHeadedDebuggerGUITes
mb.createTestProcessesAndThreads(); mb.createTestProcessesAndThreads();
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1, TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
assertEquals(recorder, modelService.getRecorder(mb.testProcess1)); assertEquals(recorder, modelService.getRecorder(mb.testProcess1));
} }
@ -311,7 +311,7 @@ public class DebuggerModelServiceTest extends AbstractGhidraHeadedDebuggerGUITes
mb.createTestProcessesAndThreads(); mb.createTestProcessesAndThreads();
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1, TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
assertEquals(recorder, modelService.getRecorder(recorder.getTrace())); assertEquals(recorder, modelService.getRecorder(recorder.getTrace()));
} }
@ -322,7 +322,7 @@ public class DebuggerModelServiceTest extends AbstractGhidraHeadedDebuggerGUITes
mb.createTestProcessesAndThreads(); mb.createTestProcessesAndThreads();
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1, TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
assertEquals(mb.testProcess1, modelService.getTarget(recorder.getTrace())); assertEquals(mb.testProcess1, modelService.getTarget(recorder.getTrace()));
} }
@ -333,7 +333,7 @@ public class DebuggerModelServiceTest extends AbstractGhidraHeadedDebuggerGUITes
mb.createTestProcessesAndThreads(); mb.createTestProcessesAndThreads();
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1, TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
assertEquals(recorder.getTrace(), modelService.getTrace(mb.testProcess1)); assertEquals(recorder.getTrace(), modelService.getTrace(mb.testProcess1));
} }
@ -344,7 +344,7 @@ public class DebuggerModelServiceTest extends AbstractGhidraHeadedDebuggerGUITes
mb.createTestProcessesAndThreads(); mb.createTestProcessesAndThreads();
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1, 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 // The most complicated case, lest I want another dimension in a cross product
mb.createTestThreadStacksAndFramesHaveRegisterBanks(); mb.createTestThreadStacksAndFramesHaveRegisterBanks();
@ -373,7 +373,7 @@ public class DebuggerModelServiceTest extends AbstractGhidraHeadedDebuggerGUITes
preRec.run(); preRec.run();
modelService.recordTarget(mb.testProcess1, modelService.recordTarget(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
postRec.run(); postRec.run();
@ -420,7 +420,7 @@ public class DebuggerModelServiceTest extends AbstractGhidraHeadedDebuggerGUITes
mb.createTestProcessesAndThreads(); mb.createTestProcessesAndThreads();
modelService.recordTarget(mb.testProcess1, modelService.recordTarget(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
// The most complicated case, lest I want another dimension in a cross product // The most complicated case, lest I want another dimension in a cross product
mb.createTestThreadStacksAndFramesHaveRegisterBanks(); mb.createTestThreadStacksAndFramesHaveRegisterBanks();
@ -439,9 +439,9 @@ public class DebuggerModelServiceTest extends AbstractGhidraHeadedDebuggerGUITes
// NOTE: getTargetFocus assumes the target is being recorded // NOTE: getTargetFocus assumes the target is being recorded
modelService.recordTarget(mb.testProcess1, modelService.recordTarget(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
modelService.recordTarget(mb.testProcess3, modelService.recordTarget(mb.testProcess3,
new TestDebuggerTargetTraceMapper(mb.testProcess3)); createTargetTraceMapper(mb.testProcess3));
assertNull(modelService.getTargetFocus(mb.testProcess1)); assertNull(modelService.getTargetFocus(mb.testProcess1));
assertNull(modelService.getTargetFocus(mb.testProcess3)); assertNull(modelService.getTargetFocus(mb.testProcess3));

View file

@ -48,7 +48,7 @@ public class DefaultTraceRecorderTest extends AbstractGhidraHeadedDebuggerGUITes
mb.createTestProcessesAndThreads(); mb.createTestProcessesAndThreads();
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1, TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
waitForPass(() -> { waitForPass(() -> {
assertNotNull(recorder.getTraceThread(mb.testThread1)); assertNotNull(recorder.getTraceThread(mb.testThread1));
assertNotNull(recorder.getTraceThread(mb.testThread2)); assertNotNull(recorder.getTraceThread(mb.testThread2));
@ -61,7 +61,7 @@ public class DefaultTraceRecorderTest extends AbstractGhidraHeadedDebuggerGUITes
mb.createTestProcessesAndThreads(); mb.createTestProcessesAndThreads();
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1, TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
Trace trace = recorder.getTrace(); Trace trace = recorder.getTrace();
TestTargetMemoryRegion targetRegion = TestTargetMemoryRegion targetRegion =
@ -97,7 +97,7 @@ public class DefaultTraceRecorderTest extends AbstractGhidraHeadedDebuggerGUITes
mb.createTestProcessesAndThreads(); mb.createTestProcessesAndThreads();
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1, TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
Trace trace = recorder.getTrace(); Trace trace = recorder.getTrace();
Language lang = trace.getBaseLanguage(); Language lang = trace.getBaseLanguage();
Register r0 = lang.getRegister("r0"); Register r0 = lang.getRegister("r0");
@ -131,7 +131,7 @@ public class DefaultTraceRecorderTest extends AbstractGhidraHeadedDebuggerGUITes
mb.createTestProcessesAndThreads(); mb.createTestProcessesAndThreads();
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1, TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
Trace trace = recorder.getTrace(); Trace trace = recorder.getTrace();
Language lang = trace.getBaseLanguage(); Language lang = trace.getBaseLanguage();
Register pc = lang.getRegister("pc"); Register pc = lang.getRegister("pc");
@ -180,7 +180,7 @@ public class DefaultTraceRecorderTest extends AbstractGhidraHeadedDebuggerGUITes
mb.createTestProcessesAndThreads(); mb.createTestProcessesAndThreads();
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1, TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
Trace trace = recorder.getTrace(); Trace trace = recorder.getTrace();
Language lang = trace.getBaseLanguage(); Language lang = trace.getBaseLanguage();
Register pc = lang.getRegister("pc"); Register pc = lang.getRegister("pc");
@ -229,7 +229,7 @@ public class DefaultTraceRecorderTest extends AbstractGhidraHeadedDebuggerGUITes
mb.createTestProcessesAndThreads(); mb.createTestProcessesAndThreads();
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1, TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
Trace trace = recorder.getTrace(); Trace trace = recorder.getTrace();
Language lang = trace.getBaseLanguage(); Language lang = trace.getBaseLanguage();
Register pc = lang.getRegister("pc"); Register pc = lang.getRegister("pc");

View file

@ -31,7 +31,6 @@ import ghidra.dbg.model.TestTargetStack;
import ghidra.dbg.model.TestTargetStackFrameHasRegisterBank; import ghidra.dbg.model.TestTargetStackFrameHasRegisterBank;
import ghidra.dbg.testutil.DebuggerModelTestUtils; import ghidra.dbg.testutil.DebuggerModelTestUtils;
import ghidra.framework.model.DomainFile; import ghidra.framework.model.DomainFile;
import ghidra.trace.database.thread.DBTraceThread;
import ghidra.trace.model.Trace; import ghidra.trace.model.Trace;
import ghidra.trace.model.stack.TraceStack; import ghidra.trace.model.stack.TraceStack;
import ghidra.trace.model.thread.TraceThread; import ghidra.trace.model.thread.TraceThread;
@ -116,7 +115,7 @@ public class DebuggerTraceManagerServiceTest extends AbstractGhidraHeadedDebugge
assertNull(traceManager.getCurrentThread()); assertNull(traceManager.getCurrentThread());
DBTraceThread thread; TraceThread thread;
try (UndoableTransaction tid = tb.startTransaction()) { try (UndoableTransaction tid = tb.startTransaction()) {
thread = tb.getOrAddThread("Thread 1", 0); thread = tb.getOrAddThread("Thread 1", 0);
} }
@ -297,7 +296,7 @@ public class DebuggerTraceManagerServiceTest extends AbstractGhidraHeadedDebugge
mb.createTestProcessesAndThreads(); mb.createTestProcessesAndThreads();
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1, TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
Trace trace = recorder.getTrace(); Trace trace = recorder.getTrace();
traceManager.openTrace(trace); traceManager.openTrace(trace);
@ -338,7 +337,7 @@ public class DebuggerTraceManagerServiceTest extends AbstractGhidraHeadedDebugge
mb.createTestProcessesAndThreads(); mb.createTestProcessesAndThreads();
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1, TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
Trace trace = recorder.getTrace(); Trace trace = recorder.getTrace();
waitForValue(() -> modelService.getTarget(trace)); waitForValue(() -> modelService.getTarget(trace));
@ -400,7 +399,7 @@ public class DebuggerTraceManagerServiceTest extends AbstractGhidraHeadedDebugge
mb.createTestProcessesAndThreads(); mb.createTestProcessesAndThreads();
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1, TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
Trace trace = recorder.getTrace(); Trace trace = recorder.getTrace();
traceManager.openTrace(trace); traceManager.openTrace(trace);

View file

@ -50,7 +50,7 @@ public class TraceRecorderAsyncPcodeExecTest extends AbstractGhidraHeadedDebugge
"r1", new byte[] { 6 }))); "r1", new byte[] { 6 })));
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1, TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
TraceThread thread = waitForValue(() -> recorder.getTraceThread(mb.testThread1)); TraceThread thread = waitForValue(() -> recorder.getTraceThread(mb.testThread1));
Trace trace = recorder.getTrace(); Trace trace = recorder.getTrace();
@ -93,7 +93,7 @@ public class TraceRecorderAsyncPcodeExecTest extends AbstractGhidraHeadedDebugge
"r1", new byte[] { 6 }))); "r1", new byte[] { 6 })));
TraceRecorder recorder = modelService.recordTarget(mb.testProcess1, TraceRecorder recorder = modelService.recordTarget(mb.testProcess1,
new TestDebuggerTargetTraceMapper(mb.testProcess1)); createTargetTraceMapper(mb.testProcess1));
TraceThread thread = waitForValue(() -> recorder.getTraceThread(mb.testThread1)); TraceThread thread = waitForValue(() -> recorder.getTraceThread(mb.testThread1));
Trace trace = recorder.getTrace(); Trace trace = recorder.getTrace();

View file

@ -718,6 +718,17 @@ public interface TargetObjectSchema {
return null; 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) { default List<String> searchForAncestor(Class<? extends TargetObject> type, List<String> path) {
for (; path != null; path = PathUtils.parent(path)) { for (; path != null; path = PathUtils.parent(path)) {
TargetObjectSchema schema = getSuccessorSchema(path); TargetObjectSchema schema = getSuccessorSchema(path);

View file

@ -38,6 +38,23 @@ public class PathMatcher implements PathPredicates {
return String.format("<PathMatcher\n %s\n>", StringUtils.join(patterns, "\n ")); 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. * 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(); 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 @Override
public Set<String> getNextNames(List<String> path) { public Set<String> getNextNames(List<String> path) {
Set<String> result = new HashSet<>(); Set<String> result = new HashSet<>();
@ -111,10 +145,10 @@ public class PathMatcher implements PathPredicates {
} }
@Override @Override
public PathMatcher applyIndices(List<String> indices) { public PathMatcher applyKeys(List<String> indices) {
PathMatcher result = new PathMatcher(); PathMatcher result = new PathMatcher();
for (PathPattern pat : patterns) { for (PathPattern pat : patterns) {
result.addPattern(pat.applyIndices(indices)); result.addPattern(pat.applyKeys(indices));
} }
return result; return result;
} }

View file

@ -62,26 +62,33 @@ public class PathPattern implements PathPredicates {
return pattern.hashCode(); 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) { public static boolean isWildcard(String pat) {
return "[]".equals(pat) || "".equals(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) { protected boolean matchesUpTo(List<String> path, int length) {
for (int i = 0; i < length; i++) { 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; return false;
} }
} }
@ -144,11 +151,25 @@ public class PathPattern implements PathPredicates {
return this; 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 @Override
public Set<String> getNextNames(List<String> path) { public Set<String> getNextNames(List<String> path) {
if (path.size() >= pattern.size()) { if (path.size() >= pattern.size()) {
return Set.of(); return Set.of();
} }
if (!matchesUpTo(path, path.size())) {
return Set.of();
}
String pat = pattern.get(path.size()); String pat = pattern.get(path.size());
if (PathUtils.isName(pat)) { if (PathUtils.isName(pat)) {
return Set.of(pat); return Set.of(pat);
@ -161,6 +182,9 @@ public class PathPattern implements PathPredicates {
if (path.size() >= pattern.size()) { if (path.size() >= pattern.size()) {
return Set.of(); return Set.of();
} }
if (!matchesUpTo(path, path.size())) {
return Set.of();
}
String pat = pattern.get(path.size()); String pat = pattern.get(path.size());
if (PathUtils.isIndex(pat)) { if (PathUtils.isIndex(pat)) {
return Set.of(PathUtils.parseIndex(pat)); return Set.of(PathUtils.parseIndex(pat));
@ -174,7 +198,7 @@ public class PathPattern implements PathPredicates {
} }
@Override @Override
public PathPattern applyIndices(List<String> indices) { public PathPattern applyKeys(List<String> indices) {
List<String> result = new ArrayList<>(pattern.size()); List<String> result = new ArrayList<>(pattern.size());
Iterator<String> it = indices.iterator(); Iterator<String> it = indices.iterator();
for (String pat : pattern) { 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> * <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 * 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 * those keys matched by a wildcard are included in the result. Indices are extracted with the
* brackets {@code []} removed. * brackets {@code []} removed.
* *
* @param path the path to match * @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(); int length = pattern.size();
if (length != path.size()) { if (length != path.size()) {
return null; return null;
@ -216,7 +240,7 @@ public class PathPattern implements PathPredicates {
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
String pat = pattern.get(i); String pat = pattern.get(i);
String key = path.get(i); String key = path.get(i);
if (!keyMatches(pat, key)) { if (!PathPredicates.keyMatches(pat, key)) {
return null; return null;
} }
if (isWildcard(pat)) { if (isWildcard(pat)) {

View file

@ -23,6 +23,38 @@ import ghidra.dbg.target.TargetObject;
import ghidra.dbg.util.PathUtils.PathComparator; import ghidra.dbg.util.PathUtils.PathComparator;
public interface PathPredicates { 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 * Check if the entire path passes
* *
@ -59,10 +91,22 @@ public interface PathPredicates {
boolean ancestorMatches(List<String> path, boolean strict); 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> * <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 * @param path the ancestor path
* @return a set of patterns * @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 * Assuming a successor of path could match, get the patterns for the next possible index
* *
* <p> * <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 * @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); Set<String> getNextIndices(List<String> path);
@ -94,18 +139,6 @@ public interface PathPredicates {
*/ */
PathPattern getSingletonPattern(); 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) { default NavigableMap<List<String>, ?> getCachedValues(TargetObject seed) {
return getCachedValues(List.of(), seed); return getCachedValues(List.of(), seed);
} }
@ -259,10 +292,10 @@ public interface PathPredicates {
* @param indices the indices to substitute * @param indices the indices to substitute
* @return the pattern or matcher with the applied substitutions * @return the pattern or matcher with the applied substitutions
*/ */
PathPredicates applyIndices(List<String> indices); PathPredicates applyKeys(List<String> indices);
default PathPredicates applyIndices(String... indices) { default PathPredicates applyIndices(String... indices) {
return applyIndices(List.of(indices)); return applyKeys(List.of(indices));
} }
/** /**

View file

@ -25,6 +25,7 @@ dependencies {
api project(':Generic') api project(':Generic')
api project(':SoftwareModeling') api project(':SoftwareModeling')
api project(':ProposedUtils') api project(':ProposedUtils')
api project(':Framework-Debugging')
annotationProcessor project(':AnnotationValidator') annotationProcessor project(':AnnotationValidator')
testImplementation project(':Base') testImplementation project(':Base')

View file

@ -42,7 +42,6 @@ import ghidra.trace.database.language.DBTraceLanguageManager;
import ghidra.trace.database.listing.DBTraceCodeManager; import ghidra.trace.database.listing.DBTraceCodeManager;
import ghidra.trace.database.listing.DBTraceCommentAdapter; import ghidra.trace.database.listing.DBTraceCommentAdapter;
import ghidra.trace.database.memory.DBTraceMemoryManager; import ghidra.trace.database.memory.DBTraceMemoryManager;
import ghidra.trace.database.memory.DBTraceMemoryRegion;
import ghidra.trace.database.module.DBTraceModuleManager; import ghidra.trace.database.module.DBTraceModuleManager;
import ghidra.trace.database.module.DBTraceStaticMappingManager; import ghidra.trace.database.module.DBTraceStaticMappingManager;
import ghidra.trace.database.program.DBTraceProgramView; 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.property.DBTraceAddressPropertyManager;
import ghidra.trace.database.stack.DBTraceStackManager; import ghidra.trace.database.stack.DBTraceStackManager;
import ghidra.trace.database.symbol.*; import ghidra.trace.database.symbol.*;
import ghidra.trace.database.target.DBTraceObjectManager;
import ghidra.trace.database.thread.DBTraceThreadManager; import ghidra.trace.database.thread.DBTraceThreadManager;
import ghidra.trace.database.time.DBTraceTimeManager; import ghidra.trace.database.time.DBTraceTimeManager;
import ghidra.trace.model.Trace; import ghidra.trace.model.Trace;
import ghidra.trace.model.memory.TraceMemoryRegion;
import ghidra.trace.util.TraceChangeManager; import ghidra.trace.util.TraceChangeManager;
import ghidra.trace.util.TraceChangeRecord; import ghidra.trace.util.TraceChangeRecord;
import ghidra.util.*; import ghidra.util.*;
@ -104,6 +105,8 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
@DependentService @DependentService
protected DBTraceModuleManager moduleManager; protected DBTraceModuleManager moduleManager;
@DependentService @DependentService
protected DBTraceObjectManager objectManager;
@DependentService
protected DBTraceOverlaySpaceAdapter overlaySpaceAdapter; protected DBTraceOverlaySpaceAdapter overlaySpaceAdapter;
@DependentService @DependentService
protected DBTraceReferenceManager referenceManager; protected DBTraceReferenceManager referenceManager;
@ -340,6 +343,14 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
baseLanguage, this)); baseLanguage, this));
} }
@DependentService
protected DBTraceObjectManager createObjectManager()
throws CancelledException, IOException {
return createTraceManager("Object Manager",
(openMode, monitor) -> new DBTraceObjectManager(dbh, openMode, rwLock, monitor,
baseLanguage, this));
}
@DependentService @DependentService
protected DBTraceOverlaySpaceAdapter createOverlaySpaceAdapter() protected DBTraceOverlaySpaceAdapter createOverlaySpaceAdapter()
throws CancelledException, IOException { throws CancelledException, IOException {
@ -391,9 +402,11 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
} }
@DependentService @DependentService
protected DBTraceThreadManager createThreadManager() throws IOException, CancelledException { protected DBTraceThreadManager createThreadManager(DBTraceObjectManager objectManager)
throws IOException, CancelledException {
return createTraceManager("Thread Manager", return createTraceManager("Thread Manager",
(openMode, monitor) -> new DBTraceThreadManager(dbh, openMode, rwLock, monitor, this)); (openMode, monitor) -> new DBTraceThreadManager(dbh, openMode, rwLock, monitor, this,
objectManager));
} }
@DependentService @DependentService
@ -494,6 +507,11 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
return moduleManager; return moduleManager;
} }
@Override
public DBTraceObjectManager getObjectManager() {
return objectManager;
}
@Internal @Internal
public DBTraceOverlaySpaceAdapter getOverlaySpaceAdapter() { public DBTraceOverlaySpaceAdapter getOverlaySpaceAdapter() {
return overlaySpaceAdapter; 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)); allViews(v -> v.updateMemoryAddRegionBlock(region));
} }
public void updateViewsChangeRegionBlockName(DBTraceMemoryRegion region) { public void updateViewsChangeRegionBlockName(TraceMemoryRegion region) {
allViews(v -> v.updateMemoryChangeRegionBlockName(region)); allViews(v -> v.updateMemoryChangeRegionBlockName(region));
} }
public void updateViewsChangeRegionBlockFlags(DBTraceMemoryRegion region) { public void updateViewsChangeRegionBlockFlags(TraceMemoryRegion region, Range<Long> lifespan) {
allViews(v -> v.updateMemoryChangeRegionBlockFlags(region)); allViews(v -> v.updateMemoryChangeRegionBlockFlags(region, lifespan));
} }
public void updateViewsChangeRegionBlockRange(DBTraceMemoryRegion region, public void updateViewsChangeRegionBlockRange(TraceMemoryRegion region,
AddressRange oldRange, AddressRange newRange) { AddressRange oldRange, AddressRange newRange) {
allViews(v -> v.updateMemoryChangeRegionBlockRange(region, oldRange, newRange)); allViews(v -> v.updateMemoryChangeRegionBlockRange(region, oldRange, newRange));
} }
public void updateViewsChangeRegionBlockLifespan(DBTraceMemoryRegion region, public void updateViewsChangeRegionBlockLifespan(TraceMemoryRegion region,
Range<Long> oldLifespan, Range<Long> newLifespan) { Range<Long> oldLifespan, Range<Long> newLifespan) {
allViews(v -> v.updateMemoryChangeRegionBlockLifespan(region, oldLifespan, newLifespan)); allViews(v -> v.updateMemoryChangeRegionBlockLifespan(region, oldLifespan, newLifespan));
} }
public void updateViewsDeleteRegionBlock(DBTraceMemoryRegion region) { public void updateViewsDeleteRegionBlock(TraceMemoryRegion region) {
allViews(v -> v.updateMemoryDeleteRegionBlock(region)); allViews(v -> v.updateMemoryDeleteRegionBlock(region));
} }

View file

@ -19,13 +19,13 @@ import java.lang.reflect.Field;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Iterator; import java.util.*;
import java.util.Objects; import java.util.Map.Entry;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.stream.Collectors;
import com.google.common.collect.BoundType; import com.google.common.collect.*;
import com.google.common.collect.Range;
import db.*; import db.*;
import ghidra.program.model.address.*; 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) { public static long lowerEndpoint(Range<Long> range) {
if (!range.hasLowerBound()) { if (!range.hasLowerBound()) {
return Long.MIN_VALUE; return Long.MIN_VALUE;
@ -386,6 +535,16 @@ public enum DBTraceUtils {
lifespanSetter.accept(data, toRange(data.getY1(), lowerEndpoint(span) - 1)); 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") @SuppressWarnings("unchecked")
public static <T> Iterator<T> covariantIterator(Iterator<? extends T> it) { public static <T> Iterator<T> covariantIterator(Iterator<? extends T> it) {
// Iterators only support read and remove, not insert. Safe to cast. // Iterators only support read and remove, not insert. Safe to cast.

View file

@ -63,11 +63,7 @@ public class DBTraceOverlaySpaceAdapter implements DBTraceManager {
extends AbstractDBFieldCodec<Address, OT, BinaryField> { extends AbstractDBFieldCodec<Address, OT, BinaryField> {
static final Charset UTF8 = Charset.forName("UTF-8"); static final Charset UTF8 = Charset.forName("UTF-8");
public AddressDBFieldCodec(Class<OT> objectType, Field field, int column) { public static byte[] encode(Address address) {
super(Address.class, objectType, BinaryField.class, field, column);
}
protected byte[] encode(Address address) {
if (address == null) { if (address == null) {
return null; return null;
} }
@ -86,6 +82,31 @@ public class DBTraceOverlaySpaceAdapter implements DBTraceManager {
return buf.array(); 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 @Override
public void store(Address value, BinaryField f) { public void store(Address value, BinaryField f) {
f.setBinaryData(encode(value)); f.setBinaryData(encode(value));
@ -101,25 +122,7 @@ public class DBTraceOverlaySpaceAdapter implements DBTraceManager {
protected void doLoad(OT obj, DBRecord record) protected void doLoad(OT obj, DBRecord record)
throws IllegalArgumentException, IllegalAccessException { throws IllegalArgumentException, IllegalAccessException {
byte[] data = record.getBinaryData(column); byte[] data = record.getBinaryData(column);
if (data == null) { setValue(obj, decode(data, obj.getOverlaySpaceAdapter()));
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));
}
} }
} }

View file

@ -25,10 +25,10 @@ import ghidra.trace.database.DBTrace;
import ghidra.trace.database.DBTraceUtils; import ghidra.trace.database.DBTraceUtils;
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree; import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree;
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.AbstractDBTraceAddressSnapRangePropertyMapData; import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.AbstractDBTraceAddressSnapRangePropertyMapData;
import ghidra.trace.database.thread.DBTraceThread;
import ghidra.trace.model.Trace.TraceBookmarkChangeType; import ghidra.trace.model.Trace.TraceBookmarkChangeType;
import ghidra.trace.model.bookmark.TraceBookmark; import ghidra.trace.model.bookmark.TraceBookmark;
import ghidra.trace.model.bookmark.TraceBookmarkType; import ghidra.trace.model.bookmark.TraceBookmarkType;
import ghidra.trace.model.thread.TraceThread;
import ghidra.trace.util.TraceChangeRecord; import ghidra.trace.util.TraceChangeRecord;
import ghidra.util.LockHold; import ghidra.util.LockHold;
import ghidra.util.database.DBCachedObjectStore; import ghidra.util.database.DBCachedObjectStore;
@ -99,7 +99,7 @@ public class DBTraceBookmark extends AbstractDBTraceAddressSnapRangePropertyMapD
} }
@Override @Override
public DBTraceThread getThread() { public TraceThread getThread() {
return space.getThread(); return space.getThread();
} }

View file

@ -31,7 +31,6 @@ import ghidra.program.model.lang.Language;
import ghidra.trace.database.DBTrace; import ghidra.trace.database.DBTrace;
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery; import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery;
import ghidra.trace.database.space.*; import ghidra.trace.database.space.*;
import ghidra.trace.database.thread.DBTraceThread;
import ghidra.trace.database.thread.DBTraceThreadManager; import ghidra.trace.database.thread.DBTraceThreadManager;
import ghidra.trace.model.Trace.TraceBookmarkChangeType; import ghidra.trace.model.Trace.TraceBookmarkChangeType;
import ghidra.trace.model.bookmark.TraceBookmarkManager; import ghidra.trace.model.bookmark.TraceBookmarkManager;
@ -160,7 +159,7 @@ public class DBTraceBookmarkManager
protected static DBTraceSpaceKey unpackRegSpaceKey(AddressSpace space, protected static DBTraceSpaceKey unpackRegSpaceKey(AddressSpace space,
DBTraceThreadManager threadManager, long id) { DBTraceThreadManager threadManager, long id) {
long threadKey = unpackRegThread(id); long threadKey = unpackRegThread(id);
DBTraceThread thread = threadManager.getThread(threadKey); TraceThread thread = threadManager.getThread(threadKey);
assert thread != null; assert thread != null;
int frameLevel = unpackRegFrame(id); int frameLevel = unpackRegFrame(id);
return DBTraceSpaceKey.create(space, thread, frameLevel); return DBTraceSpaceKey.create(space, thread, frameLevel);
@ -186,7 +185,7 @@ public class DBTraceBookmarkManager
@Override @Override
protected DBTraceBookmarkRegisterSpace createRegisterSpace(AddressSpace space, 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()); return new DBTraceBookmarkRegisterSpace(this, space, thread, ent.getFrameLevel());
} }

View file

@ -18,24 +18,24 @@ package ghidra.trace.database.bookmark;
import java.io.IOException; import java.io.IOException;
import ghidra.program.model.address.AddressSpace; import ghidra.program.model.address.AddressSpace;
import ghidra.trace.database.thread.DBTraceThread;
import ghidra.trace.model.bookmark.TraceBookmarkRegisterSpace; import ghidra.trace.model.bookmark.TraceBookmarkRegisterSpace;
import ghidra.trace.model.thread.TraceThread;
import ghidra.util.exception.VersionException; import ghidra.util.exception.VersionException;
public class DBTraceBookmarkRegisterSpace extends DBTraceBookmarkSpace public class DBTraceBookmarkRegisterSpace extends DBTraceBookmarkSpace
implements TraceBookmarkRegisterSpace { implements TraceBookmarkRegisterSpace {
private final DBTraceThread thread; private final TraceThread thread;
private final int frameLevel; private final int frameLevel;
public DBTraceBookmarkRegisterSpace(DBTraceBookmarkManager manager, AddressSpace space, public DBTraceBookmarkRegisterSpace(DBTraceBookmarkManager manager, AddressSpace space,
DBTraceThread thread, int frameLevel) throws VersionException, IOException { TraceThread thread, int frameLevel) throws VersionException, IOException {
super(manager, space); super(manager, space);
this.thread = thread; this.thread = thread;
this.frameLevel = frameLevel; this.frameLevel = frameLevel;
} }
@Override @Override
public DBTraceThread getThread() { public TraceThread getThread() {
return thread; return thread;
} }

View file

@ -26,10 +26,10 @@ import ghidra.trace.database.DBTrace;
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapSpace; import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapSpace;
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery; import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery;
import ghidra.trace.database.space.DBTraceSpaceBased; import ghidra.trace.database.space.DBTraceSpaceBased;
import ghidra.trace.database.thread.DBTraceThread;
import ghidra.trace.model.Trace.TraceBookmarkChangeType; import ghidra.trace.model.Trace.TraceBookmarkChangeType;
import ghidra.trace.model.bookmark.TraceBookmarkSpace; import ghidra.trace.model.bookmark.TraceBookmarkSpace;
import ghidra.trace.model.bookmark.TraceBookmarkType; import ghidra.trace.model.bookmark.TraceBookmarkType;
import ghidra.trace.model.thread.TraceThread;
import ghidra.trace.util.TraceChangeRecord; import ghidra.trace.util.TraceChangeRecord;
import ghidra.util.LockHold; import ghidra.util.LockHold;
import ghidra.util.database.DBCachedObjectIndex; import ghidra.util.database.DBCachedObjectIndex;
@ -65,7 +65,7 @@ public class DBTraceBookmarkSpace implements TraceBookmarkSpace, DBTraceSpaceBas
} }
@Override @Override
public DBTraceThread getThread() { public TraceThread getThread() {
return null; return null;
} }

View file

@ -26,7 +26,6 @@ import ghidra.trace.database.DBTrace;
import ghidra.trace.database.DBTraceUtils; import ghidra.trace.database.DBTraceUtils;
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree; import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree;
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.AbstractDBTraceAddressSnapRangePropertyMapData; import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.AbstractDBTraceAddressSnapRangePropertyMapData;
import ghidra.trace.database.thread.DBTraceThread;
import ghidra.trace.database.thread.DBTraceThreadManager; import ghidra.trace.database.thread.DBTraceThreadManager;
import ghidra.trace.model.Trace.TraceBreakpointChangeType; import ghidra.trace.model.Trace.TraceBreakpointChangeType;
import ghidra.trace.model.breakpoint.TraceBreakpoint; import ghidra.trace.model.breakpoint.TraceBreakpoint;
@ -128,7 +127,7 @@ public class DBTraceBreakpoint
return this; 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) { Collection<TraceBreakpointKind> kinds, boolean enabled, String comment) {
// TODO: Check that the threads exist and that each's lifespan covers the breakpoint's // 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 // TODO: This would require additional validation any time those are updated
@ -140,7 +139,7 @@ public class DBTraceBreakpoint
} }
this.threadKeys = new long[threads.size()]; this.threadKeys = new long[threads.size()];
int i = 0; int i = 0;
for (DBTraceThread t : threads) { for (TraceThread t : threads) {
this.threadKeys[i++] = t.getKey(); this.threadKeys[i++] = t.getKey();
} }
this.flagsByte = 0; this.flagsByte = 0;
@ -386,7 +385,8 @@ public class DBTraceBreakpoint
} }
@Override @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())) { try (LockHold hold = LockHold.lock(space.lock.readLock())) {
return enabled; return enabled;
} }

View file

@ -30,7 +30,6 @@ import ghidra.trace.database.DBTrace;
import ghidra.trace.database.DBTraceUtils; import ghidra.trace.database.DBTraceUtils;
import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager; import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager;
import ghidra.trace.database.space.DBTraceDelegatingManager; import ghidra.trace.database.space.DBTraceDelegatingManager;
import ghidra.trace.database.thread.DBTraceThread;
import ghidra.trace.database.thread.DBTraceThreadManager; import ghidra.trace.database.thread.DBTraceThreadManager;
import ghidra.trace.model.breakpoint.*; import ghidra.trace.model.breakpoint.*;
import ghidra.trace.model.thread.TraceThread; import ghidra.trace.model.thread.TraceThread;
@ -60,7 +59,7 @@ public class DBTraceBreakpointManager
} }
@Override @Override
protected DBTraceBreakpointSpace createRegisterSpace(AddressSpace space, DBTraceThread thread, protected DBTraceBreakpointSpace createRegisterSpace(AddressSpace space, TraceThread thread,
DBTraceSpaceEntry ent) throws VersionException, IOException { DBTraceSpaceEntry ent) throws VersionException, IOException {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@ -80,9 +79,9 @@ public class DBTraceBreakpointManager
return lock.writeLock(); 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 { throws DuplicateNameException {
for (DBTraceBreakpoint pc : getBreakpointsByPath(path)) { for (TraceBreakpoint pc : getBreakpointsByPath(path)) {
if (pc == ignore) { if (pc == ignore) {
continue; continue;
} }
@ -98,23 +97,38 @@ public class DBTraceBreakpointManager
public TraceBreakpoint addBreakpoint(String path, Range<Long> lifespan, AddressRange range, public TraceBreakpoint addBreakpoint(String path, Range<Long> lifespan, AddressRange range,
Collection<TraceThread> threads, Collection<TraceBreakpointKind> kinds, boolean enabled, Collection<TraceThread> threads, Collection<TraceBreakpointKind> kinds, boolean enabled,
String comment) throws DuplicateNameException { String comment) throws DuplicateNameException {
if (trace.getObjectManager().hasSchema()) {
return trace.getObjectManager()
.addBreakpoint(path, lifespan, range, threads, kinds, enabled, comment);
}
checkDuplicatePath(null, path, lifespan); checkDuplicatePath(null, path, lifespan);
return delegateWrite(range.getAddressSpace(), return delegateWrite(range.getAddressSpace(),
m -> m.addBreakpoint(path, lifespan, range, threads, kinds, enabled, comment)); m -> m.addBreakpoint(path, lifespan, range, threads, kinds, enabled, comment));
} }
@Override @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()); return delegateCollection(getActiveMemorySpaces(), m -> m.getAllBreakpoints());
} }
@Override @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)); return delegateCollection(getActiveMemorySpaces(), m -> m.getBreakpointsByPath(path));
} }
@Override @Override
public TraceBreakpoint getPlacedBreakpointByPath(long snap, String path) { 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())) { try (LockHold hold = LockHold.lock(lock.readLock())) {
return getBreakpointsByPath(path) return getBreakpointsByPath(path)
.stream() .stream()
@ -125,14 +139,24 @@ public class DBTraceBreakpointManager
} }
@Override @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), return delegateRead(address.getAddressSpace(), m -> m.getBreakpointsAt(snap, address),
Collections.emptyList()); Collections.emptyList());
} }
@Override @Override
public Collection<? extends DBTraceBreakpoint> getBreakpointsIntersecting(Range<Long> span, public Collection<? extends TraceBreakpoint> getBreakpointsIntersecting(Range<Long> span,
AddressRange range) { 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), return delegateRead(range.getAddressSpace(), m -> m.getBreakpointsIntersecting(span, range),
Collections.emptyList()); Collections.emptyList());
} }

View file

@ -99,11 +99,9 @@ public class DBTraceBreakpointSpace implements DBTraceSpaceBased {
for (TraceThread t : threads) { for (TraceThread t : threads) {
threadManager.assertIsMine(t); threadManager.assertIsMine(t);
} }
@SuppressWarnings({ "rawtypes", "unchecked" }) // checked by above assertIsMine
Collection<DBTraceThread> dbThreads = (Collection) threads;
DBTraceBreakpoint breakpoint = DBTraceBreakpoint breakpoint =
breakpointMapSpace.put(new ImmutableTraceAddressSnapRange(range, lifespan), null); 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( trace.setChanged(
new TraceChangeRecord<>(TraceBreakpointChangeType.ADDED, this, breakpoint)); new TraceChangeRecord<>(TraceBreakpointChangeType.ADDED, this, breakpoint));
return breakpoint; return breakpoint;

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -36,7 +36,6 @@ import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree;
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.AbstractDBTraceAddressSnapRangePropertyMapData; import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.AbstractDBTraceAddressSnapRangePropertyMapData;
import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager; import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager;
import ghidra.trace.database.space.DBTraceDelegatingManager; import ghidra.trace.database.space.DBTraceDelegatingManager;
import ghidra.trace.database.thread.DBTraceThread;
import ghidra.trace.database.thread.DBTraceThreadManager; import ghidra.trace.database.thread.DBTraceThreadManager;
import ghidra.trace.model.TraceAddressSnapRange; import ghidra.trace.model.TraceAddressSnapRange;
import ghidra.trace.model.context.TraceRegisterContextManager; import ghidra.trace.model.context.TraceRegisterContextManager;
@ -106,7 +105,7 @@ public class DBTraceRegisterContextManager extends
@Override @Override
protected DBTraceRegisterContextRegisterSpace createRegisterSpace(AddressSpace space, 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? // 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); return new DBTraceRegisterContextRegisterSpace(this, dbh, space, ent, thread);
} }

View file

@ -20,17 +20,17 @@ import java.io.IOException;
import db.DBHandle; import db.DBHandle;
import ghidra.program.model.address.AddressSpace; import ghidra.program.model.address.AddressSpace;
import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager.DBTraceSpaceEntry; import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager.DBTraceSpaceEntry;
import ghidra.trace.database.thread.DBTraceThread;
import ghidra.trace.model.context.TraceRegisterContextRegisterSpace; import ghidra.trace.model.context.TraceRegisterContextRegisterSpace;
import ghidra.trace.model.thread.TraceThread;
import ghidra.util.exception.VersionException; import ghidra.util.exception.VersionException;
public class DBTraceRegisterContextRegisterSpace extends DBTraceRegisterContextSpace public class DBTraceRegisterContextRegisterSpace extends DBTraceRegisterContextSpace
implements TraceRegisterContextRegisterSpace { implements TraceRegisterContextRegisterSpace {
private final DBTraceThread thread; private final TraceThread thread;
private final int frameLevel; private final int frameLevel;
public DBTraceRegisterContextRegisterSpace(DBTraceRegisterContextManager manager, DBHandle dbh, public DBTraceRegisterContextRegisterSpace(DBTraceRegisterContextManager manager, DBHandle dbh,
AddressSpace space, DBTraceSpaceEntry ent, DBTraceThread thread) AddressSpace space, DBTraceSpaceEntry ent, TraceThread thread)
throws VersionException, IOException { throws VersionException, IOException {
super(manager, dbh, space, ent); super(manager, dbh, space, ent);
this.thread = thread; this.thread = thread;
@ -38,7 +38,7 @@ public class DBTraceRegisterContextRegisterSpace extends DBTraceRegisterContextS
} }
@Override @Override
public DBTraceThread getThread() { public TraceThread getThread() {
return thread; return thread;
} }

View file

@ -37,10 +37,10 @@ import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapSpace;
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery; import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery;
import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager.DBTraceSpaceEntry; import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager.DBTraceSpaceEntry;
import ghidra.trace.database.space.DBTraceSpaceBased; import ghidra.trace.database.space.DBTraceSpaceBased;
import ghidra.trace.database.thread.DBTraceThread;
import ghidra.trace.model.ImmutableTraceAddressSnapRange; import ghidra.trace.model.ImmutableTraceAddressSnapRange;
import ghidra.trace.model.TraceAddressSnapRange; import ghidra.trace.model.TraceAddressSnapRange;
import ghidra.trace.model.context.TraceRegisterContextSpace; import ghidra.trace.model.context.TraceRegisterContextSpace;
import ghidra.trace.model.thread.TraceThread;
import ghidra.util.LockHold; import ghidra.util.LockHold;
import ghidra.util.database.*; import ghidra.util.database.*;
import ghidra.util.database.annot.*; import ghidra.util.database.annot.*;
@ -126,12 +126,12 @@ public class DBTraceRegisterContextSpace implements TraceRegisterContextSpace, D
} }
@Override @Override
public DBTraceThread getThread() { public TraceThread getThread() {
return null; return null;
} }
protected long getThreadKey() { protected long getThreadKey() {
DBTraceThread thread = getThread(); TraceThread thread = getThread();
return thread == null ? -1 : thread.getKey(); return thread == null ? -1 : thread.getKey();
} }

View file

@ -29,7 +29,6 @@ import ghidra.trace.database.DBTraceUtils;
import ghidra.trace.database.data.DBTraceDataSettingsAdapter.DBTraceSettingsEntry; import ghidra.trace.database.data.DBTraceDataSettingsAdapter.DBTraceSettingsEntry;
import ghidra.trace.database.map.*; import ghidra.trace.database.map.*;
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.AbstractDBTraceAddressSnapRangePropertyMapData; import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.AbstractDBTraceAddressSnapRangePropertyMapData;
import ghidra.trace.database.thread.DBTraceThread;
import ghidra.trace.database.thread.DBTraceThreadManager; import ghidra.trace.database.thread.DBTraceThreadManager;
import ghidra.trace.model.thread.TraceThread; import ghidra.trace.model.thread.TraceThread;
import ghidra.trace.util.TraceAddressSpace; import ghidra.trace.util.TraceAddressSpace;
@ -183,7 +182,7 @@ public class DBTraceDataSettingsAdapter
implements DBTraceDataSettingsOperations { implements DBTraceDataSettingsOperations {
public DBTraceDataSettingsRegisterSpace(String tableName, public DBTraceDataSettingsRegisterSpace(String tableName,
DBCachedObjectStoreFactory storeFactory, ReadWriteLock lock, AddressSpace space, DBCachedObjectStoreFactory storeFactory, ReadWriteLock lock, AddressSpace space,
DBTraceThread thread, int frameLevel, Class<DBTraceSettingsEntry> dataType, TraceThread thread, int frameLevel, Class<DBTraceSettingsEntry> dataType,
DBTraceAddressSnapRangePropertyMapDataFactory<DBTraceSettingsEntry, DBTraceSettingsEntry> dataFactory) DBTraceAddressSnapRangePropertyMapDataFactory<DBTraceSettingsEntry, DBTraceSettingsEntry> dataFactory)
throws VersionException, IOException { throws VersionException, IOException {
super(tableName, storeFactory, lock, space, thread, frameLevel, dataType, dataFactory); super(tableName, storeFactory, lock, space, thread, frameLevel, dataType, dataFactory);
@ -217,7 +216,7 @@ public class DBTraceDataSettingsAdapter
@Override @Override
protected DBTraceAddressSnapRangePropertyMapRegisterSpace<DBTraceSettingsEntry, DBTraceSettingsEntry> createRegisterSpace( protected DBTraceAddressSnapRangePropertyMapRegisterSpace<DBTraceSettingsEntry, DBTraceSettingsEntry> createRegisterSpace(
AddressSpace space, DBTraceThread thread, DBTraceSpaceEntry ent) AddressSpace space, TraceThread thread, DBTraceSpaceEntry ent)
throws VersionException, IOException { throws VersionException, IOException {
return new DBTraceDataSettingsRegisterSpace( return new DBTraceDataSettingsRegisterSpace(
tableName(space, ent.getThreadKey(), ent.getFrameLevel()), tableName(space, ent.getThreadKey(), ent.getFrameLevel()),

View file

@ -46,7 +46,6 @@ import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAdd
import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager; import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager;
import ghidra.trace.database.space.DBTraceDelegatingManager; import ghidra.trace.database.space.DBTraceDelegatingManager;
import ghidra.trace.database.symbol.DBTraceReferenceManager; import ghidra.trace.database.symbol.DBTraceReferenceManager;
import ghidra.trace.database.thread.DBTraceThread;
import ghidra.trace.database.thread.DBTraceThreadManager; import ghidra.trace.database.thread.DBTraceThreadManager;
import ghidra.trace.model.AddressSnap; import ghidra.trace.model.AddressSnap;
import ghidra.trace.model.DefaultAddressSnap; import ghidra.trace.model.DefaultAddressSnap;
@ -222,7 +221,7 @@ public class DBTraceCodeManager
// Internal // Internal
public UndefinedDBTraceData doCreateUndefinedUnit(long snap, Address address, public UndefinedDBTraceData doCreateUndefinedUnit(long snap, Address address,
DBTraceThread thread, int frameLevel) { TraceThread thread, int frameLevel) {
return undefinedCache.computeIfAbsent(new DefaultAddressSnap(address, snap), return undefinedCache.computeIfAbsent(new DefaultAddressSnap(address, snap),
ot -> new UndefinedDBTraceData(trace, snap, address, thread, frameLevel)); ot -> new UndefinedDBTraceData(trace, snap, address, thread, frameLevel));
} }
@ -279,7 +278,7 @@ public class DBTraceCodeManager
} }
@Override @Override
protected DBTraceCodeRegisterSpace createRegisterSpace(AddressSpace space, DBTraceThread thread, protected DBTraceCodeRegisterSpace createRegisterSpace(AddressSpace space, TraceThread thread,
DBTraceSpaceEntry ent) throws VersionException, IOException { DBTraceSpaceEntry ent) throws VersionException, IOException {
return new DBTraceCodeRegisterSpace(this, dbh, space, ent, thread); return new DBTraceCodeRegisterSpace(this, dbh, space, ent, thread);
} }

View file

@ -20,23 +20,23 @@ import java.io.IOException;
import db.DBHandle; import db.DBHandle;
import ghidra.program.model.address.AddressSpace; import ghidra.program.model.address.AddressSpace;
import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager.DBTraceSpaceEntry; import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager.DBTraceSpaceEntry;
import ghidra.trace.database.thread.DBTraceThread;
import ghidra.trace.model.listing.TraceCodeRegisterSpace; import ghidra.trace.model.listing.TraceCodeRegisterSpace;
import ghidra.trace.model.thread.TraceThread;
import ghidra.util.exception.VersionException; import ghidra.util.exception.VersionException;
public class DBTraceCodeRegisterSpace extends DBTraceCodeSpace implements TraceCodeRegisterSpace { public class DBTraceCodeRegisterSpace extends DBTraceCodeSpace implements TraceCodeRegisterSpace {
protected final DBTraceThread thread; protected final TraceThread thread;
private final int frameLevel; private final int frameLevel;
public DBTraceCodeRegisterSpace(DBTraceCodeManager manager, DBHandle dbh, AddressSpace space, 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); super(manager, dbh, space, ent);
this.thread = thread; this.thread = thread;
this.frameLevel = ent.getFrameLevel(); this.frameLevel = ent.getFrameLevel();
} }
@Override @Override
public DBTraceThread getThread() { public TraceThread getThread() {
return thread; return thread;
} }

View file

@ -37,9 +37,9 @@ import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAdd
import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager.DBTraceSpaceEntry; import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager.DBTraceSpaceEntry;
import ghidra.trace.database.space.DBTraceSpaceBased; import ghidra.trace.database.space.DBTraceSpaceBased;
import ghidra.trace.database.symbol.DBTraceReferenceManager; import ghidra.trace.database.symbol.DBTraceReferenceManager;
import ghidra.trace.database.thread.DBTraceThread;
import ghidra.trace.model.TraceAddressSnapRange; import ghidra.trace.model.TraceAddressSnapRange;
import ghidra.trace.model.listing.TraceCodeSpace; import ghidra.trace.model.listing.TraceCodeSpace;
import ghidra.trace.model.thread.TraceThread;
import ghidra.trace.util.ByteArrayUtils; import ghidra.trace.util.ByteArrayUtils;
import ghidra.util.LockHold; import ghidra.util.LockHold;
import ghidra.util.database.DBCachedObjectStoreFactory; import ghidra.util.database.DBCachedObjectStoreFactory;
@ -169,7 +169,7 @@ public class DBTraceCodeSpace implements TraceCodeSpace, DBTraceSpaceBased {
} }
@Override @Override
public DBTraceThread getThread() { public TraceThread getThread() {
return null; return null;
} }

View file

@ -32,10 +32,10 @@ import ghidra.program.model.mem.Memory;
import ghidra.program.model.mem.MemoryAccessException; import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.symbol.*; import ghidra.program.model.symbol.*;
import ghidra.trace.database.DBTrace; import ghidra.trace.database.DBTrace;
import ghidra.trace.database.memory.DBTraceMemoryRegion;
import ghidra.trace.database.symbol.DBTraceReference; import ghidra.trace.database.symbol.DBTraceReference;
import ghidra.trace.model.listing.TraceCodeUnit; import ghidra.trace.model.listing.TraceCodeUnit;
import ghidra.trace.model.map.TracePropertyMap; import ghidra.trace.model.map.TracePropertyMap;
import ghidra.trace.model.memory.TraceMemoryRegion;
import ghidra.trace.model.program.TraceProgramView; import ghidra.trace.model.program.TraceProgramView;
import ghidra.trace.model.symbol.TraceReference; import ghidra.trace.model.symbol.TraceReference;
import ghidra.trace.model.symbol.TraceSymbol; import ghidra.trace.model.symbol.TraceSymbol;
@ -74,7 +74,7 @@ public interface DBTraceCodeUnitAdapter extends TraceCodeUnit, MemBufferAdapter
if (!showBlockName) { if (!showBlockName) {
return address.toString(false, pad); return address.toString(false, pad);
} }
DBTraceMemoryRegion region = TraceMemoryRegion region =
getTrace().getMemoryManager().getRegionContaining(getStartSnap(), address); getTrace().getMemoryManager().getRegionContaining(getStartSnap(), address);
if (region == null) { if (region == null) {
return address.toString(showBlockName, pad); return address.toString(showBlockName, pad);

View file

@ -15,8 +15,8 @@
*/ */
package ghidra.trace.database.listing; package ghidra.trace.database.listing;
import ghidra.trace.database.thread.DBTraceThread;
import ghidra.trace.model.listing.TraceCodeUnitsRegisterView; import ghidra.trace.model.listing.TraceCodeUnitsRegisterView;
import ghidra.trace.model.thread.TraceThread;
public class DBTraceCodeUnitsRegisterView extends DBTraceCodeUnitsView public class DBTraceCodeUnitsRegisterView extends DBTraceCodeUnitsView
implements TraceCodeUnitsRegisterView { implements TraceCodeUnitsRegisterView {
@ -25,7 +25,7 @@ public class DBTraceCodeUnitsRegisterView extends DBTraceCodeUnitsView
} }
@Override @Override
public DBTraceThread getThread() { public TraceThread getThread() {
return space.getThread(); return space.getThread();
} }
} }

View file

@ -15,8 +15,8 @@
*/ */
package ghidra.trace.database.listing; package ghidra.trace.database.listing;
import ghidra.trace.database.thread.DBTraceThread;
import ghidra.trace.model.listing.TraceDataRegisterView; import ghidra.trace.model.listing.TraceDataRegisterView;
import ghidra.trace.model.thread.TraceThread;
public class DBTraceDataRegisterView extends DBTraceDataView implements TraceDataRegisterView { public class DBTraceDataRegisterView extends DBTraceDataView implements TraceDataRegisterView {
public DBTraceDataRegisterView(DBTraceCodeSpace space) { public DBTraceDataRegisterView(DBTraceCodeSpace space) {
@ -24,7 +24,7 @@ public class DBTraceDataRegisterView extends DBTraceDataView implements TraceDat
} }
@Override @Override
public DBTraceThread getThread() { public TraceThread getThread() {
return space.getThread(); return space.getThread();
} }
} }

View file

@ -15,8 +15,8 @@
*/ */
package ghidra.trace.database.listing; package ghidra.trace.database.listing;
import ghidra.trace.database.thread.DBTraceThread;
import ghidra.trace.model.listing.TraceInstructionsRegisterView; import ghidra.trace.model.listing.TraceInstructionsRegisterView;
import ghidra.trace.model.thread.TraceThread;
public class DBTraceInstructionsRegisterView extends DBTraceInstructionsView public class DBTraceInstructionsRegisterView extends DBTraceInstructionsView
implements TraceInstructionsRegisterView { implements TraceInstructionsRegisterView {
@ -26,7 +26,7 @@ public class DBTraceInstructionsRegisterView extends DBTraceInstructionsView
} }
@Override @Override
public DBTraceThread getThread() { public TraceThread getThread() {
return space.getThread(); return space.getThread();
} }
} }

View file

@ -38,7 +38,6 @@ import ghidra.trace.model.listing.TraceInstructionsView;
import ghidra.trace.util.OverlappingObjectIterator; import ghidra.trace.util.OverlappingObjectIterator;
import ghidra.trace.util.TraceChangeRecord; import ghidra.trace.util.TraceChangeRecord;
import ghidra.util.LockHold; import ghidra.util.LockHold;
import ghidra.util.SystemUtilities;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;

View file

@ -31,10 +31,10 @@ import ghidra.trace.database.DBTraceUtils;
import ghidra.trace.database.data.DBTraceDataSettingsOperations; import ghidra.trace.database.data.DBTraceDataSettingsOperations;
import ghidra.trace.database.memory.DBTraceMemorySpace; import ghidra.trace.database.memory.DBTraceMemorySpace;
import ghidra.trace.database.space.DBTraceSpaceKey; import ghidra.trace.database.space.DBTraceSpaceKey;
import ghidra.trace.database.thread.DBTraceThread;
import ghidra.trace.model.ImmutableTraceAddressSnapRange; import ghidra.trace.model.ImmutableTraceAddressSnapRange;
import ghidra.trace.model.TraceAddressSnapRange; import ghidra.trace.model.TraceAddressSnapRange;
import ghidra.trace.model.listing.TraceData; import ghidra.trace.model.listing.TraceData;
import ghidra.trace.model.thread.TraceThread;
import ghidra.trace.util.TraceAddressSpace; import ghidra.trace.util.TraceAddressSpace;
public class UndefinedDBTraceData implements DBTraceDataAdapter, DBTraceSpaceKey { public class UndefinedDBTraceData implements DBTraceDataAdapter, DBTraceSpaceKey {
@ -42,10 +42,10 @@ public class UndefinedDBTraceData implements DBTraceDataAdapter, DBTraceSpaceKey
protected final long snap; protected final long snap;
protected final Range<Long> lifespan; protected final Range<Long> lifespan;
protected final Address address; protected final Address address;
protected final DBTraceThread thread; protected final TraceThread thread;
protected final int frameLevel; 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) { int frameLevel) {
this.trace = trace; this.trace = trace;
this.snap = snap; this.snap = snap;
@ -118,7 +118,7 @@ public class UndefinedDBTraceData implements DBTraceDataAdapter, DBTraceSpaceKey
} }
@Override @Override
public DBTraceThread getThread() { public TraceThread getThread() {
return thread; return thread;
} }

View file

@ -35,7 +35,6 @@ import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.Abstract
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery; import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery;
import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager; import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager;
import ghidra.trace.database.space.DBTraceDelegatingManager; import ghidra.trace.database.space.DBTraceDelegatingManager;
import ghidra.trace.database.thread.DBTraceThread;
import ghidra.trace.database.thread.DBTraceThreadManager; import ghidra.trace.database.thread.DBTraceThreadManager;
import ghidra.trace.model.TraceAddressSnapRange; import ghidra.trace.model.TraceAddressSnapRange;
import ghidra.trace.model.map.TraceAddressSnapRangePropertyMap; import ghidra.trace.model.map.TraceAddressSnapRangePropertyMap;
@ -89,7 +88,7 @@ public class DBTraceAddressSnapRangePropertyMap<T, DR extends AbstractDBTraceAdd
@Override @Override
protected DBTraceAddressSnapRangePropertyMapRegisterSpace<T, DR> createRegisterSpace( protected DBTraceAddressSnapRangePropertyMapRegisterSpace<T, DR> createRegisterSpace(
AddressSpace space, DBTraceThread thread, DBTraceSpaceEntry ent) AddressSpace space, TraceThread thread, DBTraceSpaceEntry ent)
throws VersionException, IOException { throws VersionException, IOException {
return new DBTraceAddressSnapRangePropertyMapRegisterSpace<>( return new DBTraceAddressSnapRangePropertyMapRegisterSpace<>(
tableName(space, ent.getThreadKey(), ent.getFrameLevel()), trace.getStoreFactory(), tableName(space, ent.getThreadKey(), ent.getFrameLevel()), trace.getStoreFactory(),

View file

@ -21,20 +21,20 @@ import java.util.concurrent.locks.ReadWriteLock;
import ghidra.program.model.address.AddressSpace; import ghidra.program.model.address.AddressSpace;
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMap.DBTraceAddressSnapRangePropertyMapDataFactory; import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMap.DBTraceAddressSnapRangePropertyMapDataFactory;
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.AbstractDBTraceAddressSnapRangePropertyMapData; import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.AbstractDBTraceAddressSnapRangePropertyMapData;
import ghidra.trace.database.thread.DBTraceThread;
import ghidra.trace.model.map.TraceAddressSnapRangePropertyMapRegisterSpace; import ghidra.trace.model.map.TraceAddressSnapRangePropertyMapRegisterSpace;
import ghidra.trace.model.thread.TraceThread;
import ghidra.util.database.DBCachedObjectStoreFactory; import ghidra.util.database.DBCachedObjectStoreFactory;
import ghidra.util.exception.VersionException; import ghidra.util.exception.VersionException;
public class DBTraceAddressSnapRangePropertyMapRegisterSpace<T, DR extends AbstractDBTraceAddressSnapRangePropertyMapData<T>> public class DBTraceAddressSnapRangePropertyMapRegisterSpace<T, DR extends AbstractDBTraceAddressSnapRangePropertyMapData<T>>
extends DBTraceAddressSnapRangePropertyMapSpace<T, DR> extends DBTraceAddressSnapRangePropertyMapSpace<T, DR>
implements TraceAddressSnapRangePropertyMapRegisterSpace<T> { implements TraceAddressSnapRangePropertyMapRegisterSpace<T> {
protected final DBTraceThread thread; protected final TraceThread thread;
protected final int frameLevel; protected final int frameLevel;
public DBTraceAddressSnapRangePropertyMapRegisterSpace(String tableName, public DBTraceAddressSnapRangePropertyMapRegisterSpace(String tableName,
DBCachedObjectStoreFactory storeFactory, ReadWriteLock lock, AddressSpace space, DBCachedObjectStoreFactory storeFactory, ReadWriteLock lock, AddressSpace space,
DBTraceThread thread, int frameLevel, Class<DR> dataType, TraceThread thread, int frameLevel, Class<DR> dataType,
DBTraceAddressSnapRangePropertyMapDataFactory<T, DR> dataFactory) DBTraceAddressSnapRangePropertyMapDataFactory<T, DR> dataFactory)
throws VersionException, IOException { throws VersionException, IOException {
super(tableName, storeFactory, lock, space, dataType, dataFactory); super(tableName, storeFactory, lock, space, dataType, dataFactory);
@ -43,7 +43,7 @@ public class DBTraceAddressSnapRangePropertyMapRegisterSpace<T, DR extends Abstr
} }
@Override @Override
public DBTraceThread getThread() { public TraceThread getThread() {
return thread; return thread;
} }

View file

@ -29,9 +29,9 @@ import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMap.DBTraceAddre
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.AbstractDBTraceAddressSnapRangePropertyMapData; import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.AbstractDBTraceAddressSnapRangePropertyMapData;
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery; import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery;
import ghidra.trace.database.space.DBTraceSpaceBased; import ghidra.trace.database.space.DBTraceSpaceBased;
import ghidra.trace.database.thread.DBTraceThread;
import ghidra.trace.model.TraceAddressSnapRange; import ghidra.trace.model.TraceAddressSnapRange;
import ghidra.trace.model.map.TraceAddressSnapRangePropertyMapSpace; import ghidra.trace.model.map.TraceAddressSnapRangePropertyMapSpace;
import ghidra.trace.model.thread.TraceThread;
import ghidra.util.LockHold; import ghidra.util.LockHold;
import ghidra.util.database.*; import ghidra.util.database.*;
import ghidra.util.database.spatial.AbstractConstraintsTreeSpatialMap; import ghidra.util.database.spatial.AbstractConstraintsTreeSpatialMap;
@ -69,7 +69,7 @@ public class DBTraceAddressSnapRangePropertyMapSpace<T, DR extends AbstractDBTra
} }
@Override @Override
public DBTraceThread getThread() { public TraceThread getThread() {
return null; return null;
} }

View file

@ -28,6 +28,7 @@ import com.google.common.collect.Collections2;
import com.google.common.collect.Range; import com.google.common.collect.Range;
import db.DBHandle; import db.DBHandle;
import ghidra.dbg.target.TargetMemoryRegion;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.lang.Language; import ghidra.program.model.lang.Language;
import ghidra.program.model.mem.MemBuffer; 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.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery;
import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager; import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager;
import ghidra.trace.database.space.DBTraceDelegatingManager; import ghidra.trace.database.space.DBTraceDelegatingManager;
import ghidra.trace.database.thread.DBTraceThread;
import ghidra.trace.database.thread.DBTraceThreadManager; import ghidra.trace.database.thread.DBTraceThreadManager;
import ghidra.trace.model.TraceAddressSnapRange; import ghidra.trace.model.TraceAddressSnapRange;
import ghidra.trace.model.memory.*; import ghidra.trace.model.memory.*;
@ -85,7 +85,7 @@ public class DBTraceMemoryManager
@Override @Override
protected DBTraceMemoryRegisterSpace createRegisterSpace(AddressSpace space, 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); return new DBTraceMemoryRegisterSpace(this, dbh, space, ent, thread);
} }
@ -128,9 +128,12 @@ public class DBTraceMemoryManager
} }
@Override @Override
public DBTraceMemoryRegion addRegion(String path, Range<Long> lifespan, public TraceMemoryRegion addRegion(String path, Range<Long> lifespan,
AddressRange range, Collection<TraceMemoryFlag> flags) AddressRange range, Collection<TraceMemoryFlag> flags)
throws TraceOverlappedRegionException, DuplicateNameException { throws TraceOverlappedRegionException, DuplicateNameException {
if (trace.getObjectManager().hasSchema()) {
return trace.getObjectManager().addMemoryRegion(path, lifespan, range, flags);
}
try { try {
return delegateWrite(range.getAddressSpace(), return delegateWrite(range.getAddressSpace(),
m -> m.addRegion(path, lifespan, range, flags)); m -> m.addRegion(path, lifespan, range, flags));
@ -144,35 +147,50 @@ public class DBTraceMemoryManager
} }
@Override @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()); return delegateCollection(getActiveMemorySpaces(), m -> m.getAllRegions());
} }
// Internal
public Collection<DBTraceMemoryRegion> getRegionsInternal() {
return delegateCollection(getActiveMemorySpaces(), m -> m.regionMapSpace.values());
}
@Override @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 // 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 @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)); return delegateRead(address.getAddressSpace(), m -> m.getRegionContaining(snap, address));
} }
@Override @Override
public Collection<? extends DBTraceMemoryRegion> getRegionsIntersecting(Range<Long> lifespan, public Collection<? extends TraceMemoryRegion> getRegionsIntersecting(Range<Long> lifespan,
AddressRange range) { 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), return delegateRead(range.getAddressSpace(), m -> m.getRegionsIntersecting(lifespan, range),
Collections.emptyList()); Collections.emptyList());
} }
@Override @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)); return delegateCollection(memSpaces.values(), m -> m.getRegionsAtSnap(snap));
} }
@ -193,6 +211,11 @@ public class DBTraceMemoryManager
@Override @Override
public AddressSetView getRegionsAddressSet(long snap) { 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(), return new UnionAddressSetView(Collections2.transform(getActiveMemorySpaces(),
m -> m.getRegionsAddressSet(snap))); m -> m.getRegionsAddressSet(snap)));
} }
@ -200,6 +223,11 @@ public class DBTraceMemoryManager
@Override @Override
public AddressSetView getRegionsAddressSetWith(long snap, public AddressSetView getRegionsAddressSetWith(long snap,
Predicate<TraceMemoryRegion> predicate) { 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(), return new UnionAddressSetView(Collections2.transform(getActiveMemorySpaces(),
m -> m.getRegionsAddressSetWith(snap, predicate))); m -> m.getRegionsAddressSetWith(snap, predicate)));
} }

View file

@ -65,7 +65,7 @@ public class DBTraceMemoryRegion
private final DBTraceMemorySpace space; 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, public DBTraceMemoryRegion(DBTraceMemorySpace space,
DBTraceAddressSnapRangePropertyMapTree<DBTraceMemoryRegion, DBTraceMemoryRegion> tree, DBTraceAddressSnapRangePropertyMapTree<DBTraceMemoryRegion, DBTraceMemoryRegion> tree,
@ -81,11 +81,7 @@ public class DBTraceMemoryRegion
return; return;
} }
flags.clear(); flags.clear();
for (TraceMemoryFlag f : TraceMemoryFlag.values()) { TraceMemoryFlag.fromBits(flags, flagsByte);
if ((flagsByte & f.getBits()) != 0) {
flags.add(f);
}
}
} }
@Override @Override
@ -271,14 +267,11 @@ public class DBTraceMemoryRegion
@Override @Override
public void setFlags(Collection<TraceMemoryFlag> flags) { public void setFlags(Collection<TraceMemoryFlag> flags) {
try (LockHold hold = LockHold.lock(space.lock.writeLock())) { try (LockHold hold = LockHold.lock(space.lock.writeLock())) {
this.flagsByte = 0; this.flagsByte = TraceMemoryFlag.toBits(flags);
this.flags.clear(); this.flags.clear();
for (TraceMemoryFlag f : flags) { this.flags.addAll(flags);
this.flagsByte |= f.getBits();
this.flags.add(f);
}
update(FLAGS_COLUMN); update(FLAGS_COLUMN);
space.trace.updateViewsChangeRegionBlockFlags(this); space.trace.updateViewsChangeRegionBlockFlags(this, lifespan);
} }
space.trace.setChanged( space.trace.setChanged(
new TraceChangeRecord<>(TraceMemoryRegionChangeType.CHANGED, space, this)); new TraceChangeRecord<>(TraceMemoryRegionChangeType.CHANGED, space, this));
@ -288,12 +281,10 @@ public class DBTraceMemoryRegion
@Override @Override
public void addFlags(Collection<TraceMemoryFlag> flags) { public void addFlags(Collection<TraceMemoryFlag> flags) {
try (LockHold hold = LockHold.lock(space.lock.writeLock())) { try (LockHold hold = LockHold.lock(space.lock.writeLock())) {
for (TraceMemoryFlag f : flags) { this.flagsByte |= TraceMemoryFlag.toBits(flags);
this.flagsByte |= f.getBits(); this.flags.addAll(flags);
this.flags.add(f);
}
update(FLAGS_COLUMN); update(FLAGS_COLUMN);
space.trace.updateViewsChangeRegionBlockFlags(this); space.trace.updateViewsChangeRegionBlockFlags(this, lifespan);
} }
space.trace.setChanged( space.trace.setChanged(
new TraceChangeRecord<>(TraceMemoryRegionChangeType.CHANGED, space, this)); new TraceChangeRecord<>(TraceMemoryRegionChangeType.CHANGED, space, this));
@ -303,12 +294,10 @@ public class DBTraceMemoryRegion
@Override @Override
public void clearFlags(Collection<TraceMemoryFlag> flags) { public void clearFlags(Collection<TraceMemoryFlag> flags) {
try (LockHold hold = LockHold.lock(space.lock.writeLock())) { try (LockHold hold = LockHold.lock(space.lock.writeLock())) {
for (TraceMemoryFlag f : flags) { this.flagsByte &= ~TraceMemoryFlag.toBits(flags);
this.flagsByte &= ~f.getBits(); this.flags.removeAll(flags);
this.flags.remove(f);
}
update(FLAGS_COLUMN); update(FLAGS_COLUMN);
space.trace.updateViewsChangeRegionBlockFlags(this); space.trace.updateViewsChangeRegionBlockFlags(this, lifespan);
} }
space.trace.setChanged( space.trace.setChanged(
new TraceChangeRecord<>(TraceMemoryRegionChangeType.CHANGED, space, this)); new TraceChangeRecord<>(TraceMemoryRegionChangeType.CHANGED, space, this));

View file

@ -26,18 +26,18 @@ import ghidra.program.model.address.AddressRange;
import ghidra.program.model.address.AddressSpace; import ghidra.program.model.address.AddressSpace;
import ghidra.trace.database.listing.DBTraceCodeRegisterSpace; import ghidra.trace.database.listing.DBTraceCodeRegisterSpace;
import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager.DBTraceSpaceEntry; import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager.DBTraceSpaceEntry;
import ghidra.trace.database.thread.DBTraceThread;
import ghidra.trace.model.memory.*; import ghidra.trace.model.memory.*;
import ghidra.trace.model.thread.TraceThread;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
import ghidra.util.exception.VersionException; import ghidra.util.exception.VersionException;
public class DBTraceMemoryRegisterSpace extends DBTraceMemorySpace public class DBTraceMemoryRegisterSpace extends DBTraceMemorySpace
implements TraceMemoryRegisterSpace { implements TraceMemoryRegisterSpace {
protected final DBTraceThread thread; protected final TraceThread thread;
private final int frameLevel; private final int frameLevel;
public DBTraceMemoryRegisterSpace(DBTraceMemoryManager manager, DBHandle dbh, public DBTraceMemoryRegisterSpace(DBTraceMemoryManager manager, DBHandle dbh,
AddressSpace space, DBTraceSpaceEntry ent, DBTraceThread thread) AddressSpace space, DBTraceSpaceEntry ent, TraceThread thread)
throws IOException, VersionException { throws IOException, VersionException {
super(manager, dbh, space, ent); super(manager, dbh, space, ent);
this.thread = thread; this.thread = thread;
@ -45,7 +45,7 @@ public class DBTraceMemoryRegisterSpace extends DBTraceMemorySpace
} }
@Override @Override
public DBTraceThread getThread() { public TraceThread getThread() {
return thread; return thread;
} }

View file

@ -33,16 +33,17 @@ import ghidra.program.model.address.*;
import ghidra.program.model.mem.MemBuffer; import ghidra.program.model.mem.MemBuffer;
import ghidra.trace.database.DBTrace; import ghidra.trace.database.DBTrace;
import ghidra.trace.database.DBTraceUtils; import ghidra.trace.database.DBTraceUtils;
import ghidra.trace.database.DBTraceUtils.AddressRangeMapSetter;
import ghidra.trace.database.DBTraceUtils.OffsetSnap; import ghidra.trace.database.DBTraceUtils.OffsetSnap;
import ghidra.trace.database.listing.DBTraceCodeSpace; import ghidra.trace.database.listing.DBTraceCodeSpace;
import ghidra.trace.database.map.*; import ghidra.trace.database.map.*;
import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery; import ghidra.trace.database.map.DBTraceAddressSnapRangePropertyMapTree.TraceAddressSnapRangeQuery;
import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager.DBTraceSpaceEntry; import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager.DBTraceSpaceEntry;
import ghidra.trace.database.space.DBTraceSpaceBased; import ghidra.trace.database.space.DBTraceSpaceBased;
import ghidra.trace.database.thread.DBTraceThread;
import ghidra.trace.model.*; import ghidra.trace.model.*;
import ghidra.trace.model.Trace.*; import ghidra.trace.model.Trace.*;
import ghidra.trace.model.memory.*; import ghidra.trace.model.memory.*;
import ghidra.trace.model.thread.TraceThread;
import ghidra.trace.util.TraceChangeRecord; import ghidra.trace.util.TraceChangeRecord;
import ghidra.trace.util.TraceViewportSpanIterator; import ghidra.trace.util.TraceViewportSpanIterator;
import ghidra.util.*; import ghidra.util.*;
@ -261,7 +262,7 @@ public class DBTraceMemorySpace implements Unfinished, TraceMemorySpace, DBTrace
} }
@Override @Override
public DBTraceThread getThread() { public TraceThread getThread() {
return null; return null;
} }
@ -274,55 +275,42 @@ public class DBTraceMemorySpace implements Unfinished, TraceMemorySpace, DBTrace
if (state == null) { if (state == null) {
throw new NullPointerException(); throw new NullPointerException();
} }
// Go one out to find abutting ranges, too.
Address prev = start.previous(); new AddressRangeMapSetter<Entry<TraceAddressSnapRange, TraceMemoryState>, TraceMemoryState>() {
if (prev == null) { @Override
prev = start; protected AddressRange getRange(Entry<TraceAddressSnapRange, TraceMemoryState> entry) {
} return entry.getKey().getRange();
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
} }
stateMapSpace.remove(entry);
if (precedesMin) { @Override
if (sameState) { protected TraceMemoryState getValue(
start = range.getMinAddress(); Entry<TraceAddressSnapRange, TraceMemoryState> entry) {
} return entry.getValue();
else {
toPut.put(
new ImmutableTraceAddressSnapRange(range.getMinAddress(), prev, snap, snap),
entry.getValue());
}
} }
if (procedesMax) {
if (sameState) { @Override
end = range.getMaxAddress(); protected void remove(Entry<TraceAddressSnapRange, TraceMemoryState> entry) {
} stateMapSpace.remove(entry);
else {
toPut.put(
new ImmutableTraceAddressSnapRange(next, range.getMaxAddress(), snap, snap),
entry.getValue());
}
} }
}
if (state != TraceMemoryState.UNKNOWN) { @Override
stateMapSpace.put(start, end, snap, state); protected Iterable<Entry<TraceAddressSnapRange, TraceMemoryState>> getIntersecting(
} Address lower, Address upper) {
assert toPut.size() <= 2; return stateMapSpace
for (Entry<TraceAddressSnapRange, TraceMemoryState> ent : toPut.entrySet()) { .reduce(TraceAddressSnapRangeQuery.intersecting(lower, upper, snap, snap))
stateMapSpace.put(ent.getKey(), ent.getValue()); .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, trace.setChanged(new TraceChangeRecord<>(TraceMemoryStateChangeType.CHANGED, this,
new ImmutableTraceAddressSnapRange(start, end, snap, snap), state)); new ImmutableTraceAddressSnapRange(start, end, snap, snap), state));
} }

View file

@ -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);
}
}

View file

@ -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())];
}
}

View file

@ -23,16 +23,16 @@ import java.util.concurrent.locks.ReadWriteLock;
import com.google.common.collect.Range; import com.google.common.collect.Range;
import db.DBHandle; import db.DBHandle;
import ghidra.dbg.target.TargetModule;
import ghidra.dbg.target.TargetSection;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.lang.Language; import ghidra.program.model.lang.Language;
import ghidra.trace.database.DBTrace; import ghidra.trace.database.DBTrace;
import ghidra.trace.database.DBTraceUtils; import ghidra.trace.database.DBTraceUtils;
import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager; import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager;
import ghidra.trace.database.space.DBTraceDelegatingManager; import ghidra.trace.database.space.DBTraceDelegatingManager;
import ghidra.trace.database.thread.DBTraceThread;
import ghidra.trace.model.Trace.TraceModuleChangeType; import ghidra.trace.model.Trace.TraceModuleChangeType;
import ghidra.trace.model.modules.TraceModuleManager; import ghidra.trace.model.modules.*;
import ghidra.trace.model.modules.TraceSection;
import ghidra.trace.model.thread.TraceThread; import ghidra.trace.model.thread.TraceThread;
import ghidra.trace.util.TraceChangeRecord; import ghidra.trace.util.TraceChangeRecord;
import ghidra.util.LockHold; import ghidra.util.LockHold;
@ -64,9 +64,9 @@ public class DBTraceModuleManager
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
protected void checkModulePathConflicts(DBTraceModule ignore, String modulePath, protected void checkModulePathConflicts(TraceModule ignore, String modulePath,
Range<Long> moduleLifespan) throws DuplicateNameException { Range<Long> moduleLifespan) throws DuplicateNameException {
for (DBTraceModule pc : doGetModulesByPath(modulePath)) { for (TraceModule pc : doGetModulesByPath(modulePath)) {
if (pc == ignore) { if (pc == ignore) {
continue; continue;
} }
@ -80,12 +80,17 @@ public class DBTraceModuleManager
protected void checkSectionPathConflicts(DBTraceSection ignore, String sectionPath, protected void checkSectionPathConflicts(DBTraceSection ignore, String sectionPath,
Range<Long> moduleLifespan) throws DuplicateNameException { Range<Long> moduleLifespan) throws DuplicateNameException {
Collection<? extends DBTraceSection> pathConflicts = doGetSectionsByPath(sectionPath); Collection<? extends TraceSection> pathConflicts = doGetSectionsByPath(sectionPath);
for (DBTraceSection pc : pathConflicts) { for (TraceSection pc : pathConflicts) {
if (pc == ignore) { if (pc == ignore) {
continue; 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; continue;
} }
throw new DuplicateNameException("Section with path '" + sectionPath + throw new DuplicateNameException("Section with path '" + sectionPath +
@ -94,31 +99,41 @@ public class DBTraceModuleManager
} }
@Override @Override
public DBTraceModule addModule(String modulePath, String moduleName, AddressRange range, public TraceModule addModule(String modulePath, String moduleName, AddressRange range,
Range<Long> lifespan) throws DuplicateNameException { Range<Long> lifespan) throws DuplicateNameException {
try (LockHold hold = LockHold.lock(lock.writeLock())) { try (LockHold hold = LockHold.lock(lock.writeLock())) {
return doAddModule(modulePath, moduleName, range, lifespan); 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 { Range<Long> lifespan) throws DuplicateNameException {
if (trace.getObjectManager().hasSchema()) {
return trace.getObjectManager().addModule(modulePath, moduleName, lifespan, range);
}
checkModulePathConflicts(null, modulePath, lifespan); checkModulePathConflicts(null, modulePath, lifespan);
return delegateWrite(range.getAddressSpace(), return delegateWrite(range.getAddressSpace(),
m -> m.doAddModule(modulePath, moduleName, range, lifespan)); 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)); return delegateCollection(memSpaces.values(), m -> m.doGetModulesByPath(modulePath));
} }
@Override @Override
public Collection<? extends DBTraceModule> getModulesByPath(String modulePath) { public Collection<? extends TraceModule> getModulesByPath(String modulePath) {
return Collections.unmodifiableCollection(doGetModulesByPath(modulePath)); return Collections.unmodifiableCollection(doGetModulesByPath(modulePath));
} }
@Override @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())) { try (LockHold hold = LockHold.lock(lock.readLock())) {
return doGetModulesByPath(modulePath) return doGetModulesByPath(modulePath)
.stream() .stream()
@ -129,24 +144,40 @@ public class DBTraceModuleManager
} }
@Override @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()); return delegateCollection(memSpaces.values(), m -> m.getAllModules());
} }
@Override @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)); return delegateCollection(memSpaces.values(), m -> m.getLoadedModules(snap));
} }
@Override @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(), return delegateRead(address.getAddressSpace(),
m -> m.getModulesAt(snap, address), Set.of()); m -> m.getModulesAt(snap, address), Set.of());
} }
@Override @Override
public Collection<? extends DBTraceModule> getModulesIntersecting(Range<Long> lifespan, public Collection<? extends TraceModule> getModulesIntersecting(Range<Long> lifespan,
AddressRange range) { AddressRange range) {
if (trace.getObjectManager().hasSchema()) {
return trace.getObjectManager()
.getObjectsIntersecting(lifespan, range, TargetModule.RANGE_ATTRIBUTE_NAME,
TraceObjectModule.class);
}
return delegateRead(range.getAddressSpace(), return delegateRead(range.getAddressSpace(),
m -> m.getModulesIntersecting(lifespan, range), Set.of()); m -> m.getModulesIntersecting(lifespan, range), Set.of());
} }
@ -157,14 +188,24 @@ public class DBTraceModuleManager
} }
@Override @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(), return delegateRead(address.getAddressSpace(),
m -> m.getSectionsAt(snap, address), Set.of()); m -> m.getSectionsAt(snap, address), Set.of());
} }
@Override @Override
public Collection<? extends DBTraceSection> getSectionsIntersecting(Range<Long> lifespan, public Collection<? extends TraceSection> getSectionsIntersecting(Range<Long> lifespan,
AddressRange range) { AddressRange range) {
if (trace.getObjectManager().hasSchema()) {
return trace.getObjectManager()
.getObjectsIntersecting(lifespan, range, TargetSection.RANGE_ATTRIBUTE_NAME,
TraceObjectSection.class);
}
return delegateRead(range.getAddressSpace(), return delegateRead(range.getAddressSpace(),
m -> m.getSectionsIntersecting(lifespan, range), Set.of()); m -> m.getSectionsIntersecting(lifespan, range), Set.of());
} }
@ -186,7 +227,7 @@ public class DBTraceModuleManager
} }
@Override @Override
protected DBTraceModuleSpace createRegisterSpace(AddressSpace space, DBTraceThread thread, protected DBTraceModuleSpace createRegisterSpace(AddressSpace space, TraceThread thread,
DBTraceSpaceEntry ent) throws VersionException, IOException { DBTraceSpaceEntry ent) throws VersionException, IOException {
throw new AssertionError(); throw new AssertionError();
} }
@ -204,7 +245,10 @@ public class DBTraceModuleManager
} }
@Override @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()); return delegateCollection(memSpaces.values(), m -> m.getAllSections());
} }
@ -212,12 +256,15 @@ public class DBTraceModuleManager
return delegateCollection(memSpaces.values(), m -> m.doGetSectionsByModuleId(key)); 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)); return delegateCollection(memSpaces.values(), m -> m.doGetSectionsByPath(sectionPath));
} }
@Override @Override
public Collection<? extends DBTraceSection> getSectionsByPath(String sectionPath) { public Collection<? extends TraceSection> getSectionsByPath(String sectionPath) {
try (LockHold hold = LockHold.lock(lock.readLock())) { try (LockHold hold = LockHold.lock(lock.readLock())) {
return Collections.unmodifiableCollection(doGetSectionsByPath(sectionPath)); return Collections.unmodifiableCollection(doGetSectionsByPath(sectionPath));
} }
@ -225,10 +272,14 @@ public class DBTraceModuleManager
@Override @Override
public TraceSection getLoadedSectionByPath(long snap, String sectionPath) { 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())) { try (LockHold hold = LockHold.lock(lock.readLock())) {
return doGetSectionsByPath(sectionPath) return doGetSectionsByPath(sectionPath)
.stream() .stream()
.filter(s -> s.getLifespan().contains(snap)) .filter(s -> s.getModule().getLifespan().contains(snap))
.findAny() .findAny()
.orElse(null); .orElse(null);
} }

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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);
}

View file

@ -38,13 +38,13 @@ import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.program.model.util.PropertyMap; import ghidra.program.model.util.PropertyMap;
import ghidra.trace.database.DBTrace; import ghidra.trace.database.DBTrace;
import ghidra.trace.database.listing.UndefinedDBTraceData; import ghidra.trace.database.listing.UndefinedDBTraceData;
import ghidra.trace.database.memory.DBTraceMemoryRegion;
import ghidra.trace.database.memory.DBTraceMemorySpace; import ghidra.trace.database.memory.DBTraceMemorySpace;
import ghidra.trace.database.symbol.DBTraceFunctionSymbol; import ghidra.trace.database.symbol.DBTraceFunctionSymbol;
import ghidra.trace.database.thread.DBTraceThread; import ghidra.trace.database.thread.DBTraceThread;
import ghidra.trace.model.*; import ghidra.trace.model.*;
import ghidra.trace.model.listing.*; import ghidra.trace.model.listing.*;
import ghidra.trace.model.map.TracePropertyMap; import ghidra.trace.model.map.TracePropertyMap;
import ghidra.trace.model.memory.TraceMemoryRegion;
import ghidra.trace.model.program.TraceProgramView; import ghidra.trace.model.program.TraceProgramView;
import ghidra.trace.model.program.TraceProgramViewListing; import ghidra.trace.model.program.TraceProgramViewListing;
import ghidra.trace.model.symbol.TraceFunctionSymbol; import ghidra.trace.model.symbol.TraceFunctionSymbol;
@ -79,7 +79,7 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV
protected final TraceCodeOperations codeOperations; protected final TraceCodeOperations codeOperations;
protected final DBTraceProgramViewRootModule rootModule; protected final DBTraceProgramViewRootModule rootModule;
protected final Map<DBTraceMemoryRegion, DBTraceProgramViewFragment> fragmentsByRegion = protected final Map<TraceMemoryRegion, DBTraceProgramViewFragment> fragmentsByRegion =
new HashMap<>(); new HashMap<>();
protected final Map<AddressSnap, UndefinedDBTraceData> undefinedCache = protected final Map<AddressSnap, UndefinedDBTraceData> undefinedCache =
@ -779,7 +779,7 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV
@Override @Override
public ProgramFragment getFragment(String treeName, Address addr) { public ProgramFragment getFragment(String treeName, Address addr) {
DBTraceMemoryRegion region = program.memory.getTopRegion( TraceMemoryRegion region = program.memory.getTopRegion(
s -> program.trace.getMemoryManager().getRegionContaining(s, addr)); s -> program.trace.getMemoryManager().getRegionContaining(s, addr));
if (region == null) { if (region == null) {
return null; return null;
@ -798,7 +798,7 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV
@Override @Override
public ProgramFragment getFragment(String treeName, String name) { public ProgramFragment getFragment(String treeName, String name) {
DBTraceMemoryRegion region = program.memory.getTopRegion( TraceMemoryRegion region = program.memory.getTopRegion(
s -> program.trace.getMemoryManager().getLiveRegionByPath(s, name)); s -> program.trace.getMemoryManager().getLiveRegionByPath(s, name));
if (region == null) { if (region == null) {
return null; return null;

View file

@ -29,6 +29,7 @@ import ghidra.program.model.address.*;
import ghidra.program.model.mem.*; import ghidra.program.model.mem.*;
import ghidra.trace.database.memory.*; import ghidra.trace.database.memory.*;
import ghidra.trace.model.Trace; import ghidra.trace.model.Trace;
import ghidra.trace.model.memory.TraceMemoryRegion;
import ghidra.trace.model.program.TraceProgramView; import ghidra.trace.model.program.TraceProgramView;
import ghidra.trace.model.program.TraceProgramViewMemory; import ghidra.trace.model.program.TraceProgramViewMemory;
import ghidra.trace.util.MemoryAdapter; import ghidra.trace.util.MemoryAdapter;
@ -53,7 +54,7 @@ public abstract class AbstractDBTraceProgramViewMemory
} }
protected void regionBlockRemoved( protected void regionBlockRemoved(
RemovalNotification<DBTraceMemoryRegion, DBTraceProgramViewMemoryRegionBlock> rn) { RemovalNotification<TraceMemoryRegion, DBTraceProgramViewMemoryRegionBlock> rn) {
// Nothing // Nothing
} }
@ -138,7 +139,7 @@ public abstract class AbstractDBTraceProgramViewMemory
@Override @Override
public AddressSetView getExecuteSet() { public AddressSetView getExecuteSet() {
AddressSet result = new AddressSet(); AddressSet result = new AddressSet();
for (DBTraceMemoryRegion region : memoryManager.getRegionsInternal()) { for (TraceMemoryRegion region : memoryManager.getAllRegions()) {
if (!region.isExecute() || !program.isRegionVisible(region, region.getLifespan())) { if (!region.isExecute() || !program.isRegionVisible(region, region.getLifespan())) {
continue; continue;
} }
@ -520,8 +521,12 @@ public abstract class AbstractDBTraceProgramViewMemory
protected synchronized void changeRange(AddressRange remove, AddressRange add) { protected synchronized void changeRange(AddressRange remove, AddressRange add) {
if (!forceFullView) { if (!forceFullView) {
AddressSet temp = new AddressSet(addressSet); AddressSet temp = new AddressSet(addressSet);
temp.delete(remove); if (remove != null) {
temp.add(add); temp.delete(remove);
}
if (add != null) {
temp.add(add);
}
addressSet = temp; addressSet = temp;
} }
} }

View file

@ -1562,37 +1562,36 @@ public class DBTraceProgramView implements TraceProgramView {
trace.removeTransactionListener(listener); trace.removeTransactionListener(listener);
} }
public void updateMemoryAddRegionBlock(DBTraceMemoryRegion region) { public void updateMemoryAddRegionBlock(TraceMemoryRegion region) {
if (!isRegionVisible(region)) { if (!isRegionVisible(region)) {
return; return;
} }
memory.updateAddRegionBlock(region); memory.updateAddRegionBlock(region);
} }
public void updateMemoryChangeRegionBlockName(DBTraceMemoryRegion region) { public void updateMemoryChangeRegionBlockName(TraceMemoryRegion region) {
if (!isRegionVisible(region)) { if (!isRegionVisible(region)) {
return; return;
} }
memory.updateChangeRegionBlockName(region); memory.updateChangeRegionBlockName(region);
} }
public void updateMemoryChangeRegionBlockFlags(DBTraceMemoryRegion region) { public void updateMemoryChangeRegionBlockFlags(TraceMemoryRegion region, Range<Long> lifespan) {
if (!isRegionVisible(region)) { if (!isRegionVisible(region, lifespan)) {
return; return;
} }
memory.updateChangeRegionBlockFlags(region); memory.updateChangeRegionBlockFlags(region);
} }
public void updateMemoryChangeRegionBlockRange(DBTraceMemoryRegion region, public void updateMemoryChangeRegionBlockRange(TraceMemoryRegion region,
AddressRange oldRange, AddressRange oldRange, AddressRange newRange) {
AddressRange newRange) {
if (!isRegionVisible(region)) { if (!isRegionVisible(region)) {
return; return;
} }
memory.updateChangeRegionBlockRange(region, oldRange, newRange); memory.updateChangeRegionBlockRange(region, oldRange, newRange);
} }
public void updateMemoryChangeRegionBlockLifespan(DBTraceMemoryRegion region, public void updateMemoryChangeRegionBlockLifespan(TraceMemoryRegion region,
Range<Long> oldLifespan, Range<Long> newLifespan) { Range<Long> oldLifespan, Range<Long> newLifespan) {
boolean inOld = isRegionVisible(region, oldLifespan); boolean inOld = isRegionVisible(region, oldLifespan);
boolean inNew = isRegionVisible(region, newLifespan); 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)) { if (!isRegionVisible(region)) {
return; return;
} }

View file

@ -19,24 +19,24 @@ import java.util.Iterator;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.listing.*; 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.DuplicateNameException;
import ghidra.util.exception.NotFoundException; import ghidra.util.exception.NotFoundException;
// TODO: Destroy this in favor of databased trees? // TODO: Destroy this in favor of databased trees?
public class DBTraceProgramViewFragment implements ProgramFragment { public class DBTraceProgramViewFragment implements ProgramFragment {
protected final AbstractDBTraceProgramViewListing listing; protected final AbstractDBTraceProgramViewListing listing;
protected final DBTraceMemoryRegion region; protected final TraceMemoryRegion region;
public DBTraceProgramViewFragment(AbstractDBTraceProgramViewListing listing, public DBTraceProgramViewFragment(AbstractDBTraceProgramViewListing listing,
DBTraceMemoryRegion region) { TraceMemoryRegion region) {
this.listing = listing; this.listing = listing;
this.region = region; this.region = region;
} }
@Override @Override
public String getComment() { public String getComment() {
return region.description(); return "";
} }
@Override @Override
@ -76,22 +76,27 @@ public class DBTraceProgramViewFragment implements ProgramFragment {
@Override @Override
public boolean contains(Address addr) { public boolean contains(Address addr) {
return region.contains(addr, listing.program.snap); return region.getRange().contains(addr) &&
region.getLifespan().contains(listing.program.snap);
} }
@Override @Override
public boolean contains(Address start, Address end) { public boolean contains(Address start, Address end) {
// Regions are contiguous // Regions are contiguous
long snap = listing.program.snap; AddressRange range = region.getRange();
return region.contains(start, snap) && region.contains(end, snap); return range.contains(start) && range.contains(end) &&
region.getLifespan().contains(listing.program.snap);
} }
@Override @Override
public boolean contains(AddressSetView rangeSet) { public boolean contains(AddressSetView rangeSet) {
long snap = listing.program.snap; if (!region.getLifespan().contains(listing.program.snap)) {
return false;
}
for (AddressRange range : rangeSet) { for (AddressRange range : rangeSet) {
if (!region.contains(range.getMinAddress(), snap) || AddressRange regionRange = region.getRange();
!region.contains(range.getMaxAddress(), snap)) { if (!regionRange.contains(range.getMinAddress()) ||
!regionRange.contains(range.getMaxAddress())) {
return false; return false;
} }
} }

View file

@ -23,12 +23,12 @@ import com.google.common.cache.CacheBuilder;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.mem.MemoryBlock; import ghidra.program.model.mem.MemoryBlock;
import ghidra.trace.database.memory.DBTraceMemoryRegion; import ghidra.trace.model.memory.TraceMemoryRegion;
public class DBTraceProgramViewMemory extends AbstractDBTraceProgramViewMemory { public class DBTraceProgramViewMemory extends AbstractDBTraceProgramViewMemory {
// NB. Keep both per-region and force-full (per-space) block sets ready // 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() CacheBuilder.newBuilder()
.removalListener(this::regionBlockRemoved) .removalListener(this::regionBlockRemoved)
.weakValues() .weakValues()
@ -45,10 +45,10 @@ public class DBTraceProgramViewMemory extends AbstractDBTraceProgramViewMemory {
super(program); super(program);
} }
protected DBTraceMemoryRegion getTopRegion(Function<Long, DBTraceMemoryRegion> regFunc) { protected TraceMemoryRegion getTopRegion(Function<Long, TraceMemoryRegion> regFunc) {
return program.viewport.getTop(s -> { return program.viewport.getTop(s -> {
// TODO: There is probably an early-bail condition I can check for. // 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)) { if (reg != null && program.isRegionVisible(reg)) {
return 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()) { for (long s : program.viewport.getOrderedSnaps()) {
// NOTE: This is slightly faster than new AddressSet(mm.getRegionsAddressSet(snap)) // 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)) { if (program.isRegionVisible(reg)) {
action.accept(reg); action.accept(reg);
} }
@ -75,7 +75,7 @@ public class DBTraceProgramViewMemory extends AbstractDBTraceProgramViewMemory {
addressSet = temp; addressSet = temp;
} }
protected MemoryBlock getRegionBlock(DBTraceMemoryRegion region) { protected MemoryBlock getRegionBlock(TraceMemoryRegion region) {
return regionBlocks.computeIfAbsent(region, return regionBlocks.computeIfAbsent(region,
r -> new DBTraceProgramViewMemoryRegionBlock(program, region)); r -> new DBTraceProgramViewMemoryRegionBlock(program, region));
} }
@ -90,7 +90,7 @@ public class DBTraceProgramViewMemory extends AbstractDBTraceProgramViewMemory {
if (forceFullView) { if (forceFullView) {
return getSpaceBlock(addr.getAddressSpace()); 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); return region == null ? null : getRegionBlock(region);
} }
@ -100,7 +100,7 @@ public class DBTraceProgramViewMemory extends AbstractDBTraceProgramViewMemory {
AddressSpace space = program.getAddressFactory().getAddressSpace(blockName); AddressSpace space = program.getAddressFactory().getAddressSpace(blockName);
return space == null ? null : getSpaceBlock(space); return space == null ? null : getSpaceBlock(space);
} }
DBTraceMemoryRegion region = TraceMemoryRegion region =
getTopRegion(s -> memoryManager.getLiveRegionByPath(s, blockName)); getTopRegion(s -> memoryManager.getLiveRegionByPath(s, blockName));
return region == null ? null : getRegionBlock(region); return region == null ? null : getRegionBlock(region);
} }
@ -118,26 +118,26 @@ public class DBTraceProgramViewMemory extends AbstractDBTraceProgramViewMemory {
return result.toArray(new MemoryBlock[result.size()]); return result.toArray(new MemoryBlock[result.size()]);
} }
public void updateAddRegionBlock(DBTraceMemoryRegion region) { public void updateAddRegionBlock(TraceMemoryRegion region) {
// TODO: add block to cache? // TODO: add block to cache?
addRange(region.getRange()); addRange(region.getRange());
} }
public void updateChangeRegionBlockName(DBTraceMemoryRegion region) { public void updateChangeRegionBlockName(TraceMemoryRegion region) {
// Nothing. Block name is taken from region, uncached // 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 // Nothing. Block flags are taken from region, uncached
} }
public void updateChangeRegionBlockRange(DBTraceMemoryRegion region, AddressRange oldRange, public void updateChangeRegionBlockRange(TraceMemoryRegion region, AddressRange oldRange,
AddressRange newRange) { AddressRange newRange) {
// TODO: update cached block? Nothing to update. // TODO: update cached block? Nothing to update.
changeRange(oldRange, newRange); changeRange(oldRange, newRange);
} }
public void updateDeleteRegionBlock(DBTraceMemoryRegion region) { public void updateDeleteRegionBlock(TraceMemoryRegion region) {
regionBlocks.remove(region); regionBlocks.remove(region);
removeRange(region.getRange()); removeRange(region.getRange());
} }

View file

@ -20,18 +20,16 @@ import java.math.BigInteger;
import ghidra.framework.store.LockException; import ghidra.framework.store.LockException;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.trace.database.memory.DBTraceMemoryRegion;
import ghidra.trace.database.memory.DBTraceMemorySpace; import ghidra.trace.database.memory.DBTraceMemorySpace;
import ghidra.trace.model.memory.TraceMemoryFlag; import ghidra.trace.model.memory.*;
import ghidra.trace.model.memory.TraceMemorySpaceInputStream;
// TODO: Proper locking all over here // TODO: Proper locking all over here
public class DBTraceProgramViewMemoryRegionBlock extends AbstractDBTraceProgramViewMemoryBlock { public class DBTraceProgramViewMemoryRegionBlock extends AbstractDBTraceProgramViewMemoryBlock {
private final DBTraceMemoryRegion region; private final TraceMemoryRegion region;
public DBTraceProgramViewMemoryRegionBlock(DBTraceProgramView program, public DBTraceProgramViewMemoryRegionBlock(DBTraceProgramView program,
DBTraceMemoryRegion region) { TraceMemoryRegion region) {
super(program); super(program);
this.region = region; this.region = region;
} }

View file

@ -20,14 +20,14 @@ import com.google.common.collect.Range;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.trace.database.listing.DBTraceCodeRegisterSpace; import ghidra.trace.database.listing.DBTraceCodeRegisterSpace;
import ghidra.trace.database.listing.UndefinedDBTraceData; import ghidra.trace.database.listing.UndefinedDBTraceData;
import ghidra.trace.database.thread.DBTraceThread;
import ghidra.trace.model.program.TraceProgramViewRegisterListing; import ghidra.trace.model.program.TraceProgramViewRegisterListing;
import ghidra.trace.model.thread.TraceThread;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
public class DBTraceProgramViewRegisterListing extends AbstractDBTraceProgramViewListing public class DBTraceProgramViewRegisterListing extends AbstractDBTraceProgramViewListing
implements TraceProgramViewRegisterListing { implements TraceProgramViewRegisterListing {
private final DBTraceThread thread; private final TraceThread thread;
private Address minAddr; private Address minAddr;
private Address maxAddr; private Address maxAddr;
@ -42,7 +42,7 @@ public class DBTraceProgramViewRegisterListing extends AbstractDBTraceProgramVie
} }
@Override @Override
public DBTraceThread getThread() { public TraceThread getThread() {
return thread; return thread;
} }

View file

@ -35,7 +35,6 @@ import ghidra.program.model.util.AddressSetPropertyMap;
import ghidra.program.model.util.PropertyMapManager; import ghidra.program.model.util.PropertyMapManager;
import ghidra.trace.database.listing.DBTraceCodeRegisterSpace; import ghidra.trace.database.listing.DBTraceCodeRegisterSpace;
import ghidra.trace.database.memory.DBTraceMemoryRegisterSpace; import ghidra.trace.database.memory.DBTraceMemoryRegisterSpace;
import ghidra.trace.database.thread.DBTraceThread;
import ghidra.trace.model.Trace; import ghidra.trace.model.Trace;
import ghidra.trace.model.data.TraceBasedDataTypeManager; import ghidra.trace.model.data.TraceBasedDataTypeManager;
import ghidra.trace.model.program.TraceProgramView; import ghidra.trace.model.program.TraceProgramView;
@ -50,7 +49,7 @@ public class DBTraceProgramViewRegisters implements TraceProgramView {
protected final DomainObjectEventQueues eventQueues; protected final DomainObjectEventQueues eventQueues;
private final DBTraceProgramView view; private final DBTraceProgramView view;
private final DBTraceThread thread; private final TraceThread thread;
private final DBTraceProgramViewRegisterListing listing; private final DBTraceProgramViewRegisterListing listing;
private final DBTraceProgramViewRegisterMemory memory; private final DBTraceProgramViewRegisterMemory memory;

View file

@ -15,17 +15,17 @@
*/ */
package ghidra.trace.database.program; package ghidra.trace.database.program;
import ghidra.trace.database.thread.DBTraceThread;
import ghidra.trace.model.listing.TraceCodeOperations; import ghidra.trace.model.listing.TraceCodeOperations;
import ghidra.trace.model.symbol.TraceReferenceOperations; import ghidra.trace.model.symbol.TraceReferenceOperations;
import ghidra.trace.model.thread.TraceThread;
public class DBTraceProgramViewRegistersReferenceManager public class DBTraceProgramViewRegistersReferenceManager
extends AbstractDBTraceProgramViewReferenceManager { extends AbstractDBTraceProgramViewReferenceManager {
private final DBTraceThread thread; private final TraceThread thread;
public DBTraceProgramViewRegistersReferenceManager(DBTraceProgramView program, public DBTraceProgramViewRegistersReferenceManager(DBTraceProgramView program,
DBTraceThread thread) { TraceThread thread) {
super(program); super(program);
this.thread = thread; this.thread = thread;
} }

View file

@ -29,7 +29,6 @@ import ghidra.program.model.address.AddressFactory;
import ghidra.program.model.address.AddressSpace; import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.lang.Language; import ghidra.program.model.lang.Language;
import ghidra.trace.database.*; import ghidra.trace.database.*;
import ghidra.trace.database.thread.DBTraceThread;
import ghidra.trace.database.thread.DBTraceThreadManager; import ghidra.trace.database.thread.DBTraceThreadManager;
import ghidra.trace.model.stack.TraceStackFrame; import ghidra.trace.model.stack.TraceStackFrame;
import ghidra.trace.model.thread.TraceThread; import ghidra.trace.model.thread.TraceThread;
@ -134,7 +133,11 @@ public abstract class AbstractDBTraceSpaceBasedManager<M extends DBTraceSpaceBas
baseLanguage + ")."); baseLanguage + ").");
} }
else if (space.isRegisterSpace()) { 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; R regSpace;
if (ent.space == null) { if (ent.space == null) {
regSpace = createRegisterSpace(space, thread, ent); 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) { 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? // TODO: What if registers are memory mapped?
Pair<TraceThread, Integer> frame = ImmutablePair.of(thread, frameLevel); Pair<TraceThread, Integer> frame = ImmutablePair.of(thread, frameLevel);
if (!createIfAbsent) { if (!createIfAbsent) {
@ -203,8 +206,8 @@ public abstract class AbstractDBTraceSpaceBasedManager<M extends DBTraceSpaceBas
AddressSpace regSpace = baseLanguage.getAddressFactory().getRegisterSpace(); AddressSpace regSpace = baseLanguage.getAddressFactory().getRegisterSpace();
try { try {
DBTraceSpaceEntry ent = spaceStore.create(); DBTraceSpaceEntry ent = spaceStore.create();
ent.set(regSpace.getName(), dbThread.getKey(), frameLevel); ent.set(regSpace.getName(), thread.getKey(), frameLevel);
return createRegisterSpace(regSpace, dbThread, ent); return createRegisterSpace(regSpace, thread, ent);
} }
catch (VersionException e) { catch (VersionException e) {
throw new AssertionError(e); throw new AssertionError(e);
@ -256,7 +259,7 @@ public abstract class AbstractDBTraceSpaceBasedManager<M extends DBTraceSpaceBas
protected abstract M createSpace(AddressSpace space, DBTraceSpaceEntry ent) protected abstract M createSpace(AddressSpace space, DBTraceSpaceEntry ent)
throws VersionException, IOException; throws VersionException, IOException;
protected abstract R createRegisterSpace(AddressSpace space, DBTraceThread thread, protected abstract R createRegisterSpace(AddressSpace space, TraceThread thread,
DBTraceSpaceEntry ent) throws VersionException, IOException; DBTraceSpaceEntry ent) throws VersionException, IOException;
@Override @Override

View file

@ -16,16 +16,16 @@
package ghidra.trace.database.space; package ghidra.trace.database.space;
import ghidra.program.model.address.AddressSpace; import ghidra.program.model.address.AddressSpace;
import ghidra.trace.database.thread.DBTraceThread; import ghidra.trace.model.thread.TraceThread;
import ghidra.trace.util.TraceAddressSpace; import ghidra.trace.util.TraceAddressSpace;
public interface DBTraceSpaceKey extends TraceAddressSpace { public interface DBTraceSpaceKey extends TraceAddressSpace {
static class DefaultDBTraceSpaceKey implements DBTraceSpaceKey { static class DefaultDBTraceSpaceKey implements DBTraceSpaceKey {
private final DBTraceThread thread; private final TraceThread thread;
private final AddressSpace space; private final AddressSpace space;
private final int frameLevel; private final int frameLevel;
private DefaultDBTraceSpaceKey(DBTraceThread thread, AddressSpace space, int frameLevel) { private DefaultDBTraceSpaceKey(TraceThread thread, AddressSpace space, int frameLevel) {
this.thread = thread; this.thread = thread;
this.space = space; this.space = space;
this.frameLevel = frameLevel; this.frameLevel = frameLevel;
@ -37,7 +37,7 @@ public interface DBTraceSpaceKey extends TraceAddressSpace {
} }
@Override @Override
public DBTraceThread getThread() { public TraceThread getThread() {
return thread; 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); 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