Merge remote-tracking branch 'origin/patch'

This commit is contained in:
Ryan Kurtz 2024-06-12 11:16:47 -04:00
commit 9e7a5d8b0c
10 changed files with 218 additions and 123 deletions

View file

@ -18,6 +18,7 @@ src/decompile/datatests/condmulti.xml||GHIDRA||||END|
src/decompile/datatests/convert.xml||GHIDRA||||END| src/decompile/datatests/convert.xml||GHIDRA||||END|
src/decompile/datatests/deadvolatile.xml||GHIDRA||||END| src/decompile/datatests/deadvolatile.xml||GHIDRA||||END|
src/decompile/datatests/deindirect.xml||GHIDRA||||END| src/decompile/datatests/deindirect.xml||GHIDRA||||END|
src/decompile/datatests/deindirect2.xml||GHIDRA||||END|
src/decompile/datatests/displayformat.xml||GHIDRA||||END| src/decompile/datatests/displayformat.xml||GHIDRA||||END|
src/decompile/datatests/divopt.xml||GHIDRA||||END| src/decompile/datatests/divopt.xml||GHIDRA||||END|
src/decompile/datatests/dupptr.xml||GHIDRA||||END| src/decompile/datatests/dupptr.xml||GHIDRA||||END|

View file

@ -1674,13 +1674,20 @@ BlockMultiGoto *BlockGraph::newBlockMultiGoto(FlowBlock *bl,int4 outedge)
} }
else { else {
ret = new BlockMultiGoto(bl); ret = new BlockMultiGoto(bl);
int4 origSizeOut = bl->sizeOut();
vector<FlowBlock *> nodes; vector<FlowBlock *> nodes;
nodes.push_back(bl); nodes.push_back(bl);
identifyInternal(ret,nodes); identifyInternal(ret,nodes);
addBlock(ret); addBlock(ret);
ret->addEdge(targetbl); ret->addEdge(targetbl);
if (targetbl != bl) // If the target is itself, edge is already removed by identifyInternal if (targetbl != bl) {
removeEdge(ret,targetbl); if (ret->sizeOut() != origSizeOut) { // If there are less out edges after identifyInternal
// it must have collapsed a self edge (switch out edges are already deduped)
ret->forceOutputNum(ret->sizeOut()+1); // preserve the self edge (it is not the goto edge)
}
removeEdge(ret,targetbl); // Remove the edge to the goto target
}
// else -- the goto edge is a self edge and will get removed by identifyInternal
if (isdefaultedge) if (isdefaultedge)
ret->setDefaultGoto(); ret->setDefaultGoto();
} }

View file

@ -84,12 +84,14 @@ void LoopBody::extendToContainer(const LoopBody &container,vector<FlowBlock *> &
} }
} }
/// This updates the \b head and \b tail nodes to FlowBlock in the current collapsed graph. /// This updates the \b head node to the FlowBlock in the current collapsed graph.
/// This returns the first \b tail and passes back the head. /// The \b tail nodes are also updated until one is found that has not collapsed into \b head.
/// \param top is where \b head is passed back /// This first updated \b tail is returned. The loop may still exist as a \b head node with an
/// out edge back into itself, in which case \b head is returned as the active \b tail.
/// If the loop has been completely collapsed, null is returned.
/// \param graph is the containing control-flow structure /// \param graph is the containing control-flow structure
/// \return the current loop \b head /// \return the current loop \b tail or null
FlowBlock *LoopBody::getCurrentBounds(FlowBlock **top,FlowBlock *graph) FlowBlock *LoopBody::update(FlowBlock *graph)
{ {
while(head->getParent() != graph) while(head->getParent() != graph)
@ -101,10 +103,13 @@ FlowBlock *LoopBody::getCurrentBounds(FlowBlock **top,FlowBlock *graph)
bottom = bottom->getParent(); bottom = bottom->getParent();
tails[i] = bottom; tails[i] = bottom;
if (bottom != head) { // If the loop hasn't been fully collapsed yet if (bottom != head) { // If the loop hasn't been fully collapsed yet
*top = head;
return bottom; return bottom;
} }
} }
for(int4 i=head->sizeOut()-1;i>=0;--i) {
if (head->getOut(i) == head) // Check for head looping with itself
return head;
}
return (FlowBlock *)0; return (FlowBlock *)0;
} }
@ -391,17 +396,17 @@ void LoopBody::emitLikelyEdges(list<FloatingEdge> &likely,FlowBlock *graph)
break; break;
} }
} }
likely.push_back(FloatingEdge(inbl,outbl)); likely.emplace_back(inbl,outbl);
} }
for(int4 i=tails.size()-1;i>=0;--i) { // Go in reverse order, to put out less preferred back-edges first for(int4 i=tails.size()-1;i>=0;--i) { // Go in reverse order, to put out less preferred back-edges first
if ((holdin!=(FlowBlock *)0)&&(i==0)) if ((holdin!=(FlowBlock *)0)&&(i==0))
likely.push_back(FloatingEdge(holdin,holdout)); // Put in delayed exit, right before final backedge likely.emplace_back(holdin,holdout); // Put in delayed exit, right before final backedge
FlowBlock *tail = tails[i]; FlowBlock *tail = tails[i];
int4 sizeout = tail->sizeOut(); int4 sizeout = tail->sizeOut();
for(int4 j=0;j<sizeout;++j) { for(int4 j=0;j<sizeout;++j) {
FlowBlock *bl = tail->getOut(j); FlowBlock *bl = tail->getOut(j);
if (bl == head) // If out edge to head (back-edge for this loop) if (bl == head) // If out edge to head (back-edge for this loop)
likely.push_back(FloatingEdge(tail,head)); // emit it likely.emplace_back(tail,head); // emit it
} }
} }
} }
@ -652,7 +657,7 @@ void TraceDAG::removeTrace(BlockTrace *trace)
{ {
// Record that we should now treat this edge like goto // Record that we should now treat this edge like goto
likelygoto.push_back(FloatingEdge(trace->bottom,trace->destnode)); // Create goto record likelygoto.emplace_back(trace->bottom,trace->destnode); // Create goto record
trace->destnode->setVisitCount( trace->destnode->getVisitCount() + trace->edgelump ); // Ignore edge(s) trace->destnode->setVisitCount( trace->destnode->getVisitCount() + trace->edgelump ); // Ignore edge(s)
BranchPoint *parentbp = trace->top; BranchPoint *parentbp = trace->top;
@ -1194,12 +1199,22 @@ bool CollapseStructure::updateLoopBody(void)
FlowBlock *loopbottom = (FlowBlock *)0; FlowBlock *loopbottom = (FlowBlock *)0;
FlowBlock *looptop = (FlowBlock *)0; FlowBlock *looptop = (FlowBlock *)0;
while (loopbodyiter != loopbody.end()) { // Last innermost loop while (loopbodyiter != loopbody.end()) { // Last innermost loop
loopbottom = (*loopbodyiter).getCurrentBounds(&looptop,&graph); LoopBody &curBody( *loopbodyiter );
loopbottom = curBody.update(&graph);
if (loopbottom != (FlowBlock *)0) { if (loopbottom != (FlowBlock *)0) {
if ((!likelylistfull) || looptop = curBody.getHead();
(likelyiter != likelygoto.end())) // Reaching here means, we removed edges but loop still didn't collapse if (loopbottom == looptop) { // Check for single node looping back to itself
// If sizeout is 1 or 2, the loop would have collapsed, so the node is likely a switch.
likelygoto.clear();
likelygoto.emplace_back(looptop,looptop); // Mark the loop edge as a goto
likelyiter = likelygoto.begin();
likelylistfull = true;
return true;
}
if (!likelylistfull || likelyiter != likelygoto.end()) {
break; // Loop still exists break; // Loop still exists
} }
}
++loopbodyiter; ++loopbodyiter;
likelylistfull = false; // Need to generate likely list for new loopbody (or no loopbody) likelylistfull = false; // Need to generate likely list for new loopbody (or no loopbody)
loopbottom = (FlowBlock *)0; loopbottom = (FlowBlock *)0;

View file

@ -55,7 +55,7 @@ class LoopBody {
public: public:
LoopBody(FlowBlock *h) { head=h; immed_container = (LoopBody *)0; depth=0; } ///< Construct with a loop head LoopBody(FlowBlock *h) { head=h; immed_container = (LoopBody *)0; depth=0; } ///< Construct with a loop head
FlowBlock *getHead(void) const { return head; } ///< Return the head FlowBlock of the loop FlowBlock *getHead(void) const { return head; } ///< Return the head FlowBlock of the loop
FlowBlock *getCurrentBounds(FlowBlock **top,FlowBlock *graph); ///< Return current loop bounds (\b head and \b bottom). FlowBlock *update(FlowBlock *graph); ///< Update loop body to current view
void addTail(FlowBlock *bl) { tails.push_back(bl); } ///< Add a \e tail to the loop void addTail(FlowBlock *bl) { tails.push_back(bl); } ///< Add a \e tail to the loop
FlowBlock *getExitBlock(void) const { return exitblock; } ///< Get the exit FlowBlock or NULL FlowBlock *getExitBlock(void) const { return exitblock; } ///< Get the exit FlowBlock or NULL
void findBase(vector<FlowBlock *> &body); ///< Mark the body FlowBlocks of \b this loop void findBase(vector<FlowBlock *> &body); ///< Mark the body FlowBlocks of \b this loop

View file

@ -4984,38 +4984,37 @@ int4 FuncCallSpecs::transferLockedInputParam(ProtoParameter *param)
return 0; return 0;
} }
/// Return the p-code op whose output Varnode corresponds to the given parameter (return value) /// \brief Return any outputs of \b this CALL that contain or are contained by the given return value parameter
/// ///
/// The Varnode may be attached to the base CALL or CALLIND, but it also may be /// The output Varnodes may be attached to the base CALL or CALLIND, but also may be
/// attached to an INDIRECT preceding the CALL. The output Varnode may not exactly match /// attached to an INDIRECT preceding the CALL. The output Varnodes may not exactly match
/// the dimensions of the given parameter. We return non-null if either: /// the dimensions of the given parameter. We pass back a Varnode if either:
/// - The parameter contains the Varnode (the easier case) OR if /// - The parameter contains the Varnode (the easier case) OR if
/// - The Varnode properly contains the parameter /// - The Varnode properly contains the parameter
/// \param param is the given paramter (return value) /// \param param is the given paramter (return value)
/// \param newoutput will hold any overlapping output Varnodes
/// \return the matching PcodeOp or NULL /// \return the matching PcodeOp or NULL
PcodeOp *FuncCallSpecs::transferLockedOutputParam(ProtoParameter *param) void FuncCallSpecs::transferLockedOutputParam(ProtoParameter *param,vector<Varnode *> &newoutput)
{ {
Varnode *vn = op->getOut(); Varnode *vn = op->getOut();
if (vn != (Varnode *)0) { if (vn != (Varnode *)0) {
if (param->getAddress().justifiedContain(param->getSize(),vn->getAddr(),vn->getSize(),false)==0) if (param->getAddress().justifiedContain(param->getSize(),vn->getAddr(),vn->getSize(),false)>=0)
return op; newoutput.push_back(vn);
if (vn->getAddr().justifiedContain(vn->getSize(),param->getAddress(),param->getSize(),false)==0) else if (vn->getAddr().justifiedContain(vn->getSize(),param->getAddress(),param->getSize(),false)>=0)
return op; newoutput.push_back(vn);
return (PcodeOp *)0;
} }
PcodeOp *indop = op->previousOp(); PcodeOp *indop = op->previousOp();
while((indop!=(PcodeOp *)0)&&(indop->code()==CPUI_INDIRECT)) { while((indop!=(PcodeOp *)0)&&(indop->code()==CPUI_INDIRECT)) {
if (indop->isIndirectCreation()) { if (indop->isIndirectCreation()) {
vn = indop->getOut(); vn = indop->getOut();
if (param->getAddress().justifiedContain(param->getSize(),vn->getAddr(),vn->getSize(),false)==0) if (param->getAddress().justifiedContain(param->getSize(),vn->getAddr(),vn->getSize(),false)>=0)
return indop; newoutput.push_back(vn);
if (vn->getAddr().justifiedContain(vn->getSize(),param->getAddress(),param->getSize(),false)==0) else if (vn->getAddr().justifiedContain(vn->getSize(),param->getAddress(),param->getSize(),false)>=0)
return indop; newoutput.push_back(vn);
} }
indop = indop->previousOp(); indop = indop->previousOp();
} }
return (PcodeOp *)0;
} }
/// \brief List and/or create a Varnode for each input parameter of matching a source prototype /// \brief List and/or create a Varnode for each input parameter of matching a source prototype
@ -5057,19 +5056,14 @@ bool FuncCallSpecs::transferLockedInput(vector<Varnode *> &newinput,const FuncPr
/// \param newoutput will hold the passed back Varnode /// \param newoutput will hold the passed back Varnode
/// \param source is the source prototype /// \param source is the source prototype
/// \return \b true if the passed back value is accurate /// \return \b true if the passed back value is accurate
bool FuncCallSpecs::transferLockedOutput(Varnode *&newoutput,const FuncProto &source) bool FuncCallSpecs::transferLockedOutput(vector<Varnode *> &newoutput,const FuncProto &source)
{ {
ProtoParameter *param = source.getOutput(); ProtoParameter *param = source.getOutput();
if (param->getType()->getMetatype() == TYPE_VOID) { if (param->getType()->getMetatype() == TYPE_VOID) {
newoutput = (Varnode *)0;
return true; return true;
} }
PcodeOp *outop = transferLockedOutputParam(param); transferLockedOutputParam(param,newoutput);
if (outop == (PcodeOp *)0)
newoutput = (Varnode *)0;
else
newoutput = outop->getOut();
return true; return true;
} }
@ -5126,103 +5120,136 @@ void FuncCallSpecs::commitNewInputs(Funcdata &data,vector<Varnode *> &newinput)
/// \brief Update output Varnode to \b this CALL to reflect the formal return value /// \brief Update output Varnode to \b this CALL to reflect the formal return value
/// ///
/// The current return value must be locked and is presumably out of date /// The current return value must be locked and is presumably out of date with the current CALL output.
/// with the current CALL output. Unless the return value is \e void, the /// Unless the return value is \e void, the output Varnode must exist and must be provided.
/// output Varnode must exist and must be provided. /// The Varnode is created/updated to reflect the return value and is set as the CALL output.
/// The Varnode is updated to reflect the return value, /// Any other intersecting outputs are updated to be either truncations or extensions of this.
/// which may involve truncating or extending. Any active trials are updated, /// Any active trials are updated,
/// and the new Varnode is set as the CALL output.
/// \param data is the calling function /// \param data is the calling function
/// \param newout is the provided old output Varnode (or NULL) /// \param newout is the list of intersecting outputs
void FuncCallSpecs::commitNewOutputs(Funcdata &data,Varnode *newout) void FuncCallSpecs::commitNewOutputs(Funcdata &data,vector<Varnode *> &newoutput)
{ {
if (!isOutputLocked()) return; if (!isOutputLocked()) return;
activeoutput.clear(); activeoutput.clear();
if (newout != (Varnode *)0) { if (!newoutput.empty()) {
ProtoParameter *param = getOutput(); ProtoParameter *param = getOutput();
// We could conceivably truncate the output to the correct size to match the parameter // We could conceivably truncate the output to the correct size to match the parameter
activeoutput.registerTrial(param->getAddress(),param->getSize()); activeoutput.registerTrial(param->getAddress(),param->getSize());
PcodeOp *indop = newout->getDef(); if (param->getSize() == 1 && param->getType()->getMetatype() == TYPE_BOOL && data.isTypeRecoveryOn())
if (newout->getSize() == 1 && param->getType()->getMetatype() == TYPE_BOOL && data.isTypeRecoveryOn())
data.opMarkCalculatedBool(op); data.opMarkCalculatedBool(op);
if (newout->getSize() == param->getSize()) { Varnode *exactMatch = (Varnode *)0;
if (indop != op) { for(int4 i=0;i<newoutput.size();++i) {
data.opUnsetOutput(indop); if (newoutput[i]->getSize() == param->getSize()) {
data.opUnlink(indop); // We know this is an indirect creation which is no longer used exactMatch = newoutput[i];
break;
}
}
Varnode *realOut;
PcodeOp *indOp;
if (exactMatch != (Varnode *)0) {
// If we have a Varnode that exactly matches param, make sure it is the output of the CALL
indOp = exactMatch->getDef();
if (op != indOp) {
// If we reach here, we know -op- must have no output // If we reach here, we know -op- must have no output
data.opSetOutput(op,newout); data.opSetOutput(op,exactMatch);
data.opUnlink(indOp); // We know this is an indirect creation which is no longer used
} }
} realOut = exactMatch;
else if (newout->getSize() < param->getSize()) {
// We know newout is properly justified within param
if (indop != op) {
data.opUninsert(indop);
data.opSetOpcode(indop,CPUI_SUBPIECE);
} }
else { else {
indop = data.newOp(2,op->getAddr()); // Otherwise, we create a Varnode matching param
data.opSetOpcode(indop,CPUI_SUBPIECE); data.opUnsetOutput(op);
data.opSetOutput(indop,newout); // Move -newout- from -op- to -indop- realOut = data.newVarnodeOut(param->getSize(),param->getAddress(),op);
} }
Varnode *realout = data.newVarnodeOut(param->getSize(),param->getAddress(),op);
data.opSetInput(indop,realout,0); for(int4 i=0;i<newoutput.size();++i) {
data.opSetInput(indop,data.newConstant(4,0),1); Varnode *oldOut = newoutput[i];
data.opInsertAfter(indop,op); if (oldOut == exactMatch) continue;
indOp = oldOut->getDef();
if (indOp == op)
indOp = (PcodeOp *)0;
if (oldOut->getSize() < param->getSize()) {
if (indOp != (PcodeOp *)0) {
data.opUninsert(indOp);
data.opSetOpcode(indOp,CPUI_SUBPIECE);
} }
else { // param->getSize() < newout->getSize() else {
// We know param is justified contained in newout indOp = data.newOp(2,op->getAddr());
data.opSetOpcode(indOp,CPUI_SUBPIECE);
data.opSetOutput(indOp,oldOut); // Move oldOut from op to indOp
}
int4 overlap = oldOut->overlap(realOut->getAddr(),realOut->getSize());
data.opSetInput(indOp,realOut,0);
data.opSetInput(indOp,data.newConstant(4,(uintb)overlap),1);
data.opInsertAfter(indOp,op);
}
else if (param->getSize() < oldOut->getSize()) {
int4 overlap = oldOut->getAddr().justifiedContain(oldOut->getSize(), param->getAddress(), param->getSize(), false);
VarnodeData vardata; VarnodeData vardata;
// Test whether the new prototype naturally extends its output // Test whether the new prototype naturally extends its output
OpCode opc = assumedOutputExtension(param->getAddress(),param->getSize(),vardata); OpCode opc = assumedOutputExtension(param->getAddress(),param->getSize(),vardata);
Address hiaddr = newout->getAddr(); if (opc != CPUI_COPY && overlap == 0) {
if (opc != CPUI_COPY) { // If oldOut looks like a natural extension of the true output type, create the extension op
// If -newout- looks like a natural extension of the true output type, create the extension op if (opc == CPUI_PIECE) { // Extend based on the data-type
if (opc == CPUI_PIECE) { // Extend based on the datatype
if (param->getType()->getMetatype() == TYPE_INT) if (param->getType()->getMetatype() == TYPE_INT)
opc = CPUI_INT_SEXT; opc = CPUI_INT_SEXT;
else else
opc = CPUI_INT_ZEXT; opc = CPUI_INT_ZEXT;
} }
if (indop != op) { if (indOp != (PcodeOp *)0) {
data.opUninsert(indop); data.opUninsert(indOp);
data.opRemoveInput(indop,1); data.opRemoveInput(indOp,1);
data.opSetOpcode(indop,opc); data.opSetOpcode(indOp,opc);
Varnode *outvn = data.newVarnodeOut(param->getSize(),param->getAddress(),op); data.opSetInput(indOp,realOut,0);
data.opSetInput(indop,outvn,0); data.opInsertAfter(indOp,op);
data.opInsertAfter(indop,op);
} }
else { else {
PcodeOp *extop = data.newOp(1,op->getAddr()); PcodeOp *extop = data.newOp(1,op->getAddr());
data.opSetOpcode(extop,opc); data.opSetOpcode(extop,opc);
data.opSetOutput(extop,newout); // Move newout from -op- to -extop- data.opSetOutput(extop,oldOut); // Move newout from -op- to -extop-
Varnode *outvn = data.newVarnodeOut(param->getSize(),param->getAddress(),op); data.opSetInput(extop,realOut,0);
data.opSetInput(extop,outvn,0);
data.opInsertAfter(extop,op); data.opInsertAfter(extop,op);
} }
} }
else { // If all else fails, concatenate in extra byte from something "indirectly created" by -op- else { // If all else fails, concatenate in extra byte from something "indirectly created" by -op-
int4 hisz = newout->getSize() - param->getSize(); if (indOp != (PcodeOp *)0) {
if (!newout->getAddr().getSpace()->isBigEndian()) data.opUnlink(indOp);
hiaddr = hiaddr + param->getSize();
PcodeOp *newindop = data.newIndirectCreation(op,hiaddr,hisz,true);
if (indop != op) {
data.opUninsert(indop);
data.opSetOpcode(indop,CPUI_PIECE);
Varnode *outvn = data.newVarnodeOut(param->getSize(),param->getAddress(),op);
data.opSetInput(indop,newindop->getOut(),0);
data.opSetInput(indop,outvn,1);
data.opInsertAfter(indop,op);
} }
else { int4 mostSigSize = oldOut->getSize() - overlap - realOut->getSize();
PcodeOp *concatop = data.newOp(2,op->getAddr()); PcodeOp *lastOp = op;
data.opSetOpcode(concatop,CPUI_PIECE); if (overlap != 0) { // We need to append less significant bytes to realOut for this oldOut
data.opSetOutput(concatop,newout); // Move newout from -op- to -concatop- Address loAddr = oldOut->getAddr();
Varnode *outvn = data.newVarnodeOut(param->getSize(),param->getAddress(),op); if (loAddr.isBigEndian())
data.opSetInput(concatop,newindop->getOut(),0); loAddr = loAddr + (oldOut->getSize() - overlap);
data.opSetInput(concatop,outvn,1); PcodeOp *newIndOp = data.newIndirectCreation(op,loAddr,overlap,true);
data.opInsertAfter(concatop,op); PcodeOp *concatOp = data.newOp(2,op->getAddr());
data.opSetOpcode(concatOp,CPUI_PIECE);
data.opSetInput(concatOp,realOut,0); // Most significant part
data.opSetInput(concatOp,newIndOp->getOut(),1); // Least sig
data.opInsertAfter(concatOp,op);
if (mostSigSize != 0) {
if (loAddr.isBigEndian())
data.newVarnodeOut(overlap+realOut->getSize(),realOut->getAddr(),concatOp);
else
data.newVarnodeOut(overlap+realOut->getSize(),loAddr,concatOp);
}
lastOp = concatOp;
}
if (mostSigSize != 0) { // We need to append more significant bytes to realOut for this oldOut
Address hiAddr = oldOut->getAddr();
if (!hiAddr.isBigEndian())
hiAddr = hiAddr + (realOut->getSize() + overlap);
PcodeOp *newIndOp = data.newIndirectCreation(op,hiAddr,mostSigSize,true);
PcodeOp *concatOp = data.newOp(2,op->getAddr());
data.opSetOpcode(concatOp,CPUI_PIECE);
data.opSetInput(concatOp,newIndOp->getOut(),0);
data.opSetInput(concatOp,lastOp->getOut(),1);
data.opInsertAfter(concatOp,lastOp);
lastOp = concatOp;
}
data.opSetOutput(lastOp,oldOut); // We have completed the redefinition of this oldOut
} }
} }
} }
@ -5307,7 +5334,8 @@ void FuncCallSpecs::doInputJoin(int4 slot1,bool ishislot)
/// \param newinput will hold the new list of input Varnodes for the CALL /// \param newinput will hold the new list of input Varnodes for the CALL
/// \param newoutput will hold the new output Varnode or NULL /// \param newoutput will hold the new output Varnode or NULL
/// \return \b true if \b this can be fully converted /// \return \b true if \b this can be fully converted
bool FuncCallSpecs::lateRestriction(const FuncProto &restrictedProto,vector<Varnode *> &newinput,Varnode *&newoutput) bool FuncCallSpecs::lateRestriction(const FuncProto &restrictedProto,vector<Varnode *> &newinput,
vector<Varnode *> &newoutput)
{ {
if (!hasModel()) { if (!hasModel()) {
@ -5357,7 +5385,7 @@ void FuncCallSpecs::deindirect(Funcdata &data,Funcdata *newfd)
// Try our best to merge existing prototype // Try our best to merge existing prototype
// with the one we have just been handed // with the one we have just been handed
vector<Varnode *> newinput; vector<Varnode *> newinput;
Varnode *newoutput; vector<Varnode *> newoutput;
FuncProto &newproto( newfd->getFuncProto() ); FuncProto &newproto( newfd->getFuncProto() );
if ((!newproto.isNoReturn())&&(!newproto.isInline())) { if ((!newproto.isNoReturn())&&(!newproto.isInline())) {
if (isOverride()) // If we are overridden at the call-site if (isOverride()) // If we are overridden at the call-site
@ -5387,7 +5415,7 @@ void FuncCallSpecs::forceSet(Funcdata &data,const FuncProto &fp)
{ {
vector<Varnode *> newinput; vector<Varnode *> newinput;
Varnode *newoutput; vector<Varnode *> newoutput;
// Copy the recovered prototype into the override manager so that // Copy the recovered prototype into the override manager so that
// future restarts don't have to rediscover it // future restarts don't have to rediscover it

View file

@ -1657,11 +1657,11 @@ class FuncCallSpecs : public FuncProto {
Varnode *getSpacebaseRelative(void) const; ///< Get the active stack-pointer Varnode at \b this call site Varnode *getSpacebaseRelative(void) const; ///< Get the active stack-pointer Varnode at \b this call site
Varnode *buildParam(Funcdata &data,Varnode *vn,ProtoParameter *param,Varnode *stackref); Varnode *buildParam(Funcdata &data,Varnode *vn,ProtoParameter *param,Varnode *stackref);
int4 transferLockedInputParam(ProtoParameter *param); int4 transferLockedInputParam(ProtoParameter *param);
PcodeOp *transferLockedOutputParam(ProtoParameter *param); void transferLockedOutputParam(ProtoParameter *param,vector<Varnode *> &newoutput);
bool transferLockedInput(vector<Varnode *> &newinput,const FuncProto &source); bool transferLockedInput(vector<Varnode *> &newinput,const FuncProto &source);
bool transferLockedOutput(Varnode *&newoutput,const FuncProto &source); bool transferLockedOutput(vector<Varnode *> &newoutput,const FuncProto &source);
void commitNewInputs(Funcdata &data,vector<Varnode *> &newinput); void commitNewInputs(Funcdata &data,vector<Varnode *> &newinput);
void commitNewOutputs(Funcdata &data,Varnode *newout); void commitNewOutputs(Funcdata &data,vector<Varnode *> &newoutput);
void collectOutputTrialVarnodes(vector<Varnode *> &trialvn); void collectOutputTrialVarnodes(vector<Varnode *> &trialvn);
void setStackPlaceholderSlot(int4 slot) { stackPlaceholderSlot = slot; void setStackPlaceholderSlot(int4 slot) { stackPlaceholderSlot = slot;
if (isinputactive) activeinput.setPlaceholderSlot(); } ///< Set the slot of the stack-pointer placeholder if (isinputactive) activeinput.setPlaceholderSlot(); } ///< Set the slot of the stack-pointer placeholder
@ -1702,7 +1702,7 @@ public:
bool checkInputJoin(int4 slot1,bool ishislot,Varnode *vn1,Varnode *vn2) const; bool checkInputJoin(int4 slot1,bool ishislot,Varnode *vn1,Varnode *vn2) const;
void doInputJoin(int4 slot1,bool ishislot); void doInputJoin(int4 slot1,bool ishislot);
bool lateRestriction(const FuncProto &restrictedProto,vector<Varnode *> &newinput,Varnode *&newoutput); bool lateRestriction(const FuncProto &restrictedProto,vector<Varnode *> &newinput,vector<Varnode *> &newoutput);
void deindirect(Funcdata &data,Funcdata *newfd); void deindirect(Funcdata &data,Funcdata *newfd);
void forceSet(Funcdata &data,const FuncProto &fp); void forceSet(Funcdata &data,const FuncProto &fp);
void insertPcode(Funcdata &data); void insertPcode(Funcdata &data);

View file

@ -1515,6 +1515,8 @@ bool SplitFlow::addOp(PcodeOp *op,TransformVar *rvn,int4 slot)
if (op->code() == CPUI_INDIRECT) { if (op->code() == CPUI_INDIRECT) {
opSetInput(loOp,newIop(op->getIn(1)),1); opSetInput(loOp,newIop(op->getIn(1)),1);
opSetInput(hiOp,newIop(op->getIn(1)),1); opSetInput(hiOp,newIop(op->getIn(1)),1);
loOp->inheritIndirect(op);
hiOp->inheritIndirect(op);
numParam = 1; numParam = 1;
} }
for(int4 i=0;i<numParam;++i) { for(int4 i=0;i<numParam;++i) {

View file

@ -268,6 +268,19 @@ bool TransformOp::attemptInsertion(Funcdata *fd)
return true; // Already inserted return true; // Already inserted
} }
/// Prepare to build the transformed INDIRECT PcodeOp based on settings from the given INDIRECT.
/// \param indOp is the given INDIRECT
void TransformOp::inheritIndirect(PcodeOp *indOp)
{
if (indOp->isIndirectCreation()) {
if (indOp->getIn(0)->isIndirectZero())
special |= TransformOp::indirect_creation;
else
special |= TransformOp::indirect_creation_possible_out;
}
}
void LanedRegister::LanedIterator::normalize(void) void LanedRegister::LanedIterator::normalize(void)
{ {

View file

@ -87,6 +87,7 @@ private:
public: public:
TransformVar *getOut(void) const { return output; } ///< Get the output placeholder variable for \b this operator TransformVar *getOut(void) const { return output; } ///< Get the output placeholder variable for \b this operator
TransformVar *getIn(int4 i) const { return input[i]; } ///< Get the i-th input placeholder variable for \b this TransformVar *getIn(int4 i) const { return input[i]; } ///< Get the i-th input placeholder variable for \b this
void inheritIndirect(PcodeOp *indOp); ///< Set \e indirect \e creation flags for \b this based on given INDIRECT
}; };
/// \brief Describes a (register) storage location and the ways it might be split into lanes /// \brief Describes a (register) storage location and the ways it might be split into lanes

View file

@ -0,0 +1,28 @@
<decompilertest>
<binaryimage arch="x86:LE:64:default:gcc">
<!--
A contrived function with an indirect call that eventually collapses to a function
with an 8-byte return value. Prior to collapse, there are likely to be 2 separate
pieces being read as output from the function. After collapse these should get
concatenated and leave no shadow varnodes.
-->
<bytechunk space="ram" offset="0x100000" readonly="true">
554889e54883ec3048c7c34600100048
895de84889f94889f7488b5de8ffd348
8d59104889036631c0c3
</bytechunk>
<symbol space="ram" offset="0x100000" name="deind26"/>
<symbol space="ram" offset="0x100046" name="obtainPtr"/>
</binaryimage>
<script>
<com>parse line extern int2 deind26(int4 **ptr,char *nm);</com>
<com>parse line extern int4 *obtainPtr(char *nm);</com>
<com>lo fu deind26</com>
<com>decompile</com>
<com>print C</com>
<com>quit</com>
</script>
<stringmatch name="Deindirect Output #1" min="1" max="1">piVar1 = obtainPtr\(nm\);</stringmatch>
<stringmatch name="Deindirect Output #2" min="1" max="1">return 0;</stringmatch>
<stringmatch name="Deindirect Output #3" min="0" max="0">CONCAT</stringmatch>
</decompilertest>