mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
GP-4231: Fix emulator step from cache after interrupt
This commit is contained in:
parent
f292bad0ed
commit
37e73f1885
12 changed files with 393 additions and 101 deletions
|
@ -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.
|
||||
|
@ -232,6 +232,11 @@ public class PatchStep implements Step {
|
|||
return StepType.PATCH;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSkipCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNop() {
|
||||
// TODO: If parsing beforehand, base on number of ops
|
||||
|
@ -307,7 +312,7 @@ public class PatchStep implements Step {
|
|||
}
|
||||
|
||||
@Override
|
||||
public <T> void execute(PcodeThread<T> emuThread, Stepper stepper, TaskMonitor monitor)
|
||||
public void execute(PcodeThread<?> emuThread, Stepper stepper, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
emuThread.stepPatch(sleigh);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
@ -81,14 +81,17 @@ public interface Scheduler {
|
|||
|
||||
/**
|
||||
* The result of running a machine
|
||||
*
|
||||
* @param schedule the actual schedule executed
|
||||
* @param error if applicable, the error that interrupted execution
|
||||
*/
|
||||
record RecordRunResult(TraceSchedule schedule, Throwable error) implements RunResult {
|
||||
}
|
||||
record RecordRunResult(TraceSchedule schedule, Throwable error) implements RunResult {}
|
||||
|
||||
/**
|
||||
* Get the next step to schedule
|
||||
*
|
||||
* @return the (instruction-level) thread and tick count
|
||||
* @param trace the trace being emulated
|
||||
* @return the thread and (instruction-level) tick count
|
||||
*/
|
||||
TickStep nextSlice(Trace trace);
|
||||
|
||||
|
@ -118,12 +121,17 @@ public interface Scheduler {
|
|||
TickStep slice = nextSlice(trace);
|
||||
eventThread = slice.getThread(tm, eventThread);
|
||||
emuThread = machine.getThread(eventThread.getPath(), true);
|
||||
if (emuThread.getFrame() != null) {
|
||||
long ticksLeft = slice.tickCount;
|
||||
if (ticksLeft > 0 && emuThread.getFrame() != null) {
|
||||
monitor.checkCancelled();
|
||||
emuThread.finishInstruction();
|
||||
ticksLeft--;
|
||||
completedTicks++;
|
||||
}
|
||||
for (int i = 0; i < slice.tickCount; i++) {
|
||||
while (ticksLeft > 0) {
|
||||
monitor.checkCancelled();
|
||||
emuThread.stepInstruction();
|
||||
ticksLeft--;
|
||||
completedTicks++;
|
||||
}
|
||||
completedSteps = completedSteps.steppedForward(eventThread, completedTicks);
|
||||
|
@ -134,11 +142,11 @@ public interface Scheduler {
|
|||
completedSteps = completedSteps.steppedForward(eventThread, completedTicks);
|
||||
PcodeFrame frame = emuThread.getFrame();
|
||||
if (frame == null) {
|
||||
return new RecordRunResult(completedSteps, e);
|
||||
return new RecordRunResult(completedSteps.assumeRecorded(), e);
|
||||
}
|
||||
// Rewind one so stepping retries the op causing the error
|
||||
frame.stepBack();
|
||||
int count = frame.count();
|
||||
int count = frame.resetCount();
|
||||
if (count == 0) {
|
||||
// If we've decoded, but could not execute the first op, just drop the p-code steps
|
||||
emuThread.dropInstruction();
|
||||
|
@ -146,11 +154,11 @@ public interface Scheduler {
|
|||
}
|
||||
// The +1 accounts for the decode step
|
||||
return new RecordRunResult(
|
||||
completedSteps.steppedPcodeForward(eventThread, count + 1), e);
|
||||
completedSteps.steppedPcodeForward(eventThread, count + 1).assumeRecorded(), e);
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
return new RecordRunResult(
|
||||
completedSteps.steppedForward(eventThread, completedTicks), e);
|
||||
completedSteps.steppedForward(eventThread, completedTicks).assumeRecorded(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
@ -21,6 +21,7 @@ import java.util.stream.Collectors;
|
|||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ghidra.pcode.emu.PcodeMachine;
|
||||
import ghidra.pcode.emu.PcodeThread;
|
||||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
|
@ -240,7 +241,7 @@ public class Sequence implements Comparable<Sequence> {
|
|||
}
|
||||
|
||||
/**
|
||||
* Richly compare to sequences
|
||||
* Richly compare two sequences
|
||||
*
|
||||
* <p>
|
||||
* The result indicates not only which is "less" or "greater" than the other, but also indicates
|
||||
|
@ -355,6 +356,14 @@ public class Sequence implements Comparable<Sequence> {
|
|||
return count;
|
||||
}
|
||||
|
||||
public long totalSkipCount() {
|
||||
long count = 0;
|
||||
for (Step step : steps) {
|
||||
count += step.getSkipCount();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute to total number of patches specified
|
||||
*
|
||||
|
@ -440,4 +449,25 @@ public class Sequence implements Comparable<Sequence> {
|
|||
}
|
||||
return thread;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the first instruction step is actually to finish an incomplete instruction.
|
||||
*
|
||||
* @param thread the thread whose instruction to potentially finish
|
||||
* @param machine a machine bound to the trace whose current state reflects the given position
|
||||
* @return if a finish was performed, this sequence with one initial step removed, i.e., a
|
||||
* sequence representing the steps remaining
|
||||
*/
|
||||
Sequence checkFinish(TraceThread thread, PcodeMachine<?> machine) {
|
||||
PcodeThread<?> emuThread = machine.getThread(thread.getPath(), true);
|
||||
if (emuThread.getFrame() == null) {
|
||||
return this;
|
||||
}
|
||||
Sequence result = new Sequence(new ArrayList<>(steps));
|
||||
emuThread.finishInstruction();
|
||||
if (result.steps.get(0).rewind(1) == 0) {
|
||||
result.steps.remove(0);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
@ -48,6 +48,11 @@ public class SkipStep extends AbstractStep {
|
|||
return StepType.SKIP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSkipCount() {
|
||||
return tickCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String toStringStepPart() {
|
||||
return String.format("s%d", tickCount);
|
||||
|
@ -66,7 +71,7 @@ public class SkipStep extends AbstractStep {
|
|||
}
|
||||
|
||||
@Override
|
||||
public <T> void execute(PcodeThread<T> emuThread, Stepper stepper, TaskMonitor monitor)
|
||||
public void execute(PcodeThread<?> emuThread, Stepper stepper, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
for (int i = 0; i < tickCount; i++) {
|
||||
monitor.incrementProgress(1);
|
||||
|
|
|
@ -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.
|
||||
|
@ -116,6 +116,8 @@ public interface Step extends Comparable<Step> {
|
|||
|
||||
long getTickCount();
|
||||
|
||||
long getSkipCount();
|
||||
|
||||
long getPatchCount();
|
||||
|
||||
/**
|
||||
|
@ -147,7 +149,7 @@ public interface Step extends Comparable<Step> {
|
|||
* method sets the count to 0 and returns the (positive) difference, indicating this step should
|
||||
* be removed from the sequence, and the remaining steps rewound from the preceding step.
|
||||
*
|
||||
* @param steps the count to rewind
|
||||
* @param count the count to rewind
|
||||
* @return the number of steps remaining
|
||||
*/
|
||||
long rewind(long count);
|
||||
|
@ -155,7 +157,7 @@ public interface Step extends Comparable<Step> {
|
|||
/**
|
||||
* Richly compare this step to another
|
||||
*
|
||||
* @param step the object of comparison (this being the subject)
|
||||
* @param that the object of comparison (this being the subject)
|
||||
* @return a result describing the relationship from subject to object
|
||||
*/
|
||||
CompareResult compareStep(Step that);
|
||||
|
@ -183,7 +185,7 @@ public interface Step extends Comparable<Step> {
|
|||
return thread;
|
||||
}
|
||||
|
||||
<T> void execute(PcodeThread<T> emuThread, Stepper stepper, TaskMonitor monitor)
|
||||
void execute(PcodeThread<?> emuThread, Stepper stepper, TaskMonitor monitor)
|
||||
throws CancelledException;
|
||||
|
||||
long coalescePatches(Language language, List<Step> steps);
|
||||
|
|
|
@ -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.
|
||||
|
@ -48,6 +48,11 @@ public class TickStep extends AbstractStep {
|
|||
return StepType.TICK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSkipCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String toStringStepPart() {
|
||||
return Long.toString(tickCount);
|
||||
|
@ -66,7 +71,7 @@ public class TickStep extends AbstractStep {
|
|||
}
|
||||
|
||||
@Override
|
||||
public <T> void execute(PcodeThread<T> emuThread, Stepper stepper, TaskMonitor monitor)
|
||||
public void execute(PcodeThread<?> emuThread, Stepper stepper, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
for (int i = 0; i < tickCount; i++) {
|
||||
monitor.incrementProgress(1);
|
||||
|
|
|
@ -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.
|
||||
|
@ -39,7 +39,7 @@ public class TraceSchedule implements Comparable<TraceSchedule> {
|
|||
* @return the schedule
|
||||
*/
|
||||
public static final TraceSchedule snap(long snap) {
|
||||
return new TraceSchedule(snap, new Sequence(), new Sequence());
|
||||
return new TraceSchedule(snap, new Sequence(), new Sequence(), Source.RECORD);
|
||||
}
|
||||
|
||||
private static final String PARSE_ERR_MSG =
|
||||
|
@ -55,9 +55,10 @@ public class TraceSchedule implements Comparable<TraceSchedule> {
|
|||
* threads forward, and/or patching machine state.
|
||||
*
|
||||
* @param spec the string specification
|
||||
* @param source the presumed source of the schedule
|
||||
* @return the parsed schedule
|
||||
*/
|
||||
public static TraceSchedule parse(String spec) {
|
||||
public static TraceSchedule parse(String spec, Source source) {
|
||||
String[] parts = spec.split(":", 2);
|
||||
if (parts.length > 2) {
|
||||
throw new AssertionError();
|
||||
|
@ -98,24 +99,76 @@ public class TraceSchedule implements Comparable<TraceSchedule> {
|
|||
ticks = new Sequence();
|
||||
pTicks = new Sequence();
|
||||
}
|
||||
return new TraceSchedule(snap, ticks, pTicks);
|
||||
return new TraceSchedule(snap, ticks, pTicks, source);
|
||||
}
|
||||
|
||||
/**
|
||||
* As in {@link #parse(String, Source)}, but assumed abnormal
|
||||
*
|
||||
* @param spec the string specification
|
||||
* @return the parsed schedule
|
||||
*/
|
||||
public static TraceSchedule parse(String spec) {
|
||||
return parse(spec, Source.INPUT);
|
||||
}
|
||||
|
||||
public enum Source {
|
||||
/**
|
||||
* The schedule comes from the user or some source other than a recorded emulation schedule.
|
||||
*/
|
||||
INPUT {
|
||||
@Override
|
||||
Source adjust(long pTickCount, long pPatchCount, long pSkipCount) {
|
||||
// The first tick is decode, so <= 1 tick is definitely not a full instruction
|
||||
return pTickCount <= 1 && pPatchCount == 0 && pSkipCount == 0 ? RECORD : INPUT;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* The schedule comes from recording actual emulation.
|
||||
*
|
||||
* <p>
|
||||
* Specifically, the p-code steps must be known not to exceed one instruction.
|
||||
*/
|
||||
RECORD {
|
||||
@Override
|
||||
Source adjust(long pTickCount, long pPatchCount, long pSkipCount) {
|
||||
return pPatchCount == 0 && pSkipCount == 0 ? RECORD : INPUT;
|
||||
}
|
||||
};
|
||||
|
||||
abstract Source adjust(long tickCount, long patchCount, long skipCount);
|
||||
}
|
||||
|
||||
private final long snap;
|
||||
private final Sequence steps;
|
||||
private final Sequence pSteps;
|
||||
private final Source source;
|
||||
|
||||
/**
|
||||
* Construct the given schedule
|
||||
*
|
||||
* @param snap the initial trace snapshot
|
||||
* @param steps the step sequence
|
||||
* @param pSteps the of p-code step sequence
|
||||
* @param pSteps the p-code step sequence
|
||||
* @param source if the p-code steps are known not to exceed one instruction
|
||||
*/
|
||||
public TraceSchedule(long snap, Sequence steps, Sequence pSteps) {
|
||||
public TraceSchedule(long snap, Sequence steps, Sequence pSteps, Source source) {
|
||||
this.snap = snap;
|
||||
this.steps = steps;
|
||||
this.pSteps = pSteps;
|
||||
this.source = source.adjust(pSteps.totalTickCount(), pSteps.totalPatchCount(),
|
||||
pSteps.totalSkipCount());
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct the given schedule, but assumed abnormal
|
||||
*
|
||||
* @param snap the initial trace snapshot
|
||||
* @param steps the step sequence
|
||||
* @param pSteps the p-code step sequence
|
||||
*/
|
||||
public TraceSchedule(long snap, Sequence steps, Sequence pSteps) {
|
||||
this(snap, steps, pSteps, Source.INPUT);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -152,33 +205,17 @@ public class TraceSchedule implements Comparable<TraceSchedule> {
|
|||
}
|
||||
|
||||
result = this.steps.compareSeq(that.steps);
|
||||
switch (result) {
|
||||
case UNREL_LT:
|
||||
case UNREL_GT:
|
||||
return result;
|
||||
case REL_LT:
|
||||
if (this.pSteps.isNop()) {
|
||||
return CompareResult.REL_LT;
|
||||
}
|
||||
else {
|
||||
return CompareResult.UNREL_LT;
|
||||
}
|
||||
case REL_GT:
|
||||
if (that.pSteps.isNop()) {
|
||||
return CompareResult.REL_GT;
|
||||
}
|
||||
else {
|
||||
return CompareResult.UNREL_GT;
|
||||
}
|
||||
default: // EQUALS, compare pSteps
|
||||
}
|
||||
|
||||
result = this.pSteps.compareSeq(that.pSteps);
|
||||
if (result != CompareResult.EQUALS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return CompareResult.EQUALS;
|
||||
return switch (result) {
|
||||
case UNREL_LT, UNREL_GT -> result;
|
||||
case REL_LT -> (this.pSteps.isNop() || this.source == Source.RECORD)
|
||||
? CompareResult.REL_LT
|
||||
: CompareResult.UNREL_LT;
|
||||
case REL_GT -> (that.pSteps.isNop() || that.source == Source.RECORD)
|
||||
? CompareResult.REL_GT
|
||||
: CompareResult.UNREL_GT;
|
||||
default -> this.pSteps.compareSeq(that.pSteps);
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -222,10 +259,19 @@ public class TraceSchedule implements Comparable<TraceSchedule> {
|
|||
return steps.isNop() && pSteps.isNop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this schedule has instruction steps
|
||||
*
|
||||
* @return true if this indicates at least one instruction step
|
||||
*/
|
||||
public boolean hasSteps() {
|
||||
return !steps.isNop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the source snapshot
|
||||
*
|
||||
* @return
|
||||
* @return the snapshot key
|
||||
*/
|
||||
public long getSnap() {
|
||||
return snap;
|
||||
|
@ -234,7 +280,7 @@ public class TraceSchedule implements Comparable<TraceSchedule> {
|
|||
/**
|
||||
* Get the last thread key stepped by this schedule
|
||||
*
|
||||
* @return
|
||||
* @return the thread key
|
||||
*/
|
||||
public long getLastThreadKey() {
|
||||
long last = pSteps.getLastThreadKey();
|
||||
|
@ -396,6 +442,7 @@ public class TraceSchedule implements Comparable<TraceSchedule> {
|
|||
pRemains.execute(trace, lastThread, machine, Stepper.pcode(), monitor);
|
||||
}
|
||||
else {
|
||||
remains = remains.checkFinish(lastThread, machine);
|
||||
lastThread =
|
||||
remains.execute(trace, lastThread, machine, Stepper.instruction(), monitor);
|
||||
lastThread = pSteps.execute(trace, lastThread, machine, Stepper.pcode(), monitor);
|
||||
|
@ -417,7 +464,7 @@ public class TraceSchedule implements Comparable<TraceSchedule> {
|
|||
public TraceSchedule steppedForward(TraceThread thread, long tickCount) {
|
||||
Sequence steps = this.steps.clone();
|
||||
steps.advance(new TickStep(thread == null ? -1 : thread.getKey(), tickCount));
|
||||
return new TraceSchedule(snap, steps, new Sequence());
|
||||
return new TraceSchedule(snap, steps, new Sequence(), Source.RECORD);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -430,7 +477,7 @@ public class TraceSchedule implements Comparable<TraceSchedule> {
|
|||
public TraceSchedule skippedForward(TraceThread thread, long tickCount) {
|
||||
Sequence steps = this.steps.clone();
|
||||
steps.advance(new SkipStep(thread == null ? -1 : thread.getKey(), tickCount));
|
||||
return new TraceSchedule(snap, steps, new Sequence());
|
||||
return new TraceSchedule(snap, steps, new Sequence(), Source.RECORD);
|
||||
}
|
||||
|
||||
protected TraceSchedule doSteppedBackward(Trace trace, long tickCount, Set<Long> visited) {
|
||||
|
@ -454,7 +501,7 @@ public class TraceSchedule implements Comparable<TraceSchedule> {
|
|||
}
|
||||
Sequence steps = this.steps.clone();
|
||||
steps.rewind(tickCount);
|
||||
return new TraceSchedule(snap, steps, new Sequence());
|
||||
return new TraceSchedule(snap, steps, new Sequence(), Source.RECORD);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -486,7 +533,7 @@ public class TraceSchedule implements Comparable<TraceSchedule> {
|
|||
public TraceSchedule steppedPcodeForward(TraceThread thread, int pTickCount) {
|
||||
Sequence pTicks = this.pSteps.clone();
|
||||
pTicks.advance(new TickStep(thread == null ? -1 : thread.getKey(), pTickCount));
|
||||
return new TraceSchedule(snap, steps.clone(), pTicks);
|
||||
return new TraceSchedule(snap, steps.clone(), pTicks, Source.INPUT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -499,7 +546,7 @@ public class TraceSchedule implements Comparable<TraceSchedule> {
|
|||
public TraceSchedule skippedPcodeForward(TraceThread thread, int pTickCount) {
|
||||
Sequence pTicks = this.pSteps.clone();
|
||||
pTicks.advance(new SkipStep(thread == null ? -1 : thread.getKey(), pTickCount));
|
||||
return new TraceSchedule(snap, steps.clone(), pTicks);
|
||||
return new TraceSchedule(snap, steps.clone(), pTicks, Source.INPUT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -519,7 +566,7 @@ public class TraceSchedule implements Comparable<TraceSchedule> {
|
|||
}
|
||||
Sequence pTicks = this.pSteps.clone();
|
||||
pTicks.rewind(pStepCount);
|
||||
return new TraceSchedule(snap, steps.clone(), pTicks);
|
||||
return new TraceSchedule(snap, steps.clone(), pTicks, Source.INPUT);
|
||||
}
|
||||
|
||||
private long keyOf(TraceThread thread) {
|
||||
|
@ -530,6 +577,7 @@ public class TraceSchedule implements Comparable<TraceSchedule> {
|
|||
* Returns the equivalent of executing this schedule then performing a given patch
|
||||
*
|
||||
* @param thread the thread context for the patch; cannot be null
|
||||
* @param language the sleigh language for the patch
|
||||
* @param sleigh a single line of sleigh, excluding the terminating semicolon.
|
||||
* @return the resulting schedule
|
||||
*/
|
||||
|
@ -538,19 +586,20 @@ public class TraceSchedule implements Comparable<TraceSchedule> {
|
|||
Sequence pTicks = this.pSteps.clone();
|
||||
pTicks.advance(new PatchStep(thread.getKey(), sleigh));
|
||||
pTicks.coalescePatches(language);
|
||||
return new TraceSchedule(snap, steps.clone(), pTicks);
|
||||
return new TraceSchedule(snap, steps.clone(), pTicks, Source.INPUT);
|
||||
}
|
||||
Sequence ticks = this.steps.clone();
|
||||
ticks.advance(new PatchStep(keyOf(thread), sleigh));
|
||||
ticks.coalescePatches(language);
|
||||
return new TraceSchedule(snap, ticks, new Sequence());
|
||||
return new TraceSchedule(snap, ticks, new Sequence(), Source.RECORD);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the equivalent of executing this schedule then performing the given patches
|
||||
*
|
||||
* @param thread the thread context for the patch; cannot be null
|
||||
* @param sleigh the lines of sleigh, excluding the terminating semicolons.
|
||||
* @param language the sleigh language for the patch
|
||||
* @param sleigh the lines of sleigh, excluding the terminating semicolons
|
||||
* @return the resulting schedule
|
||||
*/
|
||||
public TraceSchedule patched(TraceThread thread, Language language, List<String> sleigh) {
|
||||
|
@ -560,14 +609,14 @@ public class TraceSchedule implements Comparable<TraceSchedule> {
|
|||
pTicks.advance(new PatchStep(thread.getKey(), line));
|
||||
}
|
||||
pTicks.coalescePatches(language);
|
||||
return new TraceSchedule(snap, steps.clone(), pTicks);
|
||||
return new TraceSchedule(snap, steps.clone(), pTicks, Source.INPUT);
|
||||
}
|
||||
Sequence ticks = this.steps.clone();
|
||||
for (String line : sleigh) {
|
||||
ticks.advance(new PatchStep(thread.getKey(), line));
|
||||
}
|
||||
ticks.coalescePatches(language);
|
||||
return new TraceSchedule(snap, ticks, new Sequence());
|
||||
return new TraceSchedule(snap, ticks, new Sequence(), Source.RECORD);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -575,7 +624,7 @@ public class TraceSchedule implements Comparable<TraceSchedule> {
|
|||
*
|
||||
* <p>
|
||||
* This operation cannot be used to append instruction steps after p-code steps. Thus, if this
|
||||
* schedule contains any p-code steps and {@code} next has instruction steps, an error will be
|
||||
* schedule contains any p-code steps and {@code next} has instruction steps, an error will be
|
||||
*
|
||||
* @param next the schedule to append. Its snap is ignored.
|
||||
* @return the complete schedule
|
||||
|
@ -586,16 +635,25 @@ public class TraceSchedule implements Comparable<TraceSchedule> {
|
|||
if (this.pSteps.isNop()) {
|
||||
Sequence ticks = this.steps.clone();
|
||||
ticks.advance(next.steps);
|
||||
return new TraceSchedule(this.snap, ticks, next.pSteps.clone());
|
||||
return new TraceSchedule(this.snap, ticks, next.pSteps.clone(), next.source);
|
||||
}
|
||||
else if (next.steps.isNop()) {
|
||||
Sequence pTicks = this.steps.clone();
|
||||
Sequence pTicks = this.pSteps.clone();
|
||||
pTicks.advance(next.pSteps);
|
||||
return new TraceSchedule(this.snap, this.steps.clone(), pTicks);
|
||||
return new TraceSchedule(this.snap, this.steps.clone(), pTicks, Source.INPUT);
|
||||
}
|
||||
throw new IllegalArgumentException("Cannot have instructions steps following p-code steps");
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop the p-code steps
|
||||
*
|
||||
* @return the schedule without ops
|
||||
*/
|
||||
public TraceSchedule dropPSteps() {
|
||||
return new TraceSchedule(this.snap, this.steps, new Sequence());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the threads involved in the schedule
|
||||
*
|
||||
|
@ -611,4 +669,8 @@ public class TraceSchedule implements Comparable<TraceSchedule> {
|
|||
result.remove(null);
|
||||
return result;
|
||||
}
|
||||
|
||||
public TraceSchedule assumeRecorded() {
|
||||
return new TraceSchedule(snap, steps, pSteps, Source.RECORD);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
@ -224,19 +224,30 @@ public class TraceScheduleTest extends AbstractGhidraHeadlessIntegrationTest {
|
|||
expectU("0:10", "1:10");
|
||||
expectU("0:t0-10", "0:t1-10");
|
||||
// We don't know how many p-code steps complete an instruction step
|
||||
expectU("0:t0-10.1", "0:t0-11");
|
||||
// But we need at least 2 to actually enter the instruction
|
||||
expectU("0:t0-10.2", "0:t0-11");
|
||||
expectU("0:t0-10;t1-5", "0:t0-11;t1-5");
|
||||
|
||||
expectR("0:t0-10", "0:t0-11");
|
||||
expectR("0:t0-10", "0:t0-10;t1-5");
|
||||
expectR("0:t0-10", "0:t0-11;t1-5");
|
||||
expectR("0:t0-10", "0:t0-10.1");
|
||||
expectR("0:t0-10", "0:t0-11.1");
|
||||
expectR("0:t0-10", "0:t0-10;t1-5.1");
|
||||
expectR("0:t0-10", "0:t0-11;t1-5.1");
|
||||
expectR("0:t0-10", "0:t0-10.2");
|
||||
expectR("0:t0-10", "0:t0-11.2");
|
||||
expectR("0:t0-10", "0:t0-10;t1-5.2");
|
||||
expectR("0:t0-10", "0:t0-11;t1-5.2");
|
||||
|
||||
expectE("0:t0-10", "0:t0-10");
|
||||
expectE("0:t0-10.1", "0:t0-10.1");
|
||||
expectE("0:t0-10.2", "0:t0-10.2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCompare2() {
|
||||
TraceSchedule timeL = TraceSchedule.parse("0:t0-2.5");
|
||||
TraceSchedule timeR = TraceSchedule.parse("0:t0-3");
|
||||
|
||||
assertEquals(CompareResult.UNREL_LT, timeL.compareSchedule(timeR));
|
||||
assertEquals(CompareResult.REL_LT, timeL.assumeRecorded().compareSchedule(timeR));
|
||||
assertEquals(CompareResult.UNREL_LT, timeL.compareSchedule(timeR.assumeRecorded()));
|
||||
}
|
||||
|
||||
public String strRelativize(String fromSpec, String toSpec) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue