mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
Merge remote-tracking branch 'origin/GP-1208_Dan_emuSyscalls-4--SQUASHED'
This commit is contained in:
commit
d428ecd97a
144 changed files with 12712 additions and 804 deletions
|
@ -36,16 +36,12 @@ public abstract class AbstractCheckedTraceCachedWriteBytesPcodeExecutorState
|
|||
@Override
|
||||
public byte[] read(long offset, int size) {
|
||||
RangeSet<UnsignedLong> uninitialized =
|
||||
cache.getUninitialized(offset, offset + size - 1);
|
||||
|
||||
bytes.getUninitialized(offset, offset + size - 1);
|
||||
if (!uninitialized.isEmpty()) {
|
||||
size = checkUninitialized(source, space.getAddress(offset), size,
|
||||
size = checkUninitialized(backing, space.getAddress(offset), size,
|
||||
addrSet(uninitialized));
|
||||
if (source != null) {
|
||||
readUninitializedFromSource(uninitialized);
|
||||
}
|
||||
}
|
||||
return readCached(offset, size);
|
||||
return super.read(offset, size);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,10 +51,10 @@ public abstract class AbstractCheckedTraceCachedWriteBytesPcodeExecutorState
|
|||
}
|
||||
|
||||
@Override
|
||||
protected CachedSpace newSpace(AddressSpace space, TraceMemorySpace source, long snap) {
|
||||
return new CheckedCachedSpace(language, space, source, snap);
|
||||
protected CachedSpace newSpace(AddressSpace space, TraceMemorySpace backing) {
|
||||
return new CheckedCachedSpace(language, space, backing, snap);
|
||||
}
|
||||
|
||||
protected abstract int checkUninitialized(TraceMemorySpace source, Address start, int size,
|
||||
protected abstract int checkUninitialized(TraceMemorySpace backing, Address start, int size,
|
||||
AddressSet uninitialized);
|
||||
}
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
/* ###
|
||||
* 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.pcode.exec.trace;
|
||||
|
||||
public interface BytesPcodeExecutorStateMixin<A, T> {
|
||||
T fromConstant(long constant);
|
||||
|
||||
long offsetToLong(A offset);
|
||||
|
||||
byte[] toBytes(T val, int size);
|
||||
|
||||
T fromBytes(byte[] data);
|
||||
}
|
|
@ -39,16 +39,16 @@ public class RequireIsKnownTraceCachedWriteBytesPcodeExecutorState
|
|||
}
|
||||
|
||||
@Override
|
||||
protected int checkUninitialized(TraceMemorySpace source, Address start, int size,
|
||||
protected int checkUninitialized(TraceMemorySpace backing, Address start, int size,
|
||||
AddressSet uninitialized) {
|
||||
if (source == null) {
|
||||
if (backing == null) {
|
||||
if (!uninitialized.contains(start)) {
|
||||
return (int) uninitialized.getMinAddress().subtract(start);
|
||||
}
|
||||
throw excFor(uninitialized);
|
||||
}
|
||||
// TODO: Could find first instead?
|
||||
AddressSetView unknown = uninitialized.subtract(getKnown(source));
|
||||
AddressSetView unknown = uninitialized.subtract(getKnown(backing));
|
||||
if (unknown.isEmpty()) {
|
||||
return size;
|
||||
}
|
||||
|
|
|
@ -16,27 +16,20 @@
|
|||
package ghidra.pcode.exec.trace;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.*;
|
||||
|
||||
import com.google.common.collect.*;
|
||||
import com.google.common.primitives.UnsignedLong;
|
||||
|
||||
import ghidra.generic.util.datastruct.SemisparseByteArray;
|
||||
import ghidra.pcode.exec.AbstractLongOffsetPcodeExecutorState;
|
||||
import ghidra.pcode.exec.BytesPcodeArithmetic;
|
||||
import ghidra.pcode.exec.AbstractBytesPcodeExecutorState;
|
||||
import ghidra.pcode.exec.BytesPcodeExecutorStateSpace;
|
||||
import ghidra.pcode.exec.trace.TraceCachedWriteBytesPcodeExecutorState.CachedSpace;
|
||||
import ghidra.pcode.utils.Utils;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.address.AddressSet;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
import ghidra.program.model.mem.Memory;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.memory.TraceMemorySpace;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.trace.util.MemBufferAdapter;
|
||||
import ghidra.util.MathUtilities;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
/**
|
||||
* A state which reads bytes from a trace, but caches writes internally.
|
||||
|
@ -47,41 +40,7 @@ import ghidra.util.Msg;
|
|||
* later time.
|
||||
*/
|
||||
public class TraceCachedWriteBytesPcodeExecutorState
|
||||
extends AbstractLongOffsetPcodeExecutorState<byte[], CachedSpace> {
|
||||
|
||||
protected class StateMemBuffer implements MemBufferAdapter {
|
||||
protected final Address address;
|
||||
protected final CachedSpace source;
|
||||
|
||||
public StateMemBuffer(Address address, CachedSpace source) {
|
||||
this.address = address;
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Memory getMemory() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBigEndian() {
|
||||
return trace.getBaseLanguage().isBigEndian();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBytes(ByteBuffer buffer, int addressOffset) {
|
||||
byte[] data = source.read(address.getOffset() + addressOffset, buffer.remaining());
|
||||
buffer.put(data);
|
||||
return data.length;
|
||||
}
|
||||
}
|
||||
|
||||
protected final Map<AddressSpace, CachedSpace> spaces = new HashMap<>();
|
||||
extends AbstractBytesPcodeExecutorState<TraceMemorySpace, CachedSpace> {
|
||||
|
||||
protected final Trace trace;
|
||||
protected final long snap;
|
||||
|
@ -90,136 +49,53 @@ public class TraceCachedWriteBytesPcodeExecutorState
|
|||
|
||||
public TraceCachedWriteBytesPcodeExecutorState(Trace trace, long snap, TraceThread thread,
|
||||
int frame) {
|
||||
super(trace.getBaseLanguage(), BytesPcodeArithmetic.forLanguage(trace.getBaseLanguage()));
|
||||
super(trace.getBaseLanguage());
|
||||
this.trace = trace;
|
||||
this.snap = snap;
|
||||
this.thread = thread;
|
||||
this.frame = frame;
|
||||
}
|
||||
|
||||
protected static class CachedSpace {
|
||||
protected final SemisparseByteArray cache = new SemisparseByteArray();
|
||||
public static class CachedSpace extends BytesPcodeExecutorStateSpace<TraceMemorySpace> {
|
||||
protected final RangeSet<UnsignedLong> written = TreeRangeSet.create();
|
||||
protected final Language language; // For logging diagnostic
|
||||
protected final AddressSpace space;
|
||||
protected final TraceMemorySpace source;
|
||||
protected final long snap;
|
||||
|
||||
public CachedSpace(Language language, AddressSpace space, TraceMemorySpace source,
|
||||
public CachedSpace(Language language, AddressSpace space, TraceMemorySpace backing,
|
||||
long snap) {
|
||||
this.language = language;
|
||||
this.space = space;
|
||||
this.source = source;
|
||||
super(language, space, backing);
|
||||
this.snap = snap;
|
||||
}
|
||||
|
||||
public void write(long offset, byte[] buffer, int srcOffset, int length) {
|
||||
cache.putData(offset, buffer, srcOffset, length);
|
||||
@Override
|
||||
public void write(long offset, byte[] val, int srcOffset, int length) {
|
||||
super.write(offset, val, srcOffset, length);
|
||||
UnsignedLong uLoc = UnsignedLong.fromLongBits(offset);
|
||||
UnsignedLong uEnd = UnsignedLong.fromLongBits(offset + length);
|
||||
written.add(Range.closedOpen(uLoc, uEnd));
|
||||
}
|
||||
|
||||
public static long lower(Range<UnsignedLong> rng) {
|
||||
return rng.lowerBoundType() == BoundType.CLOSED
|
||||
? rng.lowerEndpoint().longValue()
|
||||
: rng.lowerEndpoint().longValue() + 1;
|
||||
}
|
||||
|
||||
public static long upper(Range<UnsignedLong> rng) {
|
||||
return rng.upperBoundType() == BoundType.CLOSED
|
||||
? rng.upperEndpoint().longValue()
|
||||
: rng.upperEndpoint().longValue() - 1;
|
||||
}
|
||||
|
||||
protected void readUninitializedFromSource(RangeSet<UnsignedLong> uninitialized) {
|
||||
@Override
|
||||
protected void readUninitializedFromBacking(RangeSet<UnsignedLong> uninitialized) {
|
||||
if (!uninitialized.isEmpty()) {
|
||||
// TODO: Warn or bail when reading UNKNOWN bytes
|
||||
// NOTE: Read without regard to gaps
|
||||
// NOTE: Cannot write those gaps, though!!!
|
||||
Range<UnsignedLong> toRead = uninitialized.span();
|
||||
assert toRead.hasUpperBound() && toRead.hasLowerBound();
|
||||
long lower = lower(toRead);
|
||||
long upper = upper(toRead);
|
||||
ByteBuffer buf = ByteBuffer.allocate((int) (upper - lower + 1));
|
||||
source.getBytes(snap, space.getAddress(lower), buf);
|
||||
backing.getBytes(snap, space.getAddress(lower), buf);
|
||||
for (Range<UnsignedLong> rng : uninitialized.asRanges()) {
|
||||
long l = lower(rng);
|
||||
long u = upper(rng);
|
||||
cache.putData(l, buf.array(), (int) (l - lower), (int) (u - l + 1));
|
||||
bytes.putData(l, buf.array(), (int) (l - lower), (int) (u - l + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected byte[] readCached(long offset, int size) {
|
||||
byte[] data = new byte[size];
|
||||
cache.getData(offset, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
protected AddressRange addrRng(Range<UnsignedLong> rng) {
|
||||
Address start = space.getAddress(lower(rng));
|
||||
Address end = space.getAddress(upper(rng));
|
||||
return new AddressRangeImpl(start, end);
|
||||
}
|
||||
|
||||
protected AddressSet addrSet(RangeSet<UnsignedLong> set) {
|
||||
AddressSet result = new AddressSet();
|
||||
for (Range<UnsignedLong> rng : set.asRanges()) {
|
||||
result.add(addrRng(rng));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected Set<Register> getRegs(AddressSet set) {
|
||||
Set<Register> regs = new TreeSet<>();
|
||||
for (AddressRange rng : set) {
|
||||
Register r = language.getRegister(rng.getMinAddress(), (int) rng.getLength());
|
||||
if (r != null) {
|
||||
regs.add(r);
|
||||
}
|
||||
else {
|
||||
regs.addAll(Arrays.asList(language.getRegisters(rng.getMinAddress())));
|
||||
}
|
||||
}
|
||||
return regs;
|
||||
}
|
||||
|
||||
protected void warnState(AddressSet set, String message) {
|
||||
Set<Register> regs = getRegs(set);
|
||||
if (regs.isEmpty()) {
|
||||
Msg.warn(this, message + ": " + set);
|
||||
}
|
||||
else {
|
||||
Msg.warn(this, message + ": " + set + " (registers " + regs + ")");
|
||||
}
|
||||
}
|
||||
|
||||
protected void warnUninit(RangeSet<UnsignedLong> uninit) {
|
||||
AddressSet uninitialized = addrSet(uninit);
|
||||
Set<Register> regs = getRegs(uninitialized);
|
||||
if (regs.isEmpty()) {
|
||||
Msg.warn(this, "Emulator read from uninitialized state: " + uninit);
|
||||
}
|
||||
Msg.warn(this, "Emulator read from uninitialized state: " + uninit +
|
||||
" (includes registers: " + regs + ")");
|
||||
}
|
||||
|
||||
protected void warnUnknown(AddressSet unknown) {
|
||||
Set<Register> regs = getRegs(unknown);
|
||||
Msg.warn(this, "Emulator state initialized from UNKNOWN: " + unknown +
|
||||
"(includes registers: " + regs + ")");
|
||||
}
|
||||
|
||||
public byte[] read(long offset, int size) {
|
||||
if (source != null) {
|
||||
// TODO: Warn or bail when reading UNKNOWN bytes
|
||||
// NOTE: Read without regard to gaps
|
||||
// NOTE: Cannot write those gaps, though!!!
|
||||
readUninitializedFromSource(cache.getUninitialized(offset, offset + size - 1));
|
||||
}
|
||||
RangeSet<UnsignedLong> stillUninit = cache.getUninitialized(offset, offset + size - 1);
|
||||
if (!stillUninit.isEmpty()) {
|
||||
warnUninit(stillUninit);
|
||||
}
|
||||
return readCached(offset, size);
|
||||
warnAddressSet("Emulator state initialized from UNKNOWN", unknown);
|
||||
}
|
||||
|
||||
// Must already have started a transaction
|
||||
|
@ -238,7 +114,7 @@ public class TraceCachedWriteBytesPcodeExecutorState
|
|||
long fullLen = range.upperEndpoint().longValue() - lower;
|
||||
while (fullLen > 0) {
|
||||
int len = MathUtilities.unsignedMin(data.length, fullLen);
|
||||
cache.getData(lower, data, 0, len);
|
||||
bytes.getData(lower, data, 0, len);
|
||||
buf.position(0);
|
||||
buf.limit(len);
|
||||
mem.putBytes(snap, space.getAddress(lower), buf);
|
||||
|
@ -288,47 +164,12 @@ public class TraceCachedWriteBytesPcodeExecutorState
|
|||
}
|
||||
|
||||
@Override
|
||||
protected long offsetToLong(byte[] offset) {
|
||||
return Utils.bytesToLong(offset, offset.length, language.isBigEndian());
|
||||
protected TraceMemorySpace getBacking(AddressSpace space) {
|
||||
return TraceSleighUtils.getSpaceForExecution(space, trace, thread, frame, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] longToOffset(AddressSpace space, long l) {
|
||||
return arithmetic.fromConst(l, space.getPointerSize());
|
||||
}
|
||||
|
||||
protected CachedSpace newSpace(AddressSpace space, TraceMemorySpace source, long snap) {
|
||||
return new CachedSpace(language, space, source, snap);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CachedSpace getForSpace(AddressSpace space, boolean toWrite) {
|
||||
return spaces.computeIfAbsent(space, s -> {
|
||||
TraceMemorySpace tms = s.isUniqueSpace() ? null
|
||||
: TraceSleighUtils.getSpaceForExecution(s, trace, thread, frame, false);
|
||||
return newSpace(s, tms, snap);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setInSpace(CachedSpace space, long offset, int size, byte[] val) {
|
||||
assert size == val.length;
|
||||
space.write(offset, val, 0, val.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] getFromSpace(CachedSpace space, long offset, int size) {
|
||||
byte[] read = space.read(offset, size);
|
||||
if (read.length != size) {
|
||||
Address addr = space.space.getAddress(offset);
|
||||
throw new UnknownStatePcodeExecutionException("Incomplete read (" + read.length +
|
||||
" of " + size + " bytes)", language, addr.add(read.length), size - read.length);
|
||||
}
|
||||
return read;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MemBuffer getConcreteBuffer(Address address) {
|
||||
return new StateMemBuffer(address, getForSpace(address.getAddressSpace(), false));
|
||||
protected CachedSpace newSpace(AddressSpace space, TraceMemorySpace backing) {
|
||||
return new CachedSpace(language, space, backing, snap);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,4 +59,9 @@ public enum TraceMemoryStatePcodeArithmetic implements PcodeArithmetic<TraceMemo
|
|||
public BigInteger toConcrete(TraceMemoryState value, boolean isContextreg) {
|
||||
throw new AssertionError("Cannot make TraceMemoryState a 'concrete value'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TraceMemoryState sizeOf(TraceMemoryState value) {
|
||||
throw new AssertionError("Cannot get size of a TraceMemoryState");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,10 +18,9 @@ package ghidra.pcode.exec.trace;
|
|||
import com.google.common.collect.Range;
|
||||
|
||||
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
||||
import ghidra.pcode.emu.AbstractPcodeEmulator;
|
||||
import ghidra.pcode.emu.PcodeEmulator;
|
||||
import ghidra.pcode.emu.PcodeThread;
|
||||
import ghidra.pcode.exec.PcodeExecutorState;
|
||||
import ghidra.pcode.exec.SleighUseropLibrary;
|
||||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.trace.model.Trace;
|
||||
import ghidra.trace.model.stack.TraceStack;
|
||||
|
@ -31,7 +30,7 @@ import ghidra.trace.model.thread.TraceThreadManager;
|
|||
/**
|
||||
* An emulator that can read initial state from a trace
|
||||
*/
|
||||
public class TracePcodeEmulator extends AbstractPcodeEmulator {
|
||||
public class TracePcodeEmulator extends PcodeEmulator {
|
||||
private static SleighLanguage assertSleigh(Language language) {
|
||||
if (!(language instanceof SleighLanguage)) {
|
||||
throw new IllegalArgumentException("Emulation requires a sleigh language");
|
||||
|
@ -42,16 +41,12 @@ public class TracePcodeEmulator extends AbstractPcodeEmulator {
|
|||
protected final Trace trace;
|
||||
protected final long snap;
|
||||
|
||||
public TracePcodeEmulator(Trace trace, long snap, SleighUseropLibrary<byte[]> library) {
|
||||
super(assertSleigh(trace.getBaseLanguage()), library);
|
||||
public TracePcodeEmulator(Trace trace, long snap) {
|
||||
super(assertSleigh(trace.getBaseLanguage()));
|
||||
this.trace = trace;
|
||||
this.snap = snap;
|
||||
}
|
||||
|
||||
public TracePcodeEmulator(Trace trace, long snap) {
|
||||
this(trace, snap, SleighUseropLibrary.nil());
|
||||
}
|
||||
|
||||
protected PcodeExecutorState<byte[]> newState(TraceThread thread) {
|
||||
return new TraceCachedWriteBytesPcodeExecutorState(trace, snap, thread, 0);
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@ public enum TraceSleighUtils {
|
|||
paired);
|
||||
}
|
||||
|
||||
public static byte[] evaluateBytes(SleighExpression expr, Trace trace, long snap,
|
||||
public static byte[] evaluateBytes(PcodeExpression expr, Trace trace, long snap,
|
||||
TraceThread thread, int frame) {
|
||||
SleighLanguage language = expr.getLanguage();
|
||||
if (trace.getBaseLanguage() != language) {
|
||||
|
@ -84,14 +84,14 @@ public enum TraceSleighUtils {
|
|||
return expr.evaluate(executor);
|
||||
}
|
||||
|
||||
public static BigInteger evaluate(SleighExpression expr, Trace trace, long snap,
|
||||
public static BigInteger evaluate(PcodeExpression expr, Trace trace, long snap,
|
||||
TraceThread thread, int frame) {
|
||||
byte[] bytes = evaluateBytes(expr, trace, snap, thread, frame);
|
||||
return Utils.bytesToBigInteger(bytes, bytes.length, expr.getLanguage().isBigEndian(),
|
||||
false);
|
||||
}
|
||||
|
||||
public static Pair<byte[], TraceMemoryState> evaluateBytesWithState(SleighExpression expr,
|
||||
public static Pair<byte[], TraceMemoryState> evaluateBytesWithState(PcodeExpression expr,
|
||||
Trace trace, long snap, TraceThread thread, int frame) {
|
||||
SleighLanguage language = expr.getLanguage();
|
||||
if (trace.getBaseLanguage() != language) {
|
||||
|
@ -104,7 +104,7 @@ public enum TraceSleighUtils {
|
|||
return expr.evaluate(executor);
|
||||
}
|
||||
|
||||
public static Pair<BigInteger, TraceMemoryState> evaluateWithState(SleighExpression expr,
|
||||
public static Pair<BigInteger, TraceMemoryState> evaluateWithState(PcodeExpression expr,
|
||||
Trace trace, long snap, TraceThread thread, int frame) {
|
||||
Pair<byte[], TraceMemoryState> bytesPair =
|
||||
evaluateBytesWithState(expr, trace, snap, thread, frame);
|
||||
|
|
|
@ -28,8 +28,7 @@ import ghidra.program.model.address.Address;
|
|||
import ghidra.program.model.address.AddressRangeImpl;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.program.model.listing.CodeUnit;
|
||||
import ghidra.program.model.mem.Memory;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.trace.database.DBTrace;
|
||||
import ghidra.trace.database.symbol.DBTraceReference;
|
||||
|
@ -40,7 +39,6 @@ import ghidra.trace.model.program.TraceProgramView;
|
|||
import ghidra.trace.model.symbol.TraceReference;
|
||||
import ghidra.trace.model.symbol.TraceSymbol;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.trace.util.MemBufferAdapter;
|
||||
import ghidra.util.LockHold;
|
||||
import ghidra.util.Saveable;
|
||||
import ghidra.util.exception.NoValueException;
|
||||
|
|
|
@ -20,8 +20,8 @@ import java.nio.ByteOrder;
|
|||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressOverflowException;
|
||||
import ghidra.program.model.mem.MemBufferAdapter;
|
||||
import ghidra.program.model.mem.Memory;
|
||||
import ghidra.trace.util.MemBufferAdapter;
|
||||
|
||||
public class DBTraceMemBuffer implements MemBufferAdapter {
|
||||
private final DBTraceMemorySpace space;
|
||||
|
|
|
@ -370,7 +370,7 @@ public class PatchStep implements Step {
|
|||
|
||||
protected Map<AddressSpace, SemisparseByteArray> getPatches(Language language) {
|
||||
PcodeProgram prog = SleighProgramCompiler.compileProgram((SleighLanguage) language,
|
||||
"schedule", List.of(sleigh + ";"), SleighUseropLibrary.nil());
|
||||
"schedule", List.of(sleigh + ";"), PcodeUseropLibrary.nil());
|
||||
// SemisparseArray is a bit overkill, no?
|
||||
Map<AddressSpace, SemisparseByteArray> result = new TreeMap<>();
|
||||
for (PcodeOp op : prog.getCode()) {
|
||||
|
|
|
@ -1,83 +0,0 @@
|
|||
/* ###
|
||||
* 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.util;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
|
||||
public interface MemBufferAdapter extends MemBuffer {
|
||||
int getBytes(ByteBuffer buffer, int addressOffset);
|
||||
|
||||
@Override
|
||||
default byte getByte(int offset) throws MemoryAccessException {
|
||||
ByteBuffer buffer = ByteBuffer.allocate(1);
|
||||
if (getBytes(buffer, offset) < 1) {
|
||||
throw new MemoryAccessException(
|
||||
"Couldn't get requested byte for " + getClass().getSimpleName());
|
||||
}
|
||||
return buffer.get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int getBytes(byte[] b, int offset) {
|
||||
return getBytes(ByteBuffer.wrap(b), offset);
|
||||
}
|
||||
|
||||
default ByteBuffer getBytesInFull(int offset, int len) throws MemoryAccessException {
|
||||
ByteBuffer buf = ByteBuffer.allocate(len);
|
||||
if (getBytes(buf, offset) != len) {
|
||||
throw new MemoryAccessException("Could not read enough bytes");
|
||||
}
|
||||
if (!isBigEndian()) {
|
||||
buf.order(ByteOrder.LITTLE_ENDIAN);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
@Override
|
||||
default short getShort(int offset) throws MemoryAccessException {
|
||||
return getBytesInFull(offset, Short.BYTES).getShort(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int getInt(int offset) throws MemoryAccessException {
|
||||
return getBytesInFull(offset, Integer.BYTES).getInt(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
default long getLong(int offset) throws MemoryAccessException {
|
||||
return getBytesInFull(offset, Long.BYTES).getLong(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
default BigInteger getBigInteger(int offset, int size, boolean signed)
|
||||
throws MemoryAccessException {
|
||||
byte[] buf = getBytesInFull(offset, size).array();
|
||||
if (!isBigEndian()) {
|
||||
ArrayUtils.reverse(buf);
|
||||
}
|
||||
if (signed) {
|
||||
return new BigInteger(buf);
|
||||
}
|
||||
return new BigInteger(1, buf);
|
||||
}
|
||||
}
|
|
@ -94,8 +94,8 @@ public class TracePcodeEmulatorTest extends AbstractGhidraHeadlessIntegrationTes
|
|||
TraceSleighUtils.buildByteExecutor(tb.trace, 0, thread, 0);
|
||||
PcodeProgram initProg = SleighProgramCompiler.compileProgram(
|
||||
(SleighLanguage) tb.language, "test", stateInit,
|
||||
SleighUseropLibrary.nil());
|
||||
exec.execute(initProg, SleighUseropLibrary.nil());
|
||||
PcodeUseropLibrary.nil());
|
||||
exec.execute(initProg, PcodeUseropLibrary.nil());
|
||||
}
|
||||
return thread;
|
||||
}
|
||||
|
@ -476,13 +476,13 @@ public class TracePcodeEmulatorTest extends AbstractGhidraHeadlessIntegrationTes
|
|||
public void testInject() throws Throwable {
|
||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||
final StringBuilder dumped = new StringBuilder();
|
||||
SleighUseropLibrary<byte[]> library = new AnnotatedSleighUseropLibrary<byte[]>() {
|
||||
PcodeUseropLibrary<byte[]> hexLib = new AnnotatedPcodeUseropLibrary<byte[]>() {
|
||||
@Override
|
||||
protected Lookup getMethodLookup() {
|
||||
return MethodHandles.lookup();
|
||||
}
|
||||
|
||||
@SleighUserop
|
||||
@PcodeUserop
|
||||
public void hexdump(byte[] in) {
|
||||
dumped.append(NumericUtilities.convertBytesToString(in));
|
||||
}
|
||||
|
@ -495,7 +495,12 @@ public class TracePcodeEmulatorTest extends AbstractGhidraHeadlessIntegrationTes
|
|||
"PUSH 0xdeadbeef",
|
||||
"PUSH 0xbaadf00d"));
|
||||
|
||||
TracePcodeEmulator emu = new TracePcodeEmulator(tb.trace, 0, library);
|
||||
TracePcodeEmulator emu = new TracePcodeEmulator(tb.trace, 0) {
|
||||
@Override
|
||||
protected PcodeUseropLibrary<byte[]> createUseropLibrary() {
|
||||
return hexLib;
|
||||
}
|
||||
};
|
||||
emu.inject(tb.addr(0x00400006), List.of("hexdump(RSP);"));
|
||||
PcodeThread<byte[]> emuThread = emu.newThread(thread.getPath());
|
||||
emuThread.overrideContextWithDefault();
|
||||
|
@ -519,13 +524,13 @@ public class TracePcodeEmulatorTest extends AbstractGhidraHeadlessIntegrationTes
|
|||
public void testInjectedInterrupt() throws Throwable {
|
||||
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
|
||||
final StringBuilder dumped = new StringBuilder();
|
||||
SleighUseropLibrary<byte[]> library = new AnnotatedSleighUseropLibrary<byte[]>() {
|
||||
PcodeUseropLibrary<byte[]> hexLib = new AnnotatedPcodeUseropLibrary<byte[]>() {
|
||||
@Override
|
||||
protected Lookup getMethodLookup() {
|
||||
return MethodHandles.lookup();
|
||||
}
|
||||
|
||||
@SleighUserop
|
||||
@PcodeUserop
|
||||
public void hexdump(byte[] in) {
|
||||
dumped.append(NumericUtilities.convertBytesToString(in));
|
||||
}
|
||||
|
@ -538,7 +543,12 @@ public class TracePcodeEmulatorTest extends AbstractGhidraHeadlessIntegrationTes
|
|||
"PUSH 0xdeadbeef",
|
||||
"PUSH 0xbaadf00d"));
|
||||
|
||||
TracePcodeEmulator emu = new TracePcodeEmulator(tb.trace, 0, library);
|
||||
TracePcodeEmulator emu = new TracePcodeEmulator(tb.trace, 0) {
|
||||
@Override
|
||||
protected PcodeUseropLibrary<byte[]> createUseropLibrary() {
|
||||
return hexLib;
|
||||
}
|
||||
};
|
||||
emu.inject(tb.addr(0x00400006), List.of(
|
||||
"hexdump(RSP);",
|
||||
"emu_swi();",
|
||||
|
|
|
@ -214,7 +214,7 @@ public class TraceSleighUtilsTest extends AbstractGhidraHeadlessIntegrationTest
|
|||
"<else>",
|
||||
" r1 = 7;",
|
||||
"<done>"),
|
||||
SleighUseropLibrary.NIL);
|
||||
PcodeUseropLibrary.NIL);
|
||||
TraceThread thread;
|
||||
try (UndoableTransaction tid = b.startTransaction()) {
|
||||
thread = b.getOrAddThread("Thread1", 0);
|
||||
|
@ -222,7 +222,7 @@ public class TraceSleighUtilsTest extends AbstractGhidraHeadlessIntegrationTest
|
|||
new PcodeExecutor<>(sp.getLanguage(),
|
||||
BytesPcodeArithmetic.forLanguage(b.language),
|
||||
new TraceBytesPcodeExecutorState(b.trace, 0, thread, 0));
|
||||
sp.execute(executor, SleighUseropLibrary.nil());
|
||||
sp.execute(executor, PcodeUseropLibrary.nil());
|
||||
}
|
||||
|
||||
Register r1 = b.language.getRegister("r1");
|
||||
|
|
|
@ -85,9 +85,9 @@ public class ToyDBTraceBuilder implements AutoCloseable {
|
|||
|
||||
public void exec(long snap, int frame, TraceThread thread, List<String> sleigh) {
|
||||
PcodeProgram program = SleighProgramCompiler.compileProgram((SleighLanguage) language,
|
||||
"builder", sleigh, SleighUseropLibrary.nil());
|
||||
"builder", sleigh, PcodeUseropLibrary.nil());
|
||||
TraceSleighUtils.buildByteExecutor(trace, snap, thread, frame)
|
||||
.execute(program, SleighUseropLibrary.nil());
|
||||
.execute(program, PcodeUseropLibrary.nil());
|
||||
}
|
||||
|
||||
public Address addr(AddressSpace space, long offset) {
|
||||
|
|
|
@ -367,7 +367,7 @@ public class TraceScheduleTest extends AbstractGhidraHeadlessIntegrationTest {
|
|||
@Override
|
||||
public PcodeExecutor<Void> getExecutor() {
|
||||
return new PcodeExecutor<>(TOY_BE_64_LANG, machine.getArithmetic(), getState()) {
|
||||
public PcodeFrame execute(PcodeProgram program, SleighUseropLibrary<Void> library) {
|
||||
public PcodeFrame execute(PcodeProgram program, PcodeUseropLibrary<Void> library) {
|
||||
machine.record.add("x:" + name);
|
||||
// TODO: Verify the actual effect
|
||||
return null; //super.execute(program, library);
|
||||
|
@ -376,7 +376,7 @@ public class TraceScheduleTest extends AbstractGhidraHeadlessIntegrationTest {
|
|||
}
|
||||
|
||||
@Override
|
||||
public SleighUseropLibrary<Void> getUseropLibrary() {
|
||||
public PcodeUseropLibrary<Void> getUseropLibrary() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -402,7 +402,7 @@ public class TraceScheduleTest extends AbstractGhidraHeadlessIntegrationTest {
|
|||
protected final List<String> record = new ArrayList<>();
|
||||
|
||||
public TestMachine() {
|
||||
super(TOY_BE_64_LANG, null, null);
|
||||
super(TOY_BE_64_LANG, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -419,6 +419,11 @@ public class TraceScheduleTest extends AbstractGhidraHeadlessIntegrationTest {
|
|||
protected PcodeExecutorState<Void> createLocalState(PcodeThread<Void> thread) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PcodeUseropLibrary<Void> createUseropLibrary() {
|
||||
return PcodeUseropLibrary.nil();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue