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; } /**