mirror of
https://github.com/morluto/rea.git
synced 2026-10-31 20:06:14 +00:00
* ci(ghidra): probe M-profile ARM and Xtensa decoding The embedded plan relies on ARM:LE:32:Cortex, ARM:LE:32:v8-m and Xtensa:LE:32:default, but CI only exercised ARM:LE:32:v7. Import source-owned bytes for each language at 0x1000 with -noanalysis and check how they decode from the language's default context: Cortex and v8-m must start in Thumb state, v8-m must decode the ARMv8-M MSPLIM register, and Xtensa must decode entry and retw.n. Add the probe scripts the job runs, including the existing ARM context probe, to the ghidra_bridge change scope. * ci(ghidra): match decode-probe operands as complete operands The operand expectation searched the instruction text for a substring, so mrs/4/msp also accepted mrs r0,msplim. Compare it with each operand Ghidra reports for the instruction, so only a complete operand matches. The Cortex (msp, lr), v8-M (msplim, lr) and Xtensa (a1) expectations are unchanged.
51 lines
2.5 KiB
Java
51 lines
2.5 KiB
Java
//@category REA Verification
|
|
|
|
import ghidra.app.script.GhidraScript;
|
|
import ghidra.program.model.address.Address;
|
|
import ghidra.program.model.listing.Instruction;
|
|
import java.util.HashSet;
|
|
import java.util.Locale;
|
|
import java.util.Set;
|
|
|
|
/**
|
|
* Decodes source-owned bytes in the imported language's default context; no
|
|
* context register is set. Arguments are the expected language ID, then one
|
|
* mnemonic/length[/operand] expectation per instruction from the first byte.
|
|
* An operand expectation must equal one complete operand, so "msp" does not
|
|
* accept "msplim".
|
|
*/
|
|
public class ReaDecodeProbe extends GhidraScript {
|
|
@Override
|
|
public void run() throws Exception {
|
|
String[] args = getScriptArgs();
|
|
require(args.length >= 2, "Expected a language ID and instruction expectations");
|
|
String language = currentProgram.getLanguageID().getIdAsString();
|
|
require(language.equals(args[0]), "Imported language " + language);
|
|
Address address = currentProgram.getMemory().getMinAddress();
|
|
for (int index = 1; index < args.length; index++) {
|
|
String[] expected = args[index].split("/", 3);
|
|
require(expected.length >= 2, "Malformed expectation " + args[index]);
|
|
if (getInstructionAt(address) == null) disassemble(address);
|
|
Instruction instruction = getInstructionAt(address);
|
|
require(instruction != null, "No instruction decoded at " + address);
|
|
String text = instruction.toString().toLowerCase(Locale.ROOT);
|
|
String decoded = instruction.getMnemonicString().toLowerCase(Locale.ROOT)
|
|
+ "/" + instruction.getLength();
|
|
Set<String> operands = new HashSet<>();
|
|
for (int operand = 0; operand < instruction.getNumOperands(); operand++)
|
|
operands.add(instruction.getDefaultOperandRepresentation(operand)
|
|
.toLowerCase(Locale.ROOT));
|
|
println("REA_DECODE " + address + " " + text + " operands=" + operands);
|
|
require(decoded.equals(expected[0] + "/" + expected[1])
|
|
&& (expected.length == 2 || operands.contains(expected[2])),
|
|
"Expected " + args[index] + " at " + address + ", decoded " + text);
|
|
address = address.add(instruction.getLength());
|
|
}
|
|
println("REA_DECODE_OK " + String.join(" ", args));
|
|
}
|
|
|
|
private static void require(boolean condition, String label) {
|
|
if (!condition) throw new IllegalStateException(label);
|
|
}
|
|
}
|