mirror of
https://github.com/NationalSecurityAgency/ghidra
synced 2024-08-28 13:30:21 +00:00
GP-2601 Adjustments to setting up callspecs
This commit is contained in:
parent
a64afa37a7
commit
e45be5da7d
|
@ -25,6 +25,7 @@ src/decompile/datatests/forloop_varused.xml||GHIDRA||||END|
|
|||
src/decompile/datatests/forloop_withskip.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/impliedfield.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/indproto.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/injectoverride.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/loopcomment.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/mixfloatint.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/modulo.xml||GHIDRA||||END|
|
||||
|
|
|
@ -323,7 +323,7 @@ PcodeOp *FlowInfo::xrefControlFlow(list<PcodeOp *>::const_iterator oiter,bool &s
|
|||
--oiter; // Backup one op, to pickup halt
|
||||
break;
|
||||
case CPUI_CALLIND:
|
||||
if (setupCallindSpecs(op,true,fc))
|
||||
if (setupCallindSpecs(op,fc))
|
||||
--oiter; // Backup one op, to pickup halt
|
||||
break;
|
||||
case CPUI_CALLOTHER:
|
||||
|
@ -685,27 +685,20 @@ bool FlowInfo::setupCallSpecs(PcodeOp *op,FuncCallSpecs *fc)
|
|||
/// The new FuncCallSpecs object is created and initialized based on
|
||||
/// the CALLIND op at the site. Any overriding prototype or control-flow may be examined and applied.
|
||||
/// \param op is the given CALLIND op
|
||||
/// \param tryoverride is \b true is overrides should be applied for the call site
|
||||
/// \param fc is non-NULL if \e injection is in progress and a cycle check needs to be made
|
||||
/// \return \b true if it is discovered the sub-function never returns
|
||||
bool FlowInfo::setupCallindSpecs(PcodeOp *op,bool tryoverride,FuncCallSpecs *fc)
|
||||
bool FlowInfo::setupCallindSpecs(PcodeOp *op,FuncCallSpecs *fc)
|
||||
|
||||
{
|
||||
FuncCallSpecs *res;
|
||||
res = new FuncCallSpecs(op);
|
||||
qlst.push_back(res);
|
||||
|
||||
if (tryoverride) {
|
||||
data.getOverride().applyIndirect(data,*res);
|
||||
data.getOverride().applyPrototype(data,*res);
|
||||
}
|
||||
data.getOverride().applyIndirect(data,*res);
|
||||
if (fc != (FuncCallSpecs *)0 && fc->getEntryAddress() == res->getEntryAddress())
|
||||
res->setAddress(Address()); // Cancel any indirect override
|
||||
data.getOverride().applyPrototype(data,*res);
|
||||
queryCall(*res);
|
||||
if (fc != (FuncCallSpecs *)0) {
|
||||
if (fc->getEntryAddress() == res->getEntryAddress()) {
|
||||
res->cancelInjectId();
|
||||
res->setAddress(Address()); // Cancel any indirect override
|
||||
}
|
||||
}
|
||||
|
||||
if (!res->getEntryAddress().isInvalid()) { // If we are overridden to a direct call
|
||||
// Change indirect pcode call into a normal pcode call
|
||||
|
@ -721,9 +714,9 @@ void FlowInfo::truncateIndirectJump(PcodeOp *op,int4 failuremode)
|
|||
|
||||
{
|
||||
data.opSetOpcode(op,CPUI_CALLIND); // Turn jump into call
|
||||
bool tryoverride = (failuremode == 2);
|
||||
setupCallindSpecs(op,tryoverride,(FuncCallSpecs *)0);
|
||||
data.getCallSpecs(op)->setBadJumpTable(true);
|
||||
setupCallindSpecs(op,(FuncCallSpecs *)0);
|
||||
if (failuremode != 2) // Unless the switch was a thunk mechanism
|
||||
data.getCallSpecs(op)->setBadJumpTable(true); // Consider using special name for switch variable
|
||||
|
||||
// Create an artificial return
|
||||
PcodeOp *truncop = artificialHalt(op->getAddr(),0);
|
||||
|
@ -1031,7 +1024,7 @@ void FlowInfo::xrefInlinedBranch(PcodeOp *op)
|
|||
if (op->code() == CPUI_CALL)
|
||||
setupCallSpecs(op,(FuncCallSpecs *)0);
|
||||
else if (op->code() == CPUI_CALLIND)
|
||||
setupCallindSpecs(op,true,(FuncCallSpecs *)0);
|
||||
setupCallindSpecs(op,(FuncCallSpecs *)0);
|
||||
else if (op->code() == CPUI_BRANCHIND) {
|
||||
JumpTable *jt = data.linkJumpTable(op);
|
||||
if (jt == (JumpTable *)0)
|
||||
|
|
|
@ -125,7 +125,7 @@ private:
|
|||
bool checkForFlowModification(FuncCallSpecs &fspecs);
|
||||
void queryCall(FuncCallSpecs &fspecs); ///< Try to recover the Funcdata object corresponding to a given call
|
||||
bool setupCallSpecs(PcodeOp *op,FuncCallSpecs *fc); ///< Set up the FuncCallSpecs object for a new call site
|
||||
bool setupCallindSpecs(PcodeOp *op,bool tryoverride,FuncCallSpecs *fc);
|
||||
bool setupCallindSpecs(PcodeOp *op,FuncCallSpecs *fc);
|
||||
void xrefInlinedBranch(PcodeOp *op); ///< Check for control-flow in a new injected p-code op
|
||||
void doInjection(InjectPayload *payload,InjectContext &icontext,PcodeOp *op,FuncCallSpecs *fc);
|
||||
void injectUserOp(PcodeOp *op); ///< Perform \e injection for a given user-defined p-code op
|
||||
|
|
|
@ -3743,6 +3743,19 @@ void FuncProto::clearInput(void)
|
|||
flags &= ~((uint4)voidinputlock); // If a void was locked in clear it
|
||||
}
|
||||
|
||||
/// Set the id directly.
|
||||
/// \param id is the new id
|
||||
void FuncProto::setInjectId(int4 id)
|
||||
|
||||
{
|
||||
if (id < 0)
|
||||
cancelInjectId();
|
||||
else {
|
||||
injectid = id;
|
||||
flags |= is_inline;
|
||||
}
|
||||
}
|
||||
|
||||
void FuncProto::cancelInjectId(void)
|
||||
|
||||
{
|
||||
|
@ -5098,8 +5111,6 @@ void FuncCallSpecs::deindirect(Funcdata &data,Funcdata *newfd)
|
|||
Varnode *vn = data.newVarnodeCallSpecs(this);
|
||||
data.opSetInput(op,vn,0);
|
||||
data.opSetOpcode(op,CPUI_CALL);
|
||||
if (isOverride()) // If we are overridden at the call-site
|
||||
return; // Don't use the discovered function prototype
|
||||
|
||||
data.getOverride().insertIndirectOverride(op->getAddr(),entryaddress);
|
||||
|
||||
|
@ -5108,14 +5119,17 @@ void FuncCallSpecs::deindirect(Funcdata &data,Funcdata *newfd)
|
|||
vector<Varnode *> newinput;
|
||||
Varnode *newoutput;
|
||||
FuncProto &newproto( newfd->getFuncProto() );
|
||||
if ((!newproto.isNoReturn())&&(!newproto.isInline())&&
|
||||
lateRestriction(newproto,newinput,newoutput)) {
|
||||
commitNewInputs(data,newinput);
|
||||
commitNewOutputs(data,newoutput);
|
||||
}
|
||||
else {
|
||||
data.setRestartPending(true);
|
||||
if ((!newproto.isNoReturn())&&(!newproto.isInline())) {
|
||||
if (isOverride()) // If we are overridden at the call-site
|
||||
return; // Don't use the discovered function prototype
|
||||
|
||||
if (lateRestriction(newproto,newinput,newoutput)) {
|
||||
commitNewInputs(data,newinput);
|
||||
commitNewOutputs(data,newoutput);
|
||||
return; // We have successfully updated the prototype, don't restart
|
||||
}
|
||||
}
|
||||
data.setRestartPending(true);
|
||||
}
|
||||
|
||||
/// \brief Force a more restrictive prototype on \b this call site
|
||||
|
|
|
@ -1428,6 +1428,7 @@ public:
|
|||
void clearUnlockedInput(void); ///< Clear input parameters that have not been locked
|
||||
void clearUnlockedOutput(void); ///< Clear the return value if it has not been locked
|
||||
void clearInput(void); ///< Clear all input parameters regardless of lock
|
||||
void setInjectId(int4 id); ///< Associate a given injection with \b this prototype
|
||||
void cancelInjectId(void); ///< Turn-off any in-lining for this function
|
||||
|
||||
void resolveModel(ParamActive *active);
|
||||
|
|
|
@ -125,6 +125,7 @@ void IfaceDecompCapability::registerCommands(IfaceStatus *status)
|
|||
status->registerCom(new IfcCallGraphList(),"callgraph","list");
|
||||
status->registerCom(new IfcCallFixup(),"fixup","call");
|
||||
status->registerCom(new IfcCallOtherFixup(),"fixup","callother");
|
||||
status->registerCom(new IfcFixupApply(),"fixup","apply");
|
||||
status->registerCom(new IfcVolatile(),"volatile");
|
||||
status->registerCom(new IfcReadonly(),"readonly");
|
||||
status->registerCom(new IfcPointerSetting(),"pointer","setting");
|
||||
|
@ -2883,6 +2884,43 @@ void IfcCallOtherFixup::execute(istream &s)
|
|||
*status->optr << "Successfully registered callotherfixup" << endl;
|
||||
}
|
||||
|
||||
/// \class IfcFixupApply
|
||||
/// \brief Apply a call-fixup to a particular function: `fixup apply <fixup> <function>`
|
||||
///
|
||||
/// The call-fixup and function are named from the command-line. If they both exist,
|
||||
/// the fixup is set on the function's prototype.
|
||||
void IfcFixupApply::execute(istream &s)
|
||||
|
||||
{
|
||||
if (dcp->conf == (Architecture *)0)
|
||||
throw IfaceExecutionError("No load image present");
|
||||
|
||||
string fixupName,funcName;
|
||||
|
||||
s >> ws;
|
||||
if (s.eof())
|
||||
throw IfaceParseError("Missing fixup name");
|
||||
s >> fixupName >> ws;
|
||||
if (s.eof())
|
||||
throw IfaceParseError("Missing function name");
|
||||
s >> funcName;
|
||||
|
||||
int4 injectid = dcp->conf->pcodeinjectlib->getPayloadId(InjectPayload::CALLFIXUP_TYPE, fixupName);
|
||||
if (injectid < 0)
|
||||
throw IfaceExecutionError("Unknown fixup: " + fixupName);
|
||||
|
||||
string basename;
|
||||
Scope *funcscope = dcp->conf->symboltab->resolveScopeFromSymbolName(funcName,"::",basename,(Scope *)0);
|
||||
if (funcscope == (Scope *)0)
|
||||
throw IfaceExecutionError("Bad namespace: "+funcName);
|
||||
Funcdata *fd = funcscope->queryFunction( basename ); // Is function already in database
|
||||
if (fd == (Funcdata *)0)
|
||||
throw IfaceExecutionError("Unknown function name: "+funcName);
|
||||
|
||||
fd->getFuncProto().setInjectId(injectid);
|
||||
*status->optr << "Successfully applied callfixup" << endl;
|
||||
}
|
||||
|
||||
/// \class IfcVolatile
|
||||
/// \brief Mark a memory range as volatile: `volatile <address+size>`
|
||||
///
|
||||
|
|
|
@ -531,6 +531,11 @@ public:
|
|||
virtual void execute(istream &s);
|
||||
};
|
||||
|
||||
class IfcFixupApply : public IfaceDecompCommand {
|
||||
public:
|
||||
virtual void execute(istream &s);
|
||||
};
|
||||
|
||||
class IfcCountPcode : public IfaceDecompCommand {
|
||||
public:
|
||||
virtual void execute(istream &s);
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
<decompilertest>
|
||||
<binaryimage arch="x86:LE:64:default:windows">
|
||||
<!--
|
||||
Example of CALLIND collapsing to inject function with CALLIND.
|
||||
Example of CALL injecting to CALLIND that then collapses.
|
||||
-->
|
||||
<bytechunk space="ram" offset="0x18000c000" readonly="true">
|
||||
534883ec20ff1516000000c300000000
|
||||
48b830c000800100000066e80200c300
|
||||
c320c0008001000000
|
||||
</bytechunk>
|
||||
<symbol space="ram" offset="0x18000c000" name="callind_inject"/>
|
||||
<symbol space="ram" offset="0x18000c010" name="inject_collapse"/>
|
||||
<symbol space="ram" offset="0x18000c020" name="_guard_dispatch_icall"/>
|
||||
<symbol space="ram" offset="0x18000c030" name="collapsed"/>
|
||||
</binaryimage>
|
||||
<script>
|
||||
<com>option readonly on</com>
|
||||
<com>fixup apply guard_dispatch_icall _guard_dispatch_icall</com>
|
||||
<com>parse line extern void collapsed(int4);</com>
|
||||
<com>lo fu callind_inject</com>
|
||||
<com>override proto r0x18000c005 <![CDATA[ void func(int4,int4); ]]> </com>
|
||||
<com>decompile</com>
|
||||
<com>print C</com>
|
||||
<com>lo fu inject_collapse</com>
|
||||
<com>decompile</com>
|
||||
<com>print C</com>
|
||||
<com>quit</com>
|
||||
</script>
|
||||
<stringmatch name="Inject Override #1" min="1" max="1">\(\*in_RAX\)\(param_1,param_2\);</stringmatch>
|
||||
<stringmatch name="Inject Override #2" min="1" max="1">collapsed\(param_1\);</stringmatch>
|
||||
</decompilertest>
|
|
@ -20,10 +20,10 @@ import ghidra.app.decompiler.ClangToken;
|
|||
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
|
||||
import ghidra.app.util.HelpTopics;
|
||||
import ghidra.program.database.symbol.CodeSymbol;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.pcode.HighFunction;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.util.*;
|
||||
|
||||
|
@ -39,16 +39,17 @@ public class DeletePrototypeOverrideAction extends AbstractDecompilerAction {
|
|||
if (tokenAtCursor == null) {
|
||||
return null;
|
||||
}
|
||||
Address addr = tokenAtCursor.getMinAddress();
|
||||
if (addr == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Namespace overspace = HighFunction.findOverrideSpace(func);
|
||||
if (overspace == null) {
|
||||
return null;
|
||||
}
|
||||
PcodeOp op = OverridePrototypeAction.getCallOp(func.getProgram(), tokenAtCursor);
|
||||
if (op == null) {
|
||||
return null;
|
||||
}
|
||||
SymbolTable symtab = func.getProgram().getSymbolTable();
|
||||
SymbolIterator iter = symtab.getSymbols(overspace);
|
||||
SymbolIterator iter = symtab.getSymbolsAsIterator(op.getSeqnum().getTarget());
|
||||
while (iter.hasNext()) {
|
||||
Symbol sym = iter.next();
|
||||
if (!sym.getName().startsWith("prt")) {
|
||||
|
@ -57,7 +58,7 @@ public class DeletePrototypeOverrideAction extends AbstractDecompilerAction {
|
|||
if (!(sym instanceof CodeSymbol)) {
|
||||
continue;
|
||||
}
|
||||
if (!sym.getAddress().equals(addr)) {
|
||||
if (!sym.getParentNamespace().equals(overspace)) {
|
||||
continue;
|
||||
}
|
||||
return (CodeSymbol) sym;
|
||||
|
|
|
@ -47,7 +47,7 @@ public class OverridePrototypeAction extends AbstractDecompilerAction {
|
|||
* @param tokenAtCursor is the point in the window the user has selected
|
||||
* @return the PcodeOp or null
|
||||
*/
|
||||
private static PcodeOp getCallOp(Program program, ClangToken tokenAtCursor) {
|
||||
public static PcodeOp getCallOp(Program program, ClangToken tokenAtCursor) {
|
||||
if (tokenAtCursor == null) {
|
||||
return null;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue