#include "paramid.hh"
#define MAXDEPTH 10
void ParamMeasure::walkforward( WalkState &state, PcodeOp *ignoreop, Varnode *vn )
{
state.depth += 1;
if (state.depth >= MAXDEPTH) {
state.depth -= 1;
return;
}
list<PcodeOp *>::const_iterator iter = vn->beginDescend();
while( rank != state.terminalrank && iter != vn->endDescend() ) {
PcodeOp *op = *iter;
if( op != ignoreop ) {
OpCode oc = op->getOpcode()->getOpcode();
switch( oc ) {
case CPUI_BRANCH:
case CPUI_BRANCHIND:
if( op->getSlot(vn) == 0 ) updaterank( DIRECTREAD, state.best );
break;
case CPUI_CBRANCH:
if( op->getSlot(vn) < 2 ) updaterank( DIRECTREAD, state.best );
break;
case CPUI_CALL:
case CPUI_CALLIND:
if( op->getSlot(vn) == 0 ) updaterank( DIRECTREAD, state.best );
else {
numcalls++;
updaterank( SUBFNPARAM, state.best );
}
break;
case CPUI_CALLOTHER:
updaterank( DIRECTREAD, state.best );
break;
case CPUI_RETURN:
updaterank( THISFNRETURN, state.best );
break;
case CPUI_INDIRECT:
updaterank( INDIRECT, state.best );
break;
case CPUI_MULTIEQUAL:
if( !op->getParent()->isLoopIn(op->getSlot(vn)) ) walkforward( state, (PcodeOp *)0, op->getOut() );
break;
default:
updaterank( DIRECTREAD, state.best );
break;
}
}
iter++;
}
state.depth -= 1;
}
void ParamMeasure::walkbackward( WalkState &state, PcodeOp *ignoreop, Varnode *vn )
{
if( vn->isInput() ) {
updaterank( THISFNPARAM, state.best );
return;
}
else if( !vn->isWritten() ) {
updaterank( THISFNPARAM, state.best ); return;
}
PcodeOp *op = vn->getDef();
OpCode oc = op->getOpcode()->getOpcode();
switch( oc ) {
case CPUI_BRANCH:
case CPUI_BRANCHIND:
case CPUI_CBRANCH:
case CPUI_CALL:
case CPUI_CALLIND:
break;
case CPUI_CALLOTHER:
if( op->getOut() != (Varnode *) 0 ) updaterank( DIRECTREAD, state.best );
break;
case CPUI_RETURN:
updaterank( SUBFNRETURN, state.best );
break;
case CPUI_INDIRECT:
updaterank( INDIRECT, state.best );
break;
case CPUI_MULTIEQUAL:
for( int4 slot = 0; slot < op->numInput() && rank != state.terminalrank; slot++ )
if( !op->getParent()->isLoopIn(slot) ) walkbackward( state, op, op->getIn(slot) );
break;
default:
ParamMeasure pmfw( vn->getAddr(), vn->getSize(), vn->getType(), INPUT );
pmfw.calculateRank( false, vn, ignoreop );
if( pmfw.getMeasure() == DIRECTREAD )
updaterank( DIRECTWRITEWITHREAD, state.best );
else
updaterank( DIRECTWRITEWITHOUTREAD, state.best );
break;
}
}
void ParamMeasure::calculateRank(bool best,Varnode *basevn,PcodeOp *ignoreop)
{
WalkState state;
state.best = best;
state.depth = 0;
if( best ) {
rank = WORSTRANK;
state.terminalrank = (io == INPUT) ? DIRECTREAD : DIRECTWRITEWITHOUTREAD;
} else {
rank = BESTRANK;
state.terminalrank = INDIRECT;
}
numcalls = 0;
if (io == INPUT)
walkforward(state, ignoreop, basevn);
else
walkbackward(state, ignoreop, basevn);
}
void ParamMeasure::saveXml( ostream &s,string tag,bool moredetail ) const
{
s << "<" + tag +">\n<addr";
vndata.space->saveXmlAttributes( s, vndata.offset, vndata.size );
s << "/>\n";
vntype->saveXml(s);
if( moredetail ) {
s << "<rank";
a_v_i(s,"val",rank);
s << "/>";
}
s << "</" + tag + ">\n";
}
void ParamMeasure::savePretty( ostream &s,bool moredetail ) const
{
s << " Space: " << vndata.space->getName() << "\n";
s << " Addr: " << vndata.offset << "\n";
s << " Size: " << vndata.size << "\n";
s << " Rank: " << rank << "\n";
}
ParamIDAnalysis::ParamIDAnalysis( Funcdata *fd_in, bool justproto )
{
fd = fd_in;
if (justproto) { const FuncProto &fproto( fd->getFuncProto() );
int4 num = fproto.numParams();
for(int4 i=0;i<num;++i) {
ProtoParameter *param = fproto.getParam(i);
InputParamMeasures.push_back( ParamMeasure(param->getAddress(),param->getSize(),
param->getType(),ParamMeasure::INPUT) );
Varnode *vn = fd->findVarnodeInput(param->getSize(),param->getAddress());
if (vn != (Varnode *)0)
InputParamMeasures.back().calculateRank(true,vn,(PcodeOp *)0);
}
ProtoParameter *outparam = fproto.getOutput();
if (!outparam->getAddress().isInvalid()) { OutputParamMeasures.push_back( ParamMeasure( outparam->getAddress(),outparam->getSize(),
outparam->getType(),ParamMeasure::OUTPUT) );
list<PcodeOp *>::const_iterator rtn_iter = fd->beginOp( CPUI_RETURN );
while( rtn_iter != fd->endOp( CPUI_RETURN ) ) {
PcodeOp *rtn_op = *rtn_iter;
if( rtn_op->numInput() == 2 ) {
Varnode *ovn = rtn_op->getIn(1);
if( ovn != (Varnode *)0 ) { OutputParamMeasures.back().calculateRank(true, ovn, rtn_op );
break;
}
}
rtn_iter++;
}
}
}
else {
VarnodeDefSet::const_iterator iter,enditer;
iter = fd->beginDef(Varnode::input);
enditer = fd->endDef(Varnode::input);
while(iter != enditer) {
Varnode *invn = *iter;
++iter;
InputParamMeasures.push_back( ParamMeasure(invn->getAddr(),invn->getSize(),
invn->getType(),ParamMeasure::INPUT) );
InputParamMeasures.back().calculateRank(true, invn, (PcodeOp *)0 );
}
}
}
void ParamIDAnalysis::saveXml( ostream &s,bool moredetail ) const
{
s << "<parammeasures";
a_v( s, "name", fd->getName() );
s << ">\n ";
fd->getAddress().saveXml( s );
s << "\n <proto";
a_v(s,"model", fd->getFuncProto().getModelName());
int4 extrapop = fd->getFuncProto().getExtraPop();
if (extrapop == ProtoModel::extrapop_unknown)
a_v(s,"extrapop","unknown");
else
a_v_i(s,"extrapop",extrapop);
s << "/>\n";
list<ParamMeasure>::const_iterator pm_iter;
for( pm_iter = InputParamMeasures.begin(); pm_iter != InputParamMeasures.end(); ++pm_iter) {
const ParamMeasure &pm( *pm_iter );
s << " ";
pm.saveXml(s,"input",moredetail);
}
for( pm_iter = OutputParamMeasures.begin(); pm_iter != OutputParamMeasures.end() ; ++pm_iter) {
const ParamMeasure &pm( *pm_iter );
s << " ";
pm.saveXml( s, "output", moredetail );
}
s << "</parammeasures>";
s << "\n";
}
void ParamIDAnalysis::savePretty( ostream &s,bool moredetail ) const
{
s << "Param Measures\nFunction: " << fd->getName() << "\nAddress: 0x" << hex << fd->getAddress().getOffset() << "\n";
s << "Model: " << fd->getFuncProto().getModelName() << "\nExtrapop: " << fd->getFuncProto().getExtraPop() << "\n";
s << "Num Params: " << InputParamMeasures.size() << "\n";
list<ParamMeasure>::const_iterator pm_iter = InputParamMeasures.begin();
for( pm_iter = InputParamMeasures.begin(); pm_iter != InputParamMeasures.end() ; ++pm_iter ) {
const ParamMeasure &pm( *pm_iter );
pm.savePretty( s, moredetail );
}
s << "Num Returns: " << OutputParamMeasures.size() << "\n";
pm_iter = OutputParamMeasures.begin();
for( pm_iter = OutputParamMeasures.begin(); pm_iter != OutputParamMeasures.end() ; ++pm_iter) {
const ParamMeasure &pm( *pm_iter );
pm.savePretty( s, moredetail );
}
s << "\n";
}