diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java b/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java
index 0bdef3a230..b3b733a845 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java
@@ -90,11 +90,15 @@ public class SymbolicPropogator {
// Cache instructions looked up by containing
Map
instructionContainingCache = new LRUMap<>(LRU_SIZE);
+
+ // cache for pcode callother injection payloads
+ HashMap injectPayloadCache = new HashMap();
public SymbolicPropogator(Program program) {
this.program = program;
Language language = program.getLanguage();
+
programContext = new ProgramContextImpl(language);
spaceContext = new ProgramContextImpl(language);
@@ -792,16 +796,17 @@ public class SymbolicPropogator {
mustClearAll = pcodeIndex < mustClearAllUntil_PcodeIndex;
- ptype = ops[pcodeIndex].getOpcode();
- Varnode out = ops[pcodeIndex].getOutput();
- Varnode[] in = ops[pcodeIndex].getInputs();
+ PcodeOp pcodeOp = ops[pcodeIndex];
+ ptype = pcodeOp.getOpcode();
+ Varnode out = pcodeOp.getOutput();
+ Varnode[] in = pcodeOp.getInputs();
Varnode val1, val2, val3, result;
long lval1, lval2;
long lresult;
Varnode vt;
if (debug) {
- Msg.info(this, " " + ops[pcodeIndex]);
+ Msg.info(this, " " + pcodeOp);
}
try {
@@ -974,12 +979,12 @@ public class SymbolicPropogator {
// for callother, could be an interrupt, need to look at it like a call
case PcodeOp.CALLOTHER:
- // HACK ALERT!
- // if this is a segment op, emulate the segmenting for now.
- String opName = this.program.getLanguage()
- .getUserDefinedOpName((int) in[0].getOffset());
- if (opName.equals("segment") && in.length > 2) {
- checkSegmented(out, in[1], in[2], mustClearAll);
+ PcodeOp[] callOtherPcode = doCallOtherPcodeInjection(instruction, in, out);
+
+ if (callOtherPcode != null) {
+ ops = injectPcode(ops, pcodeIndex, callOtherPcode);
+ pcodeIndex = -1;
+ injected = true;
}
else if (out != null) {
// clear out settings for the output from call other.
@@ -1636,27 +1641,73 @@ public class SymbolicPropogator {
return currentPcode;
}
- private void checkSegmented(Varnode out, Varnode in1, Varnode in2, boolean mustClearAll)
- throws NotFoundException {
- Varnode vval1 = context.getValue(in1, evaluator);
- Varnode vval2 = context.getValue(in2, evaluator);
- if (vval1.isConstant() && vval2.isConstant()) {
- int bitsize = program.getAddressFactory().getDefaultAddressSpace().getSize();
- long segBase;
- if (bitsize > 24) {
- segBase = context.getConstant(vval1, evaluator) << 16;
- }
- else if (bitsize == 24) {
- segBase = context.getConstant(vval1, evaluator) << 8;
- }
- else {
- segBase = context.getConstant(vval1, evaluator) << 4;
- }
- vval1 = context.createConstantVarnode(segBase, out.getSize());
- vval2 = context.createConstantVarnode(vval2.getOffset(), out.getSize());
- Varnode segmentedValue = context.add(vval1, vval2, evaluator);
- context.putValue(out, segmentedValue, mustClearAll);
+ /**
+ * Check for pcode replacement for a callother pcode op
+ *
+ * @param instr instruction whose pcodeop we might replace
+ * @param ins input varnodes to callother pcodeop, ins[0] is callother nameindex
+ * @param out output varnode for pcodeop
+ * @return pcode that should replace callother, null otherwise
+ *
+ * @throws NotFoundException
+ */
+ private PcodeOp[] doCallOtherPcodeInjection(Instruction instr, Varnode ins[], Varnode out) throws NotFoundException {
+ Program prog = instr.getProgram();
+
+ PcodeInjectLibrary snippetLibrary = prog.getCompilerSpec().getPcodeInjectLibrary();
+ InjectPayload payload = findPcodeInjection(prog, snippetLibrary, ins[0].getOffset());
+ // no injection defined for this call-other pcodeop
+ if (payload == null) {
+ return null;
}
+
+ ArrayList inputs = new ArrayList();
+ for (int i = 1; i < ins.length; i++) {
+ Varnode vval = context.getValue(ins[i], evaluator);
+ if (!vval.isConstant()) {
+ return null;
+ }
+ inputs.add(vval);
+ }
+
+ InjectContext con = snippetLibrary.buildInjectContext();
+ con.baseAddr = instr.getMinAddress();
+ con.nextAddr = con.baseAddr.add(instr.getDefaultFallThroughOffset());
+ con.callAddr = null;
+ con.refAddr = con.callAddr;
+ con.inputlist = inputs;
+ con.output = new ArrayList();
+ con.output.add(out);
+ return payload.getPcode(prog, con);
+ }
+
+ private InjectPayload findPcodeInjection(Program prog, PcodeInjectLibrary snippetLibrary, long callOtherIndex) {
+ InjectPayload payload = (InjectPayload) injectPayloadCache.get(callOtherIndex);
+
+ // has a payload value for the pcode callother index
+ if (payload != null) {
+ return payload;
+ }
+
+ // value null, if contains the key, then already looked up
+ if (injectPayloadCache.containsKey(callOtherIndex)) {
+ return null;
+ }
+
+ String opName = prog.getLanguage().getUserDefinedOpName((int) callOtherIndex);
+
+ // segment is special named injection
+ if ("segment".equals(opName)) {
+ payload =
+ snippetLibrary.getPayload(InjectPayload.EXECUTABLEPCODE_TYPE, "segment_pcode");
+ }
+ else {
+ payload = snippetLibrary.getPayload(InjectPayload.CALLOTHERFIXUP_TYPE, opName);
+ }
+
+ // save payload in cache for next lookup
+ injectPayloadCache.put(callOtherIndex, payload);
+ return payload;
}
/**