Merge remote-tracking branch 'origin/GP-1245_Dan_wow64Emu--REBASED-1--SQUASHED'

This commit is contained in:
Ryan Kurtz
2021-10-08 11:14:47 -04:00
4 changed files with 109 additions and 5 deletions
@@ -141,7 +141,7 @@ public class DBTraceCodeManager
}
catch (Exception e) {
Msg.error(this, "Bad Instruction Prototype found in DB! Address: " + address +
"b Bytes: " + NumericUtilities.convertBytesToString(bytes));
"Bytes: " + NumericUtilities.convertBytesToString(bytes));
return new InvalidPrototype(language);
}
}
@@ -237,6 +237,11 @@ public class DBTraceCodeManager
}
}
protected byte[] valueBytes(RegisterValue rv) {
byte[] bytes = rv.toBytes();
return Arrays.copyOfRange(bytes, bytes.length / 2, bytes.length);
}
protected int doRecordPrototype(InstructionPrototype prototype, MemBuffer memBuffer,
ProcessorContextView context) {
DBTraceCodePrototypeEntry protoEnt = protoStore.create();
@@ -250,8 +255,8 @@ public class DBTraceCodeManager
ctx = null;
}
else {
BigInteger value = context.getValue(baseCtxReg, true);
ctx = value == null ? null : value.toByteArray();
RegisterValue value = context.getRegisterValue(baseCtxReg);
ctx = value == null ? null : valueBytes(value);
}
protoEnt.set(languageManager.getKeyForLanguage(prototype.getLanguage()), bytes, ctx,
memBuffer.getAddress(), prototype.isInDelaySlot());
@@ -27,6 +27,8 @@ import ghidra.program.model.lang.InstructionError.InstructionErrorType;
import ghidra.program.model.listing.*;
import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.trace.database.DBTraceUtils;
import ghidra.trace.database.context.DBTraceRegisterContextManager;
import ghidra.trace.database.context.DBTraceRegisterContextSpace;
import ghidra.trace.database.memory.DBTraceMemorySpace;
import ghidra.trace.model.ImmutableTraceAddressSnapRange;
import ghidra.trace.model.Trace.TraceCodeChangeType;
@@ -64,9 +66,34 @@ public class DBTraceInstructionsView extends AbstractBaseDBTraceDefinedUnitsView
this.conflictCodeUnit = conflictCodeUnit;
}
protected void doSetContexts(Range<Long> lifespan, Address min, Address max,
ProcessorContextView context) {
Language language = space.baseLanguage;
Register contextReg = language.getContextBaseRegister();
if (contextReg == null) {
return;
}
RegisterValue newValue = context.getRegisterValue(contextReg);
DBTraceRegisterContextManager ctxMgr = space.trace.getRegisterContextManager();
if (Objects.equals(ctxMgr.getDefaultValue(language, contextReg, min), newValue)) {
DBTraceRegisterContextSpace ctxSpace = ctxMgr.get(space, false);
if (ctxSpace == null) {
return;
}
ctxSpace.setValue(language, null, lifespan, new AddressRangeImpl(min, max));
return;
}
DBTraceRegisterContextSpace ctxSpace = ctxMgr.get(space, true);
// TODO: Do not save non-flowing context beyond???
ctxSpace.setValue(language, newValue, lifespan, new AddressRangeImpl(min, max));
}
protected Instruction doCreateInstruction(Range<Long> lifespan, Address address,
InstructionPrototype prototype, Instruction protoInstr) {
try {
doSetContexts(lifespan, address, address.addNoWrap(prototype.getLength() - 1),
protoInstr);
Instruction created = doCreate(lifespan, address, prototype, protoInstr);
// copy override settings to replacement instruction
if (protoInstr.isFallThroughOverridden()) {
@@ -20,6 +20,7 @@ import static org.junit.Assert.*;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.util.*;
import org.junit.Test;
@@ -32,8 +33,7 @@ import ghidra.app.plugin.assembler.sleigh.sem.AssemblyPatternBlock;
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
import ghidra.pcode.emu.PcodeThread;
import ghidra.pcode.exec.*;
import ghidra.program.model.lang.Register;
import ghidra.program.model.lang.RegisterValue;
import ghidra.program.model.lang.*;
import ghidra.program.model.listing.Instruction;
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
import ghidra.trace.database.ToyDBTraceBuilder;
@@ -775,6 +775,7 @@ public class TracePcodeEmulatorTest extends AbstractGhidraHeadlessIntegrationTes
PcodeThread<byte[]> emuThread = emu.newThread(thread.getPath());
emuThread.overrideContextWithDefault();
emuThread.stepInstruction();
// No assertions. It should simply not throw an exception.
}
}
@@ -799,6 +800,7 @@ public class TracePcodeEmulatorTest extends AbstractGhidraHeadlessIntegrationTes
PcodeThread<byte[]> emuThread = emu.newThread(thread.getPath());
emuThread.overrideContextWithDefault();
emuThread.stepInstruction();
// No assertions. It should throw an exception.
}
}
@@ -823,6 +825,7 @@ public class TracePcodeEmulatorTest extends AbstractGhidraHeadlessIntegrationTes
PcodeThread<byte[]> emuThread = emu.newThread(thread.getPath());
emuThread.overrideContextWithDefault();
emuThread.stepInstruction();
// No assertions. It should simply not throw an exception.
}
}
@@ -847,6 +850,54 @@ public class TracePcodeEmulatorTest extends AbstractGhidraHeadlessIntegrationTes
emuThread.overrideContextWithDefault();
emuThread.stepInstruction();
emuThread.stepInstruction();
// No assertions. It should simply not throw an exception.
}
}
@Test
public void testDEC_MOV_compat32() throws Throwable {
try (ToyDBTraceBuilder tb = new ToyDBTraceBuilder("Test", "x86:LE:64:default")) {
Language lang = tb.trace.getBaseLanguage();
Register ctxReg = lang.getContextBaseRegister();
Register opsizeReg = lang.getRegister("opsize");
Register addrsizeReg = lang.getRegister("addrsize");
Register longModeReg = lang.getRegister("longMode");
RegisterValue ctxVal = new RegisterValue(ctxReg)
.assign(opsizeReg, BigInteger.ONE)
.assign(addrsizeReg, BigInteger.ONE)
.assign(longModeReg, BigInteger.ZERO);
try (UndoableTransaction tid = tb.startTransaction()) {
tb.trace.getRegisterContextManager()
.setValue(lang, ctxVal, Range.atLeast(0L),
tb.range(0x00400000, 0x00400002));
}
TraceThread thread = initTrace(tb,
List.of(
"RIP = 0x00400000;",
"RSP = 0x00110000;",
"RAX = 0xff12345678;"),
List.of(
"DEC EAX",
"MOV ECX,EAX"));
// Assembly sanity check
ByteBuffer buf = ByteBuffer.allocate(3);
tb.trace.getMemoryManager().getBytes(0, tb.addr(0x00400000), buf);
assertArrayEquals(tb.arr(0x48, 0x89, 0xc1), buf.array());
TracePcodeEmulator emu = new TracePcodeEmulator(tb.trace, 0);
PcodeThread<byte[]> emuThread = emu.newThread(thread.getPath());
emuThread.overrideContext(ctxVal);
emuThread.stepInstruction();
emuThread.stepInstruction();
try (UndoableTransaction tid = tb.startTransaction()) {
emu.writeDown(tb.trace, 1, 1, false);
}
assertEquals(BigInteger.valueOf(0x00400003),
TraceSleighUtils.evaluate("RIP", tb.trace, 1, thread, 0));
assertEquals(BigInteger.valueOf(0x12345677),
TraceSleighUtils.evaluate("RCX", tb.trace, 1, thread, 0));
}
}
}
@@ -215,6 +215,7 @@ public class DBTraceDisassemblerIntegrationTest extends AbstractGhidraHeadlessIn
}
}
@Test
@TestLanguage(ProgramBuilder._X64)
public void test64BitX86DBTrace() throws Exception {
try (UndoableTransaction tid = b.startTransaction()) {
@@ -233,6 +234,15 @@ public class DBTraceDisassemblerIntegrationTest extends AbstractGhidraHeadlessIn
CodeUnit cu1 = cuManager.getAt(0, b.addr(0x00400000));
assertEquals("MOV RCX,RAX", cu1.toString());
}
File saved = b.save();
// Check that required context is actually saved and restored
try (ToyDBTraceBuilder b = new ToyDBTraceBuilder(saved)) {
DBTraceCodeUnitsMemoryView cuManager = b.trace.getCodeManager().codeUnits();
CodeUnit cu1 = cuManager.getAt(0, b.addr(0x00400000));
assertEquals("MOV RCX,RAX", cu1.toString());
}
}
@Test
@@ -258,6 +268,17 @@ public class DBTraceDisassemblerIntegrationTest extends AbstractGhidraHeadlessIn
CodeUnit cu2 = cuManager.getAt(0, b.addr(0x00400001));
assertEquals("MOV ECX,EAX", cu2.toString());
}
File saved = b.save();
// Check that required context is actually saved and restored
try (ToyDBTraceBuilder b = new ToyDBTraceBuilder(saved)) {
DBTraceCodeUnitsMemoryView cuManager = b.trace.getCodeManager().codeUnits();
CodeUnit cu1 = cuManager.getAt(0, b.addr(0x00400000));
assertEquals("DEC EAX", cu1.toString());
CodeUnit cu2 = cuManager.getAt(0, b.addr(0x00400001));
assertEquals("MOV ECX,EAX", cu2.toString());
}
}
@Test