mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-26 18:17:35 +08:00
GP-1904: Emulator: Decode instructions by block for crossbuild context
This commit is contained in:
@@ -165,7 +165,7 @@ public class DefaultPcodeThread<T> implements PcodeThread<T> {
|
||||
|
||||
@Override
|
||||
protected void branchToAddress(Address target) {
|
||||
thread.overrideCounter(target);
|
||||
thread.branchToAddress(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -293,6 +293,11 @@ public class DefaultPcodeThread<T> implements PcodeThread<T> {
|
||||
return counter;
|
||||
}
|
||||
|
||||
protected void branchToAddress(Address target) {
|
||||
overrideCounter(target);
|
||||
decoder.branched(counter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void overrideCounter(Address counter) {
|
||||
setCounter(counter);
|
||||
@@ -430,7 +435,7 @@ public class DefaultPcodeThread<T> implements PcodeThread<T> {
|
||||
overrideCounter(counter.addWrap(decoder.getLastLengthWithDelays()));
|
||||
}
|
||||
if (contextreg != Register.NO_CONTEXT) {
|
||||
overrideContext(instruction.getRegisterValue(contextreg));
|
||||
overrideContext(defaultContext.getFlowValue(instruction.getRegisterValue(contextreg)));
|
||||
}
|
||||
postExecuteInstruction();
|
||||
frame = null;
|
||||
|
||||
@@ -35,6 +35,13 @@ public interface InstructionDecoder {
|
||||
*/
|
||||
Instruction decodeInstruction(Address address, RegisterValue context);
|
||||
|
||||
/**
|
||||
* Inform the decoder that the emulator thread just branched
|
||||
*
|
||||
* @param address
|
||||
*/
|
||||
void branched(Address address);
|
||||
|
||||
/**
|
||||
* Get the last instruction decoded
|
||||
*
|
||||
|
||||
@@ -64,6 +64,10 @@ public interface PcodeThread<T> {
|
||||
/**
|
||||
* Set the thread's program counter and write the pc register of its executor state
|
||||
*
|
||||
* <p>
|
||||
* <b>Warning:</b> Setting the counter into the middle of group constructs, e.g., parallel
|
||||
* instructions or delay-slotted instructions, may cause undefined behavior.
|
||||
*
|
||||
* @see #setCounter(Address)
|
||||
* @param counter the new target address
|
||||
*/
|
||||
|
||||
+24
-5
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package ghidra.pcode.emu;
|
||||
|
||||
import ghidra.app.util.PseudoInstruction;
|
||||
import ghidra.pcode.emulate.InstructionDecodeException;
|
||||
import ghidra.pcode.exec.PcodeArithmetic.Purpose;
|
||||
import ghidra.pcode.exec.PcodeExecutorState;
|
||||
@@ -39,6 +40,7 @@ public class SleighInstructionDecoder implements InstructionDecoder {
|
||||
|
||||
private static final String DEFAULT_ERROR = "Unknown disassembly error";
|
||||
|
||||
protected final Language language;
|
||||
protected final PcodeExecutorState<?> state;
|
||||
protected final AddressFactory addrFactory;
|
||||
protected final Disassembler disassembler;
|
||||
@@ -48,7 +50,7 @@ public class SleighInstructionDecoder implements InstructionDecoder {
|
||||
protected InstructionBlock block;
|
||||
protected int lengthWithDelays;
|
||||
|
||||
private Instruction instruction;
|
||||
private PseudoInstruction instruction;
|
||||
|
||||
/**
|
||||
* Construct a SLEIGH instruction decoder
|
||||
@@ -59,6 +61,7 @@ public class SleighInstructionDecoder implements InstructionDecoder {
|
||||
* machine. It must be possible to obtain concrete buffers on this state.
|
||||
*/
|
||||
public SleighInstructionDecoder(Language language, PcodeExecutorState<?> state) {
|
||||
this.language = language;
|
||||
this.state = state;
|
||||
addrFactory = language.getAddressFactory();
|
||||
DisassemblerMessageListener listener = msg -> {
|
||||
@@ -72,17 +75,34 @@ public class SleighInstructionDecoder implements InstructionDecoder {
|
||||
@Override
|
||||
public Instruction decodeInstruction(Address address, RegisterValue context) {
|
||||
lastMsg = DEFAULT_ERROR;
|
||||
// Always re-parse block in case bytes change
|
||||
if (block != null &&
|
||||
(instruction = (PseudoInstruction) block.getInstructionAt(address)) != null) {
|
||||
return instruction;
|
||||
}
|
||||
/*
|
||||
* Parse as few instructions as possible. If more are returned, it's because they form a
|
||||
* parallel instruction group. In that case, I should not have to worry self-modifying code
|
||||
* within that group, so no need to re-disassemble after each is executed.
|
||||
*/
|
||||
block = disassembler.pseudoDisassembleBlock(
|
||||
state.getConcreteBuffer(address, Purpose.DECODE), context, 1);
|
||||
instruction = block == null ? null : block.getInstructionAt(address);
|
||||
if (instruction == null) {
|
||||
if (block == null || block.isEmpty()) {
|
||||
throw new InstructionDecodeException(lastMsg, address);
|
||||
}
|
||||
instruction = (PseudoInstruction) block.getInstructionAt(address);
|
||||
lengthWithDelays = computeLength();
|
||||
return instruction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void branched(Address address) {
|
||||
/*
|
||||
* This shouldn't happen in the middle of a parallel instruction group, but in case the
|
||||
* group modifies itself and jumps back to itself, this will ensure it is re-disassembled.
|
||||
*/
|
||||
block = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the "length" of an instruction, including any delay-slotted instructions that follow
|
||||
*
|
||||
@@ -114,7 +134,6 @@ public class SleighInstructionDecoder implements InstructionDecoder {
|
||||
@Override
|
||||
public int getLastLengthWithDelays() {
|
||||
return lengthWithDelays;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user