mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
GP-4209: GhidraTime-MSTTD integration. Type hints for (most) Python agents.
This commit is contained in:
parent
deb49d5322
commit
21a1602579
93 changed files with 6453 additions and 4118 deletions
|
@ -201,6 +201,9 @@ public class DBTraceTimeViewport implements TraceTimeViewport {
|
|||
while (true) {
|
||||
TraceSnapshot fork = locateMostRecentFork(timeManager, curSnap);
|
||||
long prevSnap = fork == null ? Long.MIN_VALUE : fork.getKey();
|
||||
if (curSnap >= 0 && prevSnap < 0) {
|
||||
prevSnap = 0;
|
||||
}
|
||||
if (!addSnapRange(prevSnap, curSnap, spanSet, ordered)) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -585,6 +585,9 @@ public class DBTraceMemorySpace
|
|||
|
||||
protected void doPutFutureBytes(OffsetSnap loc, ByteBuffer buf, int dstOffset, int maxLen,
|
||||
OutSnap lastSnap, Set<TraceAddressSnapRange> changed) throws IOException {
|
||||
if (loc.snap == Lifespan.DOMAIN.lmax()) {
|
||||
return;
|
||||
}
|
||||
// NOTE: Do not leave the buffer advanced from here
|
||||
int pos = buf.position();
|
||||
// exclusive?
|
||||
|
@ -616,7 +619,7 @@ public class DBTraceMemorySpace
|
|||
}
|
||||
}
|
||||
if (!remaining.isEmpty()) {
|
||||
lastSnap.snap = Long.MAX_VALUE;
|
||||
lastSnap.snap = Lifespan.DOMAIN.lmax();
|
||||
for (AddressRange rng : remaining) {
|
||||
changed.add(
|
||||
new ImmutableTraceAddressSnapRange(rng, Lifespan.nowOnMaybeScratch(loc.snap)));
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* 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.
|
||||
|
@ -133,6 +133,26 @@ public class DBTraceTimeManager implements TraceTimeManager, DBTraceManager {
|
|||
return snapshotsBySchedule.get(schedule.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceSnapshot findScratchSnapshot(TraceSchedule schedule) {
|
||||
Collection<? extends TraceSnapshot> exist = getSnapshotsWithSchedule(schedule);
|
||||
if (!exist.isEmpty()) {
|
||||
return exist.iterator().next();
|
||||
}
|
||||
/**
|
||||
* TODO: This could be more sophisticated.... Does it need to be, though? Ideally, we'd only
|
||||
* keep state around that has annotations, e.g., bookmarks and code units. That needs a new
|
||||
* query (latestStartSince) on those managers, though. It must find the latest start tick
|
||||
* since a given snap. We consider only start snaps because placed code units go "from now
|
||||
* on out".
|
||||
*/
|
||||
TraceSnapshot last = getMostRecentSnapshot(-1);
|
||||
long snap = last == null ? Long.MIN_VALUE : last.getKey() + 1;
|
||||
TraceSnapshot snapshot = getSnapshot(snap, true);
|
||||
snapshot.setSchedule(schedule);
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends DBTraceSnapshot> getAllSnapshots() {
|
||||
return Collections.unmodifiableCollection(snapshotStore.asMap().values());
|
||||
|
|
|
@ -806,6 +806,6 @@ public interface TraceObject extends TraceUniqueObject {
|
|||
if (stateVal == null) {
|
||||
return TraceExecutionState.INACTIVE;
|
||||
}
|
||||
return TraceExecutionState.valueOf((String) stateVal.getValue());
|
||||
return TraceExecutionState.valueOf(stateVal.castValue());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package ghidra.trace.model.target.iface;
|
||||
|
||||
import ghidra.trace.model.target.info.TraceObjectInfo;
|
||||
import ghidra.trace.model.time.schedule.TraceSchedule.ScheduleForm;
|
||||
|
||||
/**
|
||||
* An object that can emit events affecting itself and its successors
|
||||
|
@ -28,8 +29,11 @@ import ghidra.trace.model.target.info.TraceObjectInfo;
|
|||
shortName = "event scope",
|
||||
attributes = {
|
||||
TraceObjectEventScope.KEY_EVENT_THREAD,
|
||||
TraceObjectEventScope.KEY_TIME_SUPPORT,
|
||||
},
|
||||
fixedKeys = {})
|
||||
public interface TraceObjectEventScope extends TraceObjectInterface {
|
||||
String KEY_EVENT_THREAD = "_event_thread";
|
||||
/** See {@link ScheduleForm} */
|
||||
String KEY_TIME_SUPPORT = "_time_support";
|
||||
}
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* 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.
|
||||
|
@ -52,10 +52,25 @@ public interface TraceTimeManager {
|
|||
* at most one snapshot.
|
||||
*
|
||||
* @param schedule the schedule to find
|
||||
* @return the snapshot, or {@code null} if no such snapshot exists
|
||||
* @return the snapshots
|
||||
*/
|
||||
Collection<? extends TraceSnapshot> getSnapshotsWithSchedule(TraceSchedule schedule);
|
||||
|
||||
/**
|
||||
* Find or create a the snapshot with the given schedule
|
||||
*
|
||||
* <p>
|
||||
* If a snapshot with the given schedule already exists, this returns the first such snapshot
|
||||
* found. Ideally, there is exactly one. If this method is consistently used for creating
|
||||
* scratch snapshots, then that should always be the case. If no such snapshot exists, this
|
||||
* creates a snapshot with the minimum available negative snapshot key, that is starting at
|
||||
* {@link Long#MIN_VALUE} and increasing from there.
|
||||
*
|
||||
* @param schedule the schedule to find
|
||||
* @return the snapshot
|
||||
*/
|
||||
TraceSnapshot findScratchSnapshot(TraceSchedule schedule);
|
||||
|
||||
/**
|
||||
* List all snapshots in the trace
|
||||
*
|
||||
|
|
|
@ -30,8 +30,153 @@ import ghidra.util.task.TaskMonitor;
|
|||
* A sequence of emulator stepping commands, essentially comprising a "point in time."
|
||||
*/
|
||||
public class TraceSchedule implements Comparable<TraceSchedule> {
|
||||
/**
|
||||
* The initial snapshot (with no steps)
|
||||
*/
|
||||
public static final TraceSchedule ZERO = TraceSchedule.snap(0);
|
||||
|
||||
/**
|
||||
* Specifies forms of a stepping schedule.
|
||||
*
|
||||
* <p>
|
||||
* Each form defines a set of stepping schedules. It happens that each is a subset of the next.
|
||||
* A {@link #SNAP_ONLY} schedule is also a {@link #SNAP_ANY_STEPS_OPS} schedule, but not
|
||||
* necessarily vice versa.
|
||||
*/
|
||||
public enum ScheduleForm {
|
||||
/**
|
||||
* The schedule consists only of a snapshot. No stepping after.
|
||||
*/
|
||||
SNAP_ONLY {
|
||||
@Override
|
||||
public boolean contains(Trace trace, TraceSchedule schedule) {
|
||||
return schedule.steps.isNop() && schedule.pSteps.isNop();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* The schedule consists of a snapshot and some number of instruction steps on the event
|
||||
* thread only.
|
||||
*/
|
||||
SNAP_EVT_STEPS {
|
||||
@Override
|
||||
public boolean contains(Trace trace, TraceSchedule schedule) {
|
||||
if (!schedule.pSteps.isNop()) {
|
||||
return false;
|
||||
}
|
||||
List<Step> steps = schedule.steps.getSteps();
|
||||
if (steps.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
if (steps.size() != 1) {
|
||||
return false;
|
||||
}
|
||||
if (!(steps.getFirst() instanceof TickStep ticks)) {
|
||||
return false;
|
||||
}
|
||||
if (ticks.getThreadKey() == -1) {
|
||||
return true;
|
||||
}
|
||||
if (trace == null) {
|
||||
return false;
|
||||
}
|
||||
TraceThread eventThread = schedule.getEventThread(trace);
|
||||
TraceThread thread = ticks.getThread(trace.getThreadManager(), eventThread);
|
||||
if (eventThread != thread) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceSchedule validate(Trace trace, TraceSchedule schedule) {
|
||||
if (!schedule.pSteps.isNop()) {
|
||||
return null;
|
||||
}
|
||||
List<Step> steps = schedule.steps.getSteps();
|
||||
if (steps.isEmpty()) {
|
||||
return schedule;
|
||||
}
|
||||
if (steps.size() != 1) {
|
||||
return null;
|
||||
}
|
||||
if (!(steps.getFirst() instanceof TickStep ticks)) {
|
||||
return null;
|
||||
}
|
||||
if (ticks.getThreadKey() == -1) {
|
||||
return schedule;
|
||||
}
|
||||
if (trace == null) {
|
||||
return null;
|
||||
}
|
||||
TraceThread eventThread = schedule.getEventThread(trace);
|
||||
TraceThread thread = ticks.getThread(trace.getThreadManager(), eventThread);
|
||||
if (eventThread != thread) {
|
||||
return null;
|
||||
}
|
||||
return TraceSchedule.snap(schedule.snap).steppedForward(null, ticks.getTickCount());
|
||||
}
|
||||
},
|
||||
/**
|
||||
* The schedule consists of a snapshot and a sequence of instruction steps on any
|
||||
* threads(s).
|
||||
*/
|
||||
SNAP_ANY_STEPS {
|
||||
@Override
|
||||
public boolean contains(Trace trace, TraceSchedule schedule) {
|
||||
return schedule.pSteps.isNop();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* The schedule consists of a snapshot and a sequence of instruction steps then p-code op
|
||||
* steps on any thread(s).
|
||||
*
|
||||
* <p>
|
||||
* This is the most capable form supported by {@link TraceSchedule}.
|
||||
*/
|
||||
SNAP_ANY_STEPS_OPS {
|
||||
@Override
|
||||
public boolean contains(Trace trace, TraceSchedule schedule) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
public static final List<ScheduleForm> VALUES = List.of(ScheduleForm.values());
|
||||
|
||||
/**
|
||||
* Check if the given schedule conforms
|
||||
*
|
||||
* @param trace if available, a trace for determining the event thread
|
||||
* @param schedule the schedule to test
|
||||
* @return true if the schedule adheres to this form
|
||||
*/
|
||||
public abstract boolean contains(Trace trace, TraceSchedule schedule);
|
||||
|
||||
/**
|
||||
* If the given schedule conforms, normalize the schedule to prove it does.
|
||||
*
|
||||
* @param trace if available, a trace for determining the event thread
|
||||
* @param schedule the schedule to test
|
||||
* @return the non-null normalized schedule, or null if the given schedule does not conform
|
||||
*/
|
||||
public TraceSchedule validate(Trace trace, TraceSchedule schedule) {
|
||||
if (!contains(trace, schedule)) {
|
||||
return null;
|
||||
}
|
||||
return schedule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the more restrictive of this and the given form
|
||||
*
|
||||
* @param that the other form
|
||||
* @return the more restrictive form
|
||||
*/
|
||||
public ScheduleForm intersect(ScheduleForm that) {
|
||||
int ord = Math.min(this.ordinal(), that.ordinal());
|
||||
return VALUES.get(ord);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a schedule that consists solely of a snapshot
|
||||
*
|
||||
|
@ -256,7 +401,7 @@ public class TraceSchedule implements Comparable<TraceSchedule> {
|
|||
* loading a snapshot
|
||||
*/
|
||||
public boolean isSnapOnly() {
|
||||
return steps.isNop() && pSteps.isNop();
|
||||
return ScheduleForm.SNAP_ONLY.contains(null, this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue