mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
GP-2586 Exceptions for injection error conditions
This commit is contained in:
parent
dc927fc7be
commit
e996440c77
9 changed files with 240 additions and 206 deletions
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.core.debug.stack;
|
package ghidra.app.plugin.core.debug.stack;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import ghidra.app.decompiler.DecompInterface;
|
import ghidra.app.decompiler.DecompInterface;
|
||||||
|
@ -28,8 +29,10 @@ import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.lang.*;
|
import ghidra.program.model.lang.*;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
|
import ghidra.program.model.mem.MemoryAccessException;
|
||||||
import ghidra.program.model.pcode.*;
|
import ghidra.program.model.pcode.*;
|
||||||
import ghidra.util.exception.InvalidInputException;
|
import ghidra.util.exception.InvalidInputException;
|
||||||
|
import ghidra.util.exception.NotFoundException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -68,8 +71,8 @@ class SymPcodeExecutor extends PcodeExecutor<Sym> {
|
||||||
CompilerSpec cSpec = program.getCompilerSpec();
|
CompilerSpec cSpec = program.getCompilerSpec();
|
||||||
SleighLanguage language = (SleighLanguage) cSpec.getLanguage();
|
SleighLanguage language = (SleighLanguage) cSpec.getLanguage();
|
||||||
SymPcodeArithmetic arithmetic = new SymPcodeArithmetic(cSpec);
|
SymPcodeArithmetic arithmetic = new SymPcodeArithmetic(cSpec);
|
||||||
return new SymPcodeExecutor(program, cSpec, language, arithmetic, state, reason,
|
return new SymPcodeExecutor(program, cSpec, language, arithmetic, state, reason, warnings,
|
||||||
warnings, monitor);
|
monitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Program program;
|
private final Program program;
|
||||||
|
@ -93,8 +96,7 @@ class SymPcodeExecutor extends PcodeExecutor<Sym> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void executeCallother(PcodeOp op, PcodeFrame frame,
|
public void executeCallother(PcodeOp op, PcodeFrame frame, PcodeUseropLibrary<Sym> library) {
|
||||||
PcodeUseropLibrary<Sym> library) {
|
|
||||||
// Do nothing
|
// Do nothing
|
||||||
// TODO: Is there a way to know if a userop affects the stack?
|
// TODO: Is there a way to know if a userop affects the stack?
|
||||||
}
|
}
|
||||||
|
@ -120,8 +122,7 @@ class SymPcodeExecutor extends PcodeExecutor<Sym> {
|
||||||
}
|
}
|
||||||
int extrapop = convention.getExtrapop();
|
int extrapop = convention.getExtrapop();
|
||||||
if (extrapop == PrototypeModel.UNKNOWN_EXTRAPOP) {
|
if (extrapop == PrototypeModel.UNKNOWN_EXTRAPOP) {
|
||||||
throw new PcodeExecutionException(
|
throw new PcodeExecutionException("Cannot get stack change for function " + function);
|
||||||
"Cannot get stack change for function " + function);
|
|
||||||
}
|
}
|
||||||
if (function.isStackPurgeSizeValid()) {
|
if (function.isStackPurgeSizeValid()) {
|
||||||
return extrapop + function.getStackPurgeSize();
|
return extrapop + function.getStackPurgeSize();
|
||||||
|
@ -151,9 +152,15 @@ class SymPcodeExecutor extends PcodeExecutor<Sym> {
|
||||||
}
|
}
|
||||||
String fixupName = callee.getCallFixup();
|
String fixupName = callee.getCallFixup();
|
||||||
if (fixupName != null && !"".equals(fixupName)) {
|
if (fixupName != null && !"".equals(fixupName)) {
|
||||||
PcodeProgram snippet =
|
PcodeProgram snippet;
|
||||||
PcodeProgram.fromInject(program, fixupName, InjectPayload.CALLFIXUP_TYPE);
|
try {
|
||||||
execute(snippet, library);
|
snippet = PcodeProgram.fromInject(program, fixupName, InjectPayload.CALLFIXUP_TYPE);
|
||||||
|
execute(snippet, library);
|
||||||
|
}
|
||||||
|
catch (MemoryAccessException | UnknownInstructionException | NotFoundException
|
||||||
|
| IOException e) {
|
||||||
|
throw new PcodeExecutionException("Issue executing callee fixup: ", e);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int change = computeStackChange(callee);
|
int change = computeStackChange(callee);
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.pcode.exec;
|
package ghidra.pcode.exec;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
||||||
|
@ -25,7 +26,9 @@ import ghidra.pcodeCPort.slghsymbol.UserOpSymbol;
|
||||||
import ghidra.program.model.lang.*;
|
import ghidra.program.model.lang.*;
|
||||||
import ghidra.program.model.listing.Instruction;
|
import ghidra.program.model.listing.Instruction;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.program.model.mem.MemoryAccessException;
|
||||||
import ghidra.program.model.pcode.PcodeOp;
|
import ghidra.program.model.pcode.PcodeOp;
|
||||||
|
import ghidra.util.exception.NotFoundException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A p-code program to be executed by a {@link PcodeExecutor}
|
* A p-code program to be executed by a {@link PcodeExecutor}
|
||||||
|
@ -112,8 +115,7 @@ public class PcodeProgram {
|
||||||
throw new IllegalArgumentException("Instruction must be parsed using Sleigh");
|
throw new IllegalArgumentException("Instruction must be parsed using Sleigh");
|
||||||
}
|
}
|
||||||
PcodeOp[] pcode = instruction.getPcode(includeOverrides);
|
PcodeOp[] pcode = instruction.getPcode(includeOverrides);
|
||||||
return new PcodeProgram((SleighLanguage) language, List.of(pcode),
|
return new PcodeProgram((SleighLanguage) language, List.of(pcode), Map.of());
|
||||||
Map.of());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -123,8 +125,14 @@ public class PcodeProgram {
|
||||||
* @param name the name of the snippet
|
* @param name the name of the snippet
|
||||||
* @param type the type of the snippet
|
* @param type the type of the snippet
|
||||||
* @return the p-code program
|
* @return the p-code program
|
||||||
|
* @throws MemoryAccessException for problems establishing the injection context
|
||||||
|
* @throws IOException for problems while emitting the injection p-code
|
||||||
|
* @throws UnknownInstructionException if there is no underlying instruction being injected
|
||||||
|
* @throws NotFoundException if an expected aspect of the injection is not present in context
|
||||||
*/
|
*/
|
||||||
public static PcodeProgram fromInject(Program program, String name, int type) {
|
public static PcodeProgram fromInject(Program program, String name, int type)
|
||||||
|
throws MemoryAccessException, UnknownInstructionException, NotFoundException,
|
||||||
|
IOException {
|
||||||
PcodeInjectLibrary library = program.getCompilerSpec().getPcodeInjectLibrary();
|
PcodeInjectLibrary library = program.getCompilerSpec().getPcodeInjectLibrary();
|
||||||
InjectContext ctx = library.buildInjectContext();
|
InjectContext ctx = library.buildInjectContext();
|
||||||
InjectPayload payload = library.getPayload(type, name);
|
InjectPayload payload = library.getPayload(type, name);
|
||||||
|
|
|
@ -15,9 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.program.util;
|
package ghidra.program.util;
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
import org.apache.commons.collections4.map.LRUMap;
|
import org.apache.commons.collections4.map.LRUMap;
|
||||||
|
|
||||||
|
@ -1088,7 +1087,8 @@ public class SymbolicPropogator {
|
||||||
// if return value is a location, give evaluator a chance to check the value
|
// if return value is a location, give evaluator a chance to check the value
|
||||||
try {
|
try {
|
||||||
val1 = vContext.getValue(in[0], evaluator);
|
val1 = vContext.getValue(in[0], evaluator);
|
||||||
if (evaluator != null && evaluator.evaluateReturn(val1, vContext, instruction)) {
|
if (evaluator != null &&
|
||||||
|
evaluator.evaluateReturn(val1, vContext, instruction)) {
|
||||||
canceled = true;
|
canceled = true;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -1446,9 +1446,9 @@ public class SymbolicPropogator {
|
||||||
Varnode vt;
|
Varnode vt;
|
||||||
if (!context.isExternalSpace(val1.getSpace())) {
|
if (!context.isExternalSpace(val1.getSpace())) {
|
||||||
long lval = vContext.getConstant(val1, evaluator);
|
long lval = vContext.getConstant(val1, evaluator);
|
||||||
vt = vContext.getVarnode(minInstrAddress.getAddressSpace().getSpaceID(),
|
vt = vContext.getVarnode(minInstrAddress.getAddressSpace().getSpaceID(), lval, 0);
|
||||||
lval, 0);
|
}
|
||||||
} else {
|
else {
|
||||||
vt = val1;
|
vt = val1;
|
||||||
}
|
}
|
||||||
return vt;
|
return vt;
|
||||||
|
@ -1602,7 +1602,13 @@ public class SymbolicPropogator {
|
||||||
con.nextAddr = con.baseAddr.add(instr.getDefaultFallThroughOffset());
|
con.nextAddr = con.baseAddr.add(instr.getDefaultFallThroughOffset());
|
||||||
con.callAddr = func.getEntryPoint();
|
con.callAddr = func.getEntryPoint();
|
||||||
con.refAddr = con.callAddr;
|
con.refAddr = con.callAddr;
|
||||||
return payload.getPcode(prog, con);
|
try {
|
||||||
|
return payload.getPcode(prog, con);
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
Msg.warn(this, e.getMessage());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private PcodeOp[] checkForUponReturnCallMechanismInjection(Program prog, Function func,
|
private PcodeOp[] checkForUponReturnCallMechanismInjection(Program prog, Function func,
|
||||||
|
@ -1629,7 +1635,13 @@ public class SymbolicPropogator {
|
||||||
con.nextAddr = con.baseAddr.add(instr.getDefaultFallThroughOffset());
|
con.nextAddr = con.baseAddr.add(instr.getDefaultFallThroughOffset());
|
||||||
con.callAddr = target;
|
con.callAddr = target;
|
||||||
con.refAddr = con.callAddr;
|
con.refAddr = con.callAddr;
|
||||||
return payload.getPcode(prog, con);
|
try {
|
||||||
|
return payload.getPcode(prog, con);
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
Msg.warn(this, e.getMessage());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private PcodeOp[] injectPcode(PcodeOp[] currentPcode, int pcodeIndex, PcodeOp[] replacePcode) {
|
private PcodeOp[] injectPcode(PcodeOp[] currentPcode, int pcodeIndex, PcodeOp[] replacePcode) {
|
||||||
|
@ -1662,7 +1674,8 @@ public class SymbolicPropogator {
|
||||||
*
|
*
|
||||||
* @throws NotFoundException
|
* @throws NotFoundException
|
||||||
*/
|
*/
|
||||||
private PcodeOp[] doCallOtherPcodeInjection(Instruction instr, Varnode ins[], Varnode out) throws NotFoundException {
|
private PcodeOp[] doCallOtherPcodeInjection(Instruction instr, Varnode ins[], Varnode out)
|
||||||
|
throws NotFoundException {
|
||||||
Program prog = instr.getProgram();
|
Program prog = instr.getProgram();
|
||||||
|
|
||||||
PcodeInjectLibrary snippetLibrary = prog.getCompilerSpec().getPcodeInjectLibrary();
|
PcodeInjectLibrary snippetLibrary = prog.getCompilerSpec().getPcodeInjectLibrary();
|
||||||
|
@ -1689,10 +1702,17 @@ public class SymbolicPropogator {
|
||||||
con.inputlist = inputs;
|
con.inputlist = inputs;
|
||||||
con.output = new ArrayList<Varnode>();
|
con.output = new ArrayList<Varnode>();
|
||||||
con.output.add(out);
|
con.output.add(out);
|
||||||
return payload.getPcode(prog, con);
|
try {
|
||||||
|
return payload.getPcode(prog, con);
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
Msg.warn(this, e.getMessage());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private InjectPayload findPcodeInjection(Program prog, PcodeInjectLibrary snippetLibrary, long callOtherIndex) {
|
private InjectPayload findPcodeInjection(Program prog, PcodeInjectLibrary snippetLibrary,
|
||||||
|
long callOtherIndex) {
|
||||||
InjectPayload payload = injectPayloadCache.get(callOtherIndex);
|
InjectPayload payload = injectPayloadCache.get(callOtherIndex);
|
||||||
|
|
||||||
// has a payload value for the pcode callother index
|
// has a payload value for the pcode callother index
|
||||||
|
|
|
@ -1154,6 +1154,8 @@ void FlowInfo::doInjection(InjectPayload *payload,InjectContext &icontext,PcodeO
|
||||||
|
|
||||||
bool startbasic = op->isBlockStart();
|
bool startbasic = op->isBlockStart();
|
||||||
++iter; // Now points to first op in the injection
|
++iter; // Now points to first op in the injection
|
||||||
|
if (iter == obank.endDead())
|
||||||
|
throw LowlevelError("Empty injection: " + payload->getName());
|
||||||
PcodeOp *firstop = *iter;
|
PcodeOp *firstop = *iter;
|
||||||
bool isfallthru = true;
|
bool isfallthru = true;
|
||||||
PcodeOp *lastop = xrefControlFlow(iter,startbasic,isfallthru,fc);
|
PcodeOp *lastop = xrefControlFlow(iter,startbasic,isfallthru,fc);
|
||||||
|
|
|
@ -51,13 +51,13 @@ void InjectPayloadGhidra::inject(InjectContext &con,PcodeEmit &emit) const
|
||||||
PackedDecode decoder(ghidra);
|
PackedDecode decoder(ghidra);
|
||||||
try {
|
try {
|
||||||
if (!ghidra->getPcodeInject(name,type,con,decoder))
|
if (!ghidra->getPcodeInject(name,type,con,decoder))
|
||||||
throw LowlevelError("Could not retrieve pcode snippet: "+name);
|
throw LowlevelError("Could not retrieve injection: "+name);
|
||||||
}
|
}
|
||||||
catch(JavaError &err) {
|
catch(JavaError &err) {
|
||||||
throw LowlevelError("Error getting pcode snippet: " + err.explain);
|
throw LowlevelError("Injection error: " + err.explain);
|
||||||
}
|
}
|
||||||
catch(DecoderError &err) {
|
catch(DecoderError &err) {
|
||||||
throw LowlevelError("Error in pcode snippet xml: "+err.explain);
|
throw LowlevelError("Error decoding injection: "+err.explain);
|
||||||
}
|
}
|
||||||
uint4 elemId = decoder.openElement();
|
uint4 elemId = decoder.openElement();
|
||||||
Address addr = Address::decode(decoder);
|
Address addr = Address::decode(decoder);
|
||||||
|
|
|
@ -35,6 +35,7 @@ import ghidra.program.model.pcode.*;
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.*;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.UndefinedFunction;
|
import ghidra.util.UndefinedFunction;
|
||||||
|
import ghidra.util.exception.NotFoundException;
|
||||||
import ghidra.util.exception.UsrException;
|
import ghidra.util.exception.UsrException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
|
@ -139,6 +140,8 @@ public class DecompileCallback {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get bytes from the program's memory image.
|
* Get bytes from the program's memory image.
|
||||||
|
* Any exceptions are caught, resulting in null being returned. The decompiler treats a null
|
||||||
|
* as a DataUnavailError but will continue to process the function.
|
||||||
* @param addr is the starting address to fetch bytes from
|
* @param addr is the starting address to fetch bytes from
|
||||||
* @param size is the number of bytes to fetch
|
* @param size is the number of bytes to fetch
|
||||||
* @return the bytes matching the query or null if the query can't be met
|
* @return the bytes matching the query or null if the query can't be met
|
||||||
|
@ -199,7 +202,9 @@ public class DecompileCallback {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate p-code ops for the instruction at the given address
|
* Generate p-code ops for the instruction at the given address.
|
||||||
|
* Any exceptions are caught, resulting in an empty result. The decompiler interprets these
|
||||||
|
* as a BadDataError, but will continue to process the function.
|
||||||
* @param addr is the given address
|
* @param addr is the given address
|
||||||
* @param resultEncoder will contain the generated p-code ops
|
* @param resultEncoder will contain the generated p-code ops
|
||||||
*/
|
*/
|
||||||
|
@ -234,7 +239,8 @@ public class DecompileCallback {
|
||||||
Msg.error(this,
|
Msg.error(this,
|
||||||
"Decompiling " + funcEntry + ", pcode error at " + addr + ": " + e.getMessage(), e);
|
"Decompiling " + funcEntry + ", pcode error at " + addr + ": " + e.getMessage(), e);
|
||||||
}
|
}
|
||||||
resultEncoder.clear();
|
// If we reach here, an exception was thrown
|
||||||
|
resultEncoder.clear(); // Make sure the result is empty
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -275,73 +281,62 @@ public class DecompileCallback {
|
||||||
* @param paramDecoder contains the context
|
* @param paramDecoder contains the context
|
||||||
* @param type is the type of payload
|
* @param type is the type of payload
|
||||||
* @param resultEncoder will contain the generated p-code ops
|
* @param resultEncoder will contain the generated p-code ops
|
||||||
|
* @throws DecoderException for problems decoding the injection context
|
||||||
|
* @throws UnknownInstructionException if there is no instruction at the injection site
|
||||||
|
* @throws IOException for errors encoding the injection result
|
||||||
|
* @throws NotFoundException if an expected aspect of the injection is not present in context
|
||||||
|
* @throws MemoryAccessException for problems establishing the injection context
|
||||||
*/
|
*/
|
||||||
public void getPcodeInject(String nm, Decoder paramDecoder, int type, Encoder resultEncoder) {
|
public void getPcodeInject(String nm, Decoder paramDecoder, int type, Encoder resultEncoder)
|
||||||
|
throws DecoderException, UnknownInstructionException, IOException,
|
||||||
|
MemoryAccessException, NotFoundException {
|
||||||
PcodeInjectLibrary snippetLibrary = pcodecompilerspec.getPcodeInjectLibrary();
|
PcodeInjectLibrary snippetLibrary = pcodecompilerspec.getPcodeInjectLibrary();
|
||||||
|
|
||||||
InjectPayload payload = snippetLibrary.getPayload(type, nm);
|
InjectPayload payload = snippetLibrary.getPayload(type, nm);
|
||||||
if (payload == null) {
|
if (payload == null) {
|
||||||
Msg.warn(this, "Decompiling " + funcEntry + ", no pcode inject with name: " + nm);
|
throw new NotFoundException("No p-code injection with name: " + nm);
|
||||||
return; // No fixup associated with this name
|
|
||||||
}
|
}
|
||||||
InjectContext con = snippetLibrary.buildInjectContext();
|
InjectContext con = snippetLibrary.buildInjectContext();
|
||||||
PcodeOp[] pcode;
|
PcodeOp[] pcode;
|
||||||
try {
|
con.decode(paramDecoder);
|
||||||
con.decode(paramDecoder);
|
int fallThruOffset;
|
||||||
|
if (payload.getType() == InjectPayload.EXECUTABLEPCODE_TYPE) {
|
||||||
|
// Executable p-code has no underlying instruction address and
|
||||||
|
// does (should) not use the inst_start, inst_next symbols that need
|
||||||
|
// to know about it.
|
||||||
|
fallThruOffset = 4; // Provide a dummy length
|
||||||
}
|
}
|
||||||
catch (DecoderException e) {
|
else {
|
||||||
Msg.error(this, "Decompiling " + funcEntry + ": " + e.getMessage());
|
Instruction instr = getInstruction(con.baseAddr);
|
||||||
return;
|
if (instr == null) {
|
||||||
}
|
Msg.warn(this, "Decompiling " + funcEntry + ", pcode inject error at " +
|
||||||
try {
|
con.baseAddr + ": instruction not found");
|
||||||
int fallThruOffset;
|
return;
|
||||||
if (payload.getType() == InjectPayload.EXECUTABLEPCODE_TYPE) {
|
|
||||||
// Executable p-code has no underlying instruction address and
|
|
||||||
// does (should) not use the inst_start, inst_next symbols that need
|
|
||||||
// to know about it.
|
|
||||||
fallThruOffset = 4; // Provide a dummy length
|
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
Instruction instr = getInstruction(con.baseAddr);
|
|
||||||
if (instr == null) {
|
|
||||||
Msg.warn(this, "Decompiling " + funcEntry + ", pcode inject error at " +
|
|
||||||
con.baseAddr + ": instruction not found");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get next inst addr for inst_next pcode variable
|
// get next inst addr for inst_next pcode variable
|
||||||
fallThruOffset = instr.getDefaultFallThroughOffset();
|
fallThruOffset = instr.getDefaultFallThroughOffset();
|
||||||
con.nextAddr = con.baseAddr.add(fallThruOffset);
|
con.nextAddr = con.baseAddr.add(fallThruOffset);
|
||||||
|
|
||||||
con.refAddr = null;
|
con.refAddr = null;
|
||||||
for (Reference ref : program.getReferenceManager()
|
for (Reference ref : program.getReferenceManager().getReferencesFrom(con.baseAddr)) {
|
||||||
.getReferencesFrom(con.baseAddr)) {
|
if (ref.isPrimary() && ref.getReferenceType().isCall()) {
|
||||||
if (ref.isPrimary() && ref.getReferenceType().isCall()) {
|
con.refAddr = ref.getToAddress();
|
||||||
con.refAddr = ref.getToAddress();
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pcode = payload.getPcode(program, con);
|
}
|
||||||
if (pcode == null) {
|
pcode = payload.getPcode(program, con);
|
||||||
return; // Return without result, which should let the decompiler exit gracefully
|
if (pcode == null) {
|
||||||
}
|
return; // Return without result, which should let the decompiler exit gracefully
|
||||||
encodeInstruction(resultEncoder, con.baseAddr, pcode, fallThruOffset,
|
}
|
||||||
|
encodeInstruction(resultEncoder, con.baseAddr, pcode, fallThruOffset,
|
||||||
|
payload.getParamShift(), addrfactory);
|
||||||
|
if (debug != null) {
|
||||||
|
XmlEncode xmlEncode = new XmlEncode();
|
||||||
|
encodeInstruction(xmlEncode, con.baseAddr, pcode, fallThruOffset,
|
||||||
payload.getParamShift(), addrfactory);
|
payload.getParamShift(), addrfactory);
|
||||||
if (debug != null) {
|
debug.addInject(con.baseAddr, nm, type, xmlEncode.toString());
|
||||||
XmlEncode xmlEncode = new XmlEncode();
|
|
||||||
encodeInstruction(xmlEncode, con.baseAddr, pcode, fallThruOffset,
|
|
||||||
payload.getParamShift(), addrfactory);
|
|
||||||
debug.addInject(con.baseAddr, nm, type, xmlEncode.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (UnknownInstructionException e) {
|
|
||||||
Msg.warn(this, "Decompiling " + funcEntry + ", pcode inject error at " + con.baseAddr +
|
|
||||||
": " + e.getMessage());
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
Msg.error(this, "Decompiling " + funcEntry + ", pcode inject error at " + con.baseAddr +
|
|
||||||
": " + e.getMessage(), e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -429,26 +424,19 @@ public class DecompileCallback {
|
||||||
* Return the first symbol name at the given address
|
* Return the first symbol name at the given address
|
||||||
* @param addr is the given address
|
* @param addr is the given address
|
||||||
* @return the symbol or null if no symbol is found
|
* @return the symbol or null if no symbol is found
|
||||||
|
* @throws IOException for errors trying to encode the symbol
|
||||||
*/
|
*/
|
||||||
public String getCodeLabel(Address addr) {
|
public String getCodeLabel(Address addr) throws IOException {
|
||||||
try {
|
Symbol sym = program.getSymbolTable().getPrimarySymbol(addr);
|
||||||
Symbol sym = program.getSymbolTable().getPrimarySymbol(addr);
|
if (sym == null) {
|
||||||
if (sym == null) {
|
return null;
|
||||||
return null;
|
}
|
||||||
}
|
String res = getSymbolName(sym);
|
||||||
String res = getSymbolName(sym);
|
if (debug != null) {
|
||||||
if (debug != null) {
|
debug.getCodeSymbol(addr, sym.getID(), res, sym.getParentNamespace());
|
||||||
debug.getCodeSymbol(addr, sym.getID(), res, sym.getParentNamespace());
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
Msg.error(this,
|
|
||||||
"Decompiling " + funcEntry + ", error while accessing symbol: " + e.getMessage(),
|
|
||||||
e);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getSymbolName(Symbol sym) {
|
private String getSymbolName(Symbol sym) {
|
||||||
|
@ -658,100 +646,86 @@ public class DecompileCallback {
|
||||||
*
|
*
|
||||||
* @param addr is the given address
|
* @param addr is the given address
|
||||||
* @param resultEncoder is where to write encoded description
|
* @param resultEncoder is where to write encoded description
|
||||||
|
* @throws IOException for errors encoding the result
|
||||||
*/
|
*/
|
||||||
public void getMappedSymbols(Address addr, Encoder resultEncoder) {
|
public void getMappedSymbols(Address addr, Encoder resultEncoder) throws IOException {
|
||||||
if (addr == Address.NO_ADDRESS) {
|
if (addr == Address.NO_ADDRESS) {
|
||||||
// Unknown spaces may result from "spacebase" registers defined in cspec
|
// Unknown spaces may result from "spacebase" registers defined in cspec
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
Object obj = lookupSymbol(addr);
|
||||||
Object obj = lookupSymbol(addr);
|
if (obj instanceof Function) {
|
||||||
if (obj instanceof Function) {
|
boolean includeDefaults = addr.equals(funcEntry);
|
||||||
boolean includeDefaults = addr.equals(funcEntry);
|
encodeFunction(resultEncoder, (Function) obj, addr, includeDefaults);
|
||||||
encodeFunction(resultEncoder, (Function) obj, addr, includeDefaults);
|
|
||||||
}
|
|
||||||
else if (obj instanceof Data) {
|
|
||||||
if (!encodeData(resultEncoder, (Data) obj)) {
|
|
||||||
encodeHole(resultEncoder, addr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (obj instanceof ExternalReference) {
|
|
||||||
encodeExternalRef(resultEncoder, addr, (ExternalReference) obj);
|
|
||||||
}
|
|
||||||
else if (obj instanceof Symbol) {
|
|
||||||
encodeLabel(resultEncoder, (Symbol) obj, addr);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
encodeHole(resultEncoder, addr); // There is a hole, describe the extent of the hole
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
else if (obj instanceof Data) {
|
||||||
Msg.error(this, "Decompiling " + funcEntry + ", mapped symbol error for " + addr +
|
if (!encodeData(resultEncoder, (Data) obj)) {
|
||||||
": " + e.getMessage(), e);
|
encodeHole(resultEncoder, addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (obj instanceof ExternalReference) {
|
||||||
|
encodeExternalRef(resultEncoder, addr, (ExternalReference) obj);
|
||||||
|
}
|
||||||
|
else if (obj instanceof Symbol) {
|
||||||
|
encodeLabel(resultEncoder, (Symbol) obj, addr);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
encodeHole(resultEncoder, addr); // There is a hole, describe the extent of the hole
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a description of an external reference at the given address
|
* Get a description of an external reference at the given address
|
||||||
* @param addr is the given address
|
* @param addr is the given address
|
||||||
* @param resultEncoder will contain the resulting description
|
* @param resultEncoder will contain the resulting description
|
||||||
|
* @throws IOException for errors encoding the result
|
||||||
*/
|
*/
|
||||||
public void getExternalRef(Address addr, Encoder resultEncoder) {
|
public void getExternalRef(Address addr, Encoder resultEncoder) throws IOException {
|
||||||
try {
|
Function func = null;
|
||||||
Function func = null;
|
if (cachedFunction != null && cachedFunction.getEntryPoint().equals(addr)) {
|
||||||
if (cachedFunction != null && cachedFunction.getEntryPoint().equals(addr)) {
|
func = cachedFunction;
|
||||||
func = cachedFunction;
|
}
|
||||||
|
else {
|
||||||
|
ExternalReference extRef = getExternalReference(addr);
|
||||||
|
if (extRef != null) {
|
||||||
|
func = listing.getFunctionAt(extRef.getToAddress());
|
||||||
|
if (func == null) {
|
||||||
|
Symbol symbol = extRef.getExternalLocation().getSymbol();
|
||||||
|
long extId;
|
||||||
|
if (symbol != null) {
|
||||||
|
extId = symbol.getID();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
extId = program.getSymbolTable().getDynamicSymbolID(addr);
|
||||||
|
|
||||||
|
}
|
||||||
|
HighSymbol shellSymbol =
|
||||||
|
new HighFunctionShellSymbol(extId, extRef.getLabel(), addr, dtmanage);
|
||||||
|
encodeResult(resultEncoder, shellSymbol, null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ExternalReference extRef = getExternalReference(addr);
|
func = listing.getFunctionAt(addr);
|
||||||
if (extRef != null) {
|
|
||||||
func = listing.getFunctionAt(extRef.getToAddress());
|
|
||||||
if (func == null) {
|
|
||||||
Symbol symbol = extRef.getExternalLocation().getSymbol();
|
|
||||||
long extId;
|
|
||||||
if (symbol != null) {
|
|
||||||
extId = symbol.getID();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
extId = program.getSymbolTable().getDynamicSymbolID(addr);
|
|
||||||
|
|
||||||
}
|
|
||||||
HighSymbol shellSymbol =
|
|
||||||
new HighFunctionShellSymbol(extId, extRef.getLabel(), addr, dtmanage);
|
|
||||||
encodeResult(resultEncoder, shellSymbol, null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
func = listing.getFunctionAt(addr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (func == null) {
|
}
|
||||||
// Its conceivable we could have external data, but we aren't currently checking for it
|
if (func == null) {
|
||||||
return;
|
// Its conceivable we could have external data, but we aren't currently checking for it
|
||||||
}
|
|
||||||
|
|
||||||
HighFunction hfunc = new HighFunction(func, pcodelanguage, pcodecompilerspec, dtmanage);
|
|
||||||
|
|
||||||
int extrapop = getExtraPopOverride(func, addr);
|
|
||||||
hfunc.grabFromFunction(extrapop, false, (extrapop != default_extrapop));
|
|
||||||
|
|
||||||
HighSymbol funcSymbol = new HighFunctionSymbol(addr, 2, hfunc);
|
|
||||||
Namespace namespc = funcSymbol.getNamespace();
|
|
||||||
if (debug != null) {
|
|
||||||
debug.getFNTypes(hfunc);
|
|
||||||
debug.addPossiblePrototypeExtension(func);
|
|
||||||
}
|
|
||||||
encodeResult(resultEncoder, funcSymbol, namespc);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
|
||||||
Msg.error(this,
|
HighFunction hfunc = new HighFunction(func, pcodelanguage, pcodecompilerspec, dtmanage);
|
||||||
"Decompiling " + funcEntry + ", error in getExternalRef: " + e.getMessage(), e);
|
|
||||||
|
int extrapop = getExtraPopOverride(func, addr);
|
||||||
|
hfunc.grabFromFunction(extrapop, false, (extrapop != default_extrapop));
|
||||||
|
|
||||||
|
HighSymbol funcSymbol = new HighFunctionSymbol(addr, 2, hfunc);
|
||||||
|
Namespace namespc = funcSymbol.getNamespace();
|
||||||
|
if (debug != null) {
|
||||||
|
debug.getFNTypes(hfunc);
|
||||||
|
debug.addPossiblePrototypeExtension(func);
|
||||||
}
|
}
|
||||||
|
encodeResult(resultEncoder, funcSymbol, namespc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -22,9 +22,12 @@ import java.io.*;
|
||||||
|
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.lang.InjectPayload;
|
import ghidra.program.model.lang.InjectPayload;
|
||||||
|
import ghidra.program.model.lang.UnknownInstructionException;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.program.model.mem.MemoryAccessException;
|
||||||
import ghidra.program.model.pcode.*;
|
import ghidra.program.model.pcode.*;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
|
import ghidra.util.exception.NotFoundException;
|
||||||
import ghidra.util.timer.GTimer;
|
import ghidra.util.timer.GTimer;
|
||||||
import ghidra.util.timer.GTimerMonitor;
|
import ghidra.util.timer.GTimerMonitor;
|
||||||
|
|
||||||
|
@ -705,7 +708,8 @@ public class DecompileProcess {
|
||||||
write(query_response_end);
|
write(query_response_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void getPcodeInject(int type) throws IOException, DecoderException {
|
private void getPcodeInject(int type) throws IOException, DecoderException,
|
||||||
|
UnknownInstructionException, MemoryAccessException, NotFoundException {
|
||||||
resultEncoder.clear();
|
resultEncoder.clear();
|
||||||
String name = paramDecoder.readString(ATTRIB_NAME);
|
String name = paramDecoder.readString(ATTRIB_NAME);
|
||||||
callback.getPcodeInject(name, paramDecoder, type, resultEncoder);
|
callback.getPcodeInject(name, paramDecoder, type, resultEncoder);
|
||||||
|
|
|
@ -20,8 +20,10 @@ import java.io.IOException;
|
||||||
import ghidra.app.plugin.processors.sleigh.PcodeEmit;
|
import ghidra.app.plugin.processors.sleigh.PcodeEmit;
|
||||||
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.program.model.mem.MemoryAccessException;
|
||||||
import ghidra.program.model.pcode.Encoder;
|
import ghidra.program.model.pcode.Encoder;
|
||||||
import ghidra.program.model.pcode.PcodeOp;
|
import ghidra.program.model.pcode.PcodeOp;
|
||||||
|
import ghidra.util.exception.NotFoundException;
|
||||||
import ghidra.xml.XmlParseException;
|
import ghidra.xml.XmlParseException;
|
||||||
import ghidra.xml.XmlPullParser;
|
import ghidra.xml.XmlPullParser;
|
||||||
|
|
||||||
|
@ -122,8 +124,13 @@ public interface InjectPayload {
|
||||||
* Given a context, send the p-code payload to the emitter
|
* Given a context, send the p-code payload to the emitter
|
||||||
* @param context is the context for injection
|
* @param context is the context for injection
|
||||||
* @param emit is the object accumulating the final p-code
|
* @param emit is the object accumulating the final p-code
|
||||||
|
* @throws MemoryAccessException for problems establishing the injection context
|
||||||
|
* @throws IOException for problems while emitting the injection p-code
|
||||||
|
* @throws UnknownInstructionException if there is no underlying instruction being injected
|
||||||
|
* @throws NotFoundException if an expected aspect of the injection is not present in context
|
||||||
*/
|
*/
|
||||||
public void inject(InjectContext context, PcodeEmit emit);
|
public void inject(InjectContext context, PcodeEmit emit) throws MemoryAccessException,
|
||||||
|
IOException, UnknownInstructionException, NotFoundException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A convenience function wrapping the inject method, to produce the final set
|
* A convenience function wrapping the inject method, to produce the final set
|
||||||
|
@ -131,8 +138,13 @@ public interface InjectPayload {
|
||||||
* @param program is the Program for which injection is happening
|
* @param program is the Program for which injection is happening
|
||||||
* @param con is the context for injection
|
* @param con is the context for injection
|
||||||
* @return the array of PcodeOps
|
* @return the array of PcodeOps
|
||||||
|
* @throws MemoryAccessException for problems establishing the injection context
|
||||||
|
* @throws IOException for problems while emitting the injection p-code
|
||||||
|
* @throws UnknownInstructionException if there is no underlying instruction being injected
|
||||||
|
* @throws NotFoundException if an expected aspect of the injection is not present in context
|
||||||
*/
|
*/
|
||||||
public PcodeOp[] getPcode(Program program, InjectContext con);
|
public PcodeOp[] getPcode(Program program, InjectContext con) throws MemoryAccessException,
|
||||||
|
IOException, UnknownInstructionException, NotFoundException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true if the injected p-code falls thru
|
* @return true if the injected p-code falls thru
|
||||||
|
|
|
@ -27,7 +27,9 @@ import ghidra.app.plugin.processors.sleigh.template.*;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.address.AddressFactory;
|
import ghidra.program.model.address.AddressFactory;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
|
import ghidra.program.model.mem.MemoryAccessException;
|
||||||
import ghidra.program.model.pcode.*;
|
import ghidra.program.model.pcode.*;
|
||||||
|
import ghidra.util.exception.NotFoundException;
|
||||||
import ghidra.util.xml.SpecXmlUtils;
|
import ghidra.util.xml.SpecXmlUtils;
|
||||||
import ghidra.xml.*;
|
import ghidra.xml.*;
|
||||||
|
|
||||||
|
@ -163,22 +165,19 @@ public class InjectPayloadSleigh implements InjectPayload {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void inject(InjectContext context, PcodeEmit emit) {
|
public void inject(InjectContext context, PcodeEmit emit) throws UnknownInstructionException,
|
||||||
|
MemoryAccessException, IOException, NotFoundException {
|
||||||
ParserWalker walker = emit.getWalker();
|
ParserWalker walker = emit.getWalker();
|
||||||
try {
|
walker.snippetState();
|
||||||
walker.snippetState();
|
setupParameters(context, walker);
|
||||||
setupParameters(context, walker);
|
emit.build(pcodeTemplate, -1);
|
||||||
emit.build(pcodeTemplate, -1);
|
|
||||||
}
|
|
||||||
catch (Exception e) { // Should not be happening in a CallFixup
|
|
||||||
e.printStackTrace();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
emit.resolveRelatives();
|
emit.resolveRelatives();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PcodeOp[] getPcode(Program program, InjectContext con) {
|
public PcodeOp[] getPcode(Program program, InjectContext con)
|
||||||
|
throws UnknownInstructionException, MemoryAccessException, IOException,
|
||||||
|
NotFoundException {
|
||||||
SleighParserContext protoContext =
|
SleighParserContext protoContext =
|
||||||
new SleighParserContext(con.baseAddr, con.nextAddr, con.refAddr, con.callAddr);
|
new SleighParserContext(con.baseAddr, con.nextAddr, con.refAddr, con.callAddr);
|
||||||
ParserWalker walker = new ParserWalker(protoContext);
|
ParserWalker walker = new ParserWalker(protoContext);
|
||||||
|
@ -333,29 +332,36 @@ public class InjectPayloadSleigh implements InjectPayload {
|
||||||
/**
|
/**
|
||||||
* Verify that the storage locations passed -con- match the restrictions for this payload
|
* Verify that the storage locations passed -con- match the restrictions for this payload
|
||||||
* @param con is InjectContext containing parameter storage locations
|
* @param con is InjectContext containing parameter storage locations
|
||||||
|
* @throws NotFoundException for expected aspects of the context that are not present
|
||||||
*/
|
*/
|
||||||
private void checkParameterRestrictions(InjectContext con, Address addr) {
|
private void checkParameterRestrictions(InjectContext con, Address addr)
|
||||||
|
throws NotFoundException {
|
||||||
int insize = (con.inputlist == null) ? 0 : con.inputlist.size();
|
int insize = (con.inputlist == null) ? 0 : con.inputlist.size();
|
||||||
if (inputlist.length != insize) {
|
if (inputlist.length != insize) {
|
||||||
throw new SleighException(
|
throw new NotFoundException(
|
||||||
"Input parameters do not match injection specification: " + source);
|
"Input parameters do not match specification " + name + " in\n" + source);
|
||||||
}
|
}
|
||||||
for (int i = 0; i < inputlist.length; ++i) {
|
for (int i = 0; i < inputlist.length; ++i) {
|
||||||
int sz = inputlist[i].getSize();
|
int sz = inputlist[i].getSize();
|
||||||
if (sz != 0 && sz != con.inputlist.get(i).getSize()) {
|
if (sz != 0 && sz != con.inputlist.get(i).getSize()) {
|
||||||
throw new SleighException(
|
throw new NotFoundException(
|
||||||
"Input parameter size does not match injection specification: " + source);
|
"Input parameter size does not match specification " + name + " in\n" + source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int outsize = (con.output == null) ? 0 : con.output.size();
|
int outsize = (con.output == null) ? 0 : con.output.size();
|
||||||
if (output.length != outsize) {
|
if (output.length != outsize) {
|
||||||
throw new SleighException("Output does not match injection specification: " + source);
|
if (outsize == 0) {
|
||||||
|
throw new NotFoundException(
|
||||||
|
"Output expected by specification " + name + " in\n" + source);
|
||||||
|
}
|
||||||
|
throw new NotFoundException(
|
||||||
|
"Output not expected by specification " + name + " in\n" + source);
|
||||||
}
|
}
|
||||||
for (int i = 0; i < output.length; ++i) {
|
for (int i = 0; i < output.length; ++i) {
|
||||||
int sz = output[i].getSize();
|
int sz = output[i].getSize();
|
||||||
if (sz != 0 && sz != con.output.get(i).getSize()) {
|
if (sz != 0 && sz != con.output.get(i).getSize()) {
|
||||||
throw new SleighException(
|
throw new NotFoundException(
|
||||||
"Output size does not match injection specification: " + source);
|
"Output size does not match specification " + name + " in\n" + source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -365,9 +371,10 @@ public class InjectPayloadSleigh implements InjectPayload {
|
||||||
* @param con is the InjectContext containing storage locations
|
* @param con is the InjectContext containing storage locations
|
||||||
* @param walker is the sleigh parser state object
|
* @param walker is the sleigh parser state object
|
||||||
* @throws UnknownInstructionException if there are too many parameters for the parser
|
* @throws UnknownInstructionException if there are too many parameters for the parser
|
||||||
|
* @throws NotFoundException for expected aspects of the context that are not present
|
||||||
*/
|
*/
|
||||||
private void setupParameters(InjectContext con, ParserWalker walker)
|
private void setupParameters(InjectContext con, ParserWalker walker)
|
||||||
throws UnknownInstructionException {
|
throws UnknownInstructionException, NotFoundException {
|
||||||
checkParameterRestrictions(con, walker.getAddr());
|
checkParameterRestrictions(con, walker.getAddr());
|
||||||
for (int i = 0; i < inputlist.length; ++i) {
|
for (int i = 0; i < inputlist.length; ++i) {
|
||||||
walker.allocateOperand();
|
walker.allocateOperand();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue