/* ### * IP: GHIDRA * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "pcodecompile.hh" string Location::format(void) const { ostringstream s; s << filename << ":" << dec << lineno; return s.str(); } ExprTree::ExprTree(VarnodeTpl *vn) { outvn = vn; ops = new vector; } ExprTree::ExprTree(OpTpl *op) { ops = new vector; ops->push_back(op); if (op->getOut() != (VarnodeTpl *)0) outvn = new VarnodeTpl(*op->getOut()); else outvn = (VarnodeTpl *)0; } ExprTree::~ExprTree(void) { if (outvn != (VarnodeTpl *)0) delete outvn; if (ops != (vector *)0) { for(int4 i=0;isize();++i) delete (*ops)[i]; delete ops; } } vector *ExprTree::appendParams(OpTpl *op,vector *param) { // Create op expression with entire list of expression // inputs vector *res = new vector; for(int4 i=0;isize();++i) { res->insert(res->end(),(*param)[i]->ops->begin(),(*param)[i]->ops->end()); (*param)[i]->ops->clear(); op->addInput((*param)[i]->outvn); (*param)[i]->outvn = (VarnodeTpl *)0; delete (*param)[i]; } res->push_back(op); delete param; return res; } vector *ExprTree::toVector(ExprTree *expr) { // Grab the op vector and delete the output expression vector *res = expr->ops; expr->ops = (vector *)0; delete expr; return res; } void ExprTree::setOutput(VarnodeTpl *newout) { // Force the output of the expression to be new out // If the original output is named, this requires // an extra COPY op OpTpl *op; if (outvn == (VarnodeTpl *)0) throw SleighError("Expression has no output"); if (outvn->isUnnamed()) { delete outvn; op = ops->back(); op->clearOutput(); op->setOutput(newout); } else { op = new OpTpl(CPUI_COPY); op->addInput(outvn); op->setOutput(newout); ops->push_back(op); } outvn = new VarnodeTpl(*newout); } void PcodeCompile::force_size(VarnodeTpl *vt,const ConstTpl &size,const vector &ops) { if ((vt->getSize().getType()!=ConstTpl::real)||(vt->getSize().getReal() != 0)) return; // Size already exists vt->setSize(size); if (!vt->isLocalTemp()) return; // If the variable is a local temporary // The size may need to be propagated to the various // uses of the variable OpTpl *op; VarnodeTpl *vn; for(int4 i=0;igetOut(); if ((vn!=(VarnodeTpl *)0)&&(vn->isLocalTemp())) { if (vn->getOffset() == vt->getOffset()) { if ((size.getType() == ConstTpl::real)&&(vn->getSize().getType() == ConstTpl::real)&& (vn->getSize().getReal() != 0) && (vn->getSize().getReal() != size.getReal())) throw SleighError("Localtemp size mismatch"); vn->setSize(size); } } for(int4 j=0;jnumInput();++j) { vn = op->getIn(j); if (vn->isLocalTemp()&&(vn->getOffset()==vt->getOffset())) { if ((size.getType() == ConstTpl::real)&&(vn->getSize().getType() == ConstTpl::real)&& (vn->getSize().getReal() != 0) && (vn->getSize().getReal() != size.getReal())) throw SleighError("Localtemp size mismatch"); vn->setSize(size); } } } } void PcodeCompile::matchSize(int4 j,OpTpl *op,bool inputonly,const vector &ops) { // Find something to fill in zero size varnode // j is the slot we are trying to fill (-1=output) // Don't check output for non-zero if inputonly is true VarnodeTpl *match = (VarnodeTpl *)0; VarnodeTpl *vt; int4 i,inputsize; vt = (j==-1) ? op->getOut() : op->getIn(j); if (!inputonly) { if (op->getOut() != (VarnodeTpl *)0) if (!op->getOut()->isZeroSize()) match = op->getOut(); } inputsize = op->numInput(); for(i=0;igetIn(i)->isZeroSize()) continue; match = op->getIn(i); } if (match != (VarnodeTpl *)0) force_size(vt,match->getSize(),ops); } void PcodeCompile::fillinZero(OpTpl *op,const vector &ops) { // Try to get rid of zero size varnodes in op // Right now this is written assuming operands for the constructor are // are built before any other pcode in the constructor is generated int4 inputsize,i; switch(op->getOpcode()) { case CPUI_COPY: // Instructions where all inputs and output are same size case CPUI_INT_ADD: case CPUI_INT_SUB: case CPUI_INT_2COMP: case CPUI_INT_NEGATE: case CPUI_INT_XOR: case CPUI_INT_AND: case CPUI_INT_OR: case CPUI_INT_MULT: case CPUI_INT_DIV: case CPUI_INT_SDIV: case CPUI_INT_REM: case CPUI_INT_SREM: case CPUI_FLOAT_ADD: case CPUI_FLOAT_DIV: case CPUI_FLOAT_MULT: case CPUI_FLOAT_SUB: case CPUI_FLOAT_NEG: case CPUI_FLOAT_ABS: case CPUI_FLOAT_SQRT: case CPUI_FLOAT_CEIL: case CPUI_FLOAT_FLOOR: case CPUI_FLOAT_ROUND: if ((op->getOut()!=(VarnodeTpl *)0)&&(op->getOut()->isZeroSize())) matchSize(-1,op,false,ops); inputsize = op->numInput(); for(i=0;igetIn(i)->isZeroSize()) matchSize(i,op,false,ops); break; case CPUI_INT_EQUAL: // Instructions with bool output case CPUI_INT_NOTEQUAL: case CPUI_INT_SLESS: case CPUI_INT_SLESSEQUAL: case CPUI_INT_LESS: case CPUI_INT_LESSEQUAL: case CPUI_INT_CARRY: case CPUI_INT_SCARRY: case CPUI_INT_SBORROW: case CPUI_FLOAT_EQUAL: case CPUI_FLOAT_NOTEQUAL: case CPUI_FLOAT_LESS: case CPUI_FLOAT_LESSEQUAL: case CPUI_FLOAT_NAN: case CPUI_BOOL_NEGATE: case CPUI_BOOL_XOR: case CPUI_BOOL_AND: case CPUI_BOOL_OR: if (op->getOut()->isZeroSize()) force_size(op->getOut(),ConstTpl(ConstTpl::real,1),ops); inputsize = op->numInput(); for(i=0;igetIn(i)->isZeroSize()) matchSize(i,op,true,ops); break; // The shift amount does not necessarily have to be the same size // But if no size is specified, assume it is the same size case CPUI_INT_LEFT: case CPUI_INT_RIGHT: case CPUI_INT_SRIGHT: if (op->getOut()->isZeroSize()) { if (!op->getIn(0)->isZeroSize()) force_size(op->getOut(),op->getIn(0)->getSize(),ops); } else if (op->getIn(0)->isZeroSize()) force_size(op->getIn(0),op->getOut()->getSize(),ops); // fallthru to subpiece constant check case CPUI_SUBPIECE: if (op->getIn(1)->isZeroSize()) force_size(op->getIn(1),ConstTpl(ConstTpl::real,4),ops); break; case CPUI_CPOOLREF: if (op->getOut()->isZeroSize() && (!op->getIn(0)->isZeroSize())) force_size(op->getOut(),op->getIn(0)->getSize(),ops); if (op->getIn(0)->isZeroSize() && (!op->getOut()->isZeroSize())) force_size(op->getIn(0),op->getOut()->getSize(),ops); for(i=1;inumInput();++i) { if (op->getIn(i)->isZeroSize()) force_size(op->getIn(i),ConstTpl(ConstTpl::real,sizeof(uintb)),ops); } break; default: break; } } bool PcodeCompile::propagateSize(ConstructTpl *ct) { // Fill in size for varnodes with size 0 // Return first OpTpl with a size 0 varnode // that cannot be filled in or NULL otherwise vector zerovec,zerovec2; vector::const_iterator iter; int4 lastsize; for(iter=ct->getOpvec().begin();iter!=ct->getOpvec().end();++iter) if ((*iter)->isZeroSize()) { fillinZero(*iter,ct->getOpvec()); if ((*iter)->isZeroSize()) zerovec.push_back(*iter); } lastsize = zerovec.size() + 1; while( zerovec.size() < lastsize ) { lastsize = zerovec.size(); zerovec2.clear(); for(iter=zerovec.begin();iter!=zerovec.end();++iter) { fillinZero(*iter,ct->getOpvec()); if ((*iter)->isZeroSize()) zerovec2.push_back( *iter ); } zerovec = zerovec2; } if ( lastsize != 0 ) return false; return true; } VarnodeTpl *PcodeCompile::buildTemporary(void) { // Build temporary variable (with zerosize) VarnodeTpl *res = new VarnodeTpl(ConstTpl(uniqspace), ConstTpl(ConstTpl::real,allocateTemp()), ConstTpl(ConstTpl::real,0)); res->setUnnamed(true); return res; } LabelSymbol *PcodeCompile::defineLabel(string *name) { // Create a label symbol LabelSymbol *labsym = new LabelSymbol(*name,local_labelcount++); delete name; addSymbol(labsym); // Add symbol to local scope return labsym; } vector *PcodeCompile::placeLabel(LabelSymbol *labsym) { // Create placeholder OpTpl for a label if (labsym->isPlaced()) { reportError(getLocation(labsym), "Label '" + labsym->getName() + "' is placed more than once"); } labsym->setPlaced(); vector *res = new vector; OpTpl *op = new OpTpl(LABELBUILD); VarnodeTpl *idvn = new VarnodeTpl(ConstTpl(constantspace), ConstTpl(ConstTpl::real,labsym->getIndex()), ConstTpl(ConstTpl::real,4)); op->addInput(idvn); res->push_back(op); return res; } vector *PcodeCompile::newOutput(bool usesLocalKey,ExprTree *rhs,string *varname,uint4 size) { VarnodeSymbol *sym; VarnodeTpl *tmpvn = buildTemporary(); if (size != 0) tmpvn->setSize(ConstTpl(ConstTpl::real,size)); // Size was explicitly specified else if ((rhs->getSize().getType()==ConstTpl::real)&&(rhs->getSize().getReal()!=0)) tmpvn->setSize(rhs->getSize()); // Inherit size from unnamed expression result // Only inherit if the size is real, otherwise we // cannot build the VarnodeSymbol with a placeholder constant rhs->setOutput(tmpvn); sym = new VarnodeSymbol(*varname,tmpvn->getSpace().getSpace(),tmpvn->getOffset().getReal(),tmpvn->getSize().getReal()); // Create new symbol regardless addSymbol(sym); if ((!usesLocalKey) && enforceLocalKey) reportError(getLocation(sym), "Must use 'local' keyword to define symbol '"+*varname + "'"); delete varname; return ExprTree::toVector(rhs); } void PcodeCompile::newLocalDefinition(string *varname,uint4 size) { // Create a new temporary symbol (without generating any pcode) VarnodeSymbol *sym; VarnodeTpl *tmpvn = buildTemporary(); if (size != 0) tmpvn->setSize(ConstTpl(ConstTpl::real,size)); // Size was explicitly specified sym = new VarnodeSymbol(*varname,tmpvn->getSpace().getSpace(),tmpvn->getOffset().getReal(),tmpvn->getSize().getReal()); addSymbol(sym); delete varname; } ExprTree *PcodeCompile::createOp(OpCode opc,ExprTree *vn) { // Create new expression with output -outvn- // built by performing -opc- on input vn. // Free input expression VarnodeTpl *outvn = buildTemporary(); OpTpl *op = new OpTpl(opc); op->addInput(vn->outvn); op->setOutput(outvn); vn->ops->push_back(op); vn->outvn = new VarnodeTpl(*outvn); return vn; } ExprTree *PcodeCompile::createOp(OpCode opc,ExprTree *vn1, ExprTree *vn2) { // Create new expression with output -outvn- // built by performing -opc- on inputs vn1 and vn2. // Free input expressions VarnodeTpl *outvn = buildTemporary(); vn1->ops->insert(vn1->ops->end(),vn2->ops->begin(),vn2->ops->end()); vn2->ops->clear(); OpTpl *op = new OpTpl(opc); op->addInput(vn1->outvn); op->addInput(vn2->outvn); vn2->outvn = (VarnodeTpl *)0; op->setOutput(outvn); vn1->ops->push_back(op); vn1->outvn = new VarnodeTpl(*outvn); delete vn2; return vn1; } ExprTree *PcodeCompile::createOpOut(VarnodeTpl *outvn,OpCode opc, ExprTree *vn1,ExprTree *vn2) { // Create an op with explicit output and two inputs vn1->ops->insert(vn1->ops->end(),vn2->ops->begin(),vn2->ops->end()); vn2->ops->clear(); OpTpl *op = new OpTpl(opc); op->addInput(vn1->outvn); op->addInput(vn2->outvn); vn2->outvn = (VarnodeTpl *)0; op->setOutput(outvn); vn1->ops->push_back(op); vn1->outvn = new VarnodeTpl(*outvn); delete vn2; return vn1; } ExprTree *PcodeCompile::createOpOutUnary(VarnodeTpl *outvn,OpCode opc,ExprTree *vn) { // Create an op with explicit output and 1 input OpTpl *op = new OpTpl(opc); op->addInput(vn->outvn); op->setOutput(outvn); vn->ops->push_back(op); vn->outvn = new VarnodeTpl(*outvn); return vn; } vector *PcodeCompile::createOpNoOut(OpCode opc,ExprTree *vn) { // Create new expression by creating op with given -opc- // and single input vn. Free the input expression OpTpl *op = new OpTpl(opc); op->addInput(vn->outvn); vn->outvn = (VarnodeTpl *)0; // There is no longer an output to this expression vector *res = vn->ops; vn->ops = (vector *)0; delete vn; res->push_back(op); return res; } vector *PcodeCompile::createOpNoOut(OpCode opc,ExprTree *vn1,ExprTree *vn2) { // Create new expression by creating op with given -opc- // and inputs vn1 and vn2. Free the input expressions vector *res = vn1->ops; vn1->ops = (vector *)0; res->insert(res->end(),vn2->ops->begin(),vn2->ops->end()); vn2->ops->clear(); OpTpl *op = new OpTpl(opc); op->addInput(vn1->outvn); vn1->outvn = (VarnodeTpl *)0; op->addInput(vn2->outvn); vn2->outvn = (VarnodeTpl *)0; res->push_back(op); delete vn1; delete vn2; return res; } vector *PcodeCompile::createOpConst(OpCode opc,uintb val) { VarnodeTpl *vn = new VarnodeTpl(ConstTpl(constantspace), ConstTpl(ConstTpl::real,val), ConstTpl(ConstTpl::real,4)); vector *res = new vector; OpTpl *op = new OpTpl(opc); op->addInput(vn); res->push_back(op); return res; } ExprTree *PcodeCompile::createLoad(StarQuality *qual,ExprTree *ptr) { // Create new load expression, free ptr expression VarnodeTpl *outvn = buildTemporary(); OpTpl *op = new OpTpl(CPUI_LOAD); // The first varnode input to the load is a constant reference to the AddrSpace being loaded // from. Internally, we really store the pointer to the AddrSpace as the reference, but this // isn't platform independent. So officially, we assume that the constant reference will be the // AddrSpace index. We can safely assume this always has size 4. VarnodeTpl *spcvn = new VarnodeTpl(ConstTpl(constantspace), qual->id, ConstTpl(ConstTpl::real,8)); op->addInput(spcvn); op->addInput(ptr->outvn); op->setOutput(outvn); ptr->ops->push_back(op); if (qual->size > 0) force_size(outvn,ConstTpl(ConstTpl::real,qual->size),*ptr->ops); ptr->outvn = new VarnodeTpl(*outvn); delete qual; return ptr; } vector *PcodeCompile::createStore(StarQuality *qual, ExprTree *ptr,ExprTree *val) { vector *res = ptr->ops; ptr->ops = (vector *)0; res->insert(res->end(),val->ops->begin(),val->ops->end()); val->ops->clear(); OpTpl *op = new OpTpl(CPUI_STORE); // The first varnode input to the store is a constant reference to the AddrSpace being loaded // from. Internally, we really store the pointer to the AddrSpace as the reference, but this // isn't platform independent. So officially, we assume that the constant reference will be the // AddrSpace index. We can safely assume this always has size 4. VarnodeTpl *spcvn = new VarnodeTpl(ConstTpl(constantspace), qual->id, ConstTpl(ConstTpl::real,8)); op->addInput(spcvn); op->addInput(ptr->outvn); op->addInput(val->outvn); res->push_back(op); force_size(val->outvn,ConstTpl(ConstTpl::real,qual->size),*res); ptr->outvn = (VarnodeTpl *)0; val->outvn = (VarnodeTpl *)0; delete ptr; delete val; delete qual; return res; } ExprTree *PcodeCompile::createUserOp(UserOpSymbol *sym,vector *param) { // Create userdefined pcode op, given symbol and parameters VarnodeTpl *outvn = buildTemporary(); ExprTree *res = new ExprTree(); res->ops = createUserOpNoOut(sym,param); res->ops->back()->setOutput(outvn); res->outvn = new VarnodeTpl(*outvn); return res; } vector *PcodeCompile::createUserOpNoOut(UserOpSymbol *sym,vector *param) { OpTpl *op = new OpTpl(CPUI_CALLOTHER); VarnodeTpl *vn = new VarnodeTpl(ConstTpl(constantspace), ConstTpl(ConstTpl::real,sym->getIndex()), ConstTpl(ConstTpl::real,4)); op->addInput(vn); return ExprTree::appendParams(op,param); } ExprTree *PcodeCompile::createVariadic(OpCode opc,vector *param) { VarnodeTpl *outvn = buildTemporary(); ExprTree *res = new ExprTree(); OpTpl *op = new OpTpl(opc); res->ops = ExprTree::appendParams(op,param); res->ops->back()->setOutput(outvn); res->outvn = new VarnodeTpl(*outvn); return res; } void PcodeCompile::appendOp(OpCode opc,ExprTree *res,uintb constval,int4 constsz) { // Take output of res expression, combine with constant, // using opc operation, return the resulting expression OpTpl *op = new OpTpl(opc); VarnodeTpl *constvn = new VarnodeTpl(ConstTpl(constantspace), ConstTpl(ConstTpl::real,constval), ConstTpl(ConstTpl::real,constsz)); VarnodeTpl *outvn = buildTemporary(); op->addInput(res->outvn); op->addInput(constvn); op->setOutput(outvn); res->ops->push_back(op); res->outvn = new VarnodeTpl(*outvn); } VarnodeTpl *PcodeCompile::buildTruncatedVarnode(VarnodeTpl *basevn,uint4 bitoffset,uint4 numbits) { // Build a truncated form -basevn- that matches the bitrange [ -bitoffset-, -numbits- ] if possible // using just ConstTpl mechanics, otherwise return null uint4 byteoffset = bitoffset / 8; // Convert to byte units uint4 numbytes = numbits / 8; uintb fullsz = 0; if (basevn->getSize().getType() == ConstTpl::real) { // If we know the size of base, make sure the bit range is in bounds fullsz = basevn->getSize().getReal(); if (fullsz == 0) return (VarnodeTpl *)0; if (byteoffset + numbytes > fullsz) throw SleighError("Requested bit range out of bounds"); } if ((bitoffset % 8) != 0) return (VarnodeTpl *)0; if ((numbits % 8) != 0) return (VarnodeTpl *)0; if (basevn->getSpace().isUniqueSpace()) // Do we really want to prevent truncated uniques?? return (VarnodeTpl *)0; ConstTpl::const_type offset_type = basevn->getOffset().getType(); if ((offset_type != ConstTpl::real)&&(offset_type != ConstTpl::handle)) return (VarnodeTpl *)0; ConstTpl specialoff; if (offset_type == ConstTpl::handle) { // We put in the correct adjustment to offset assuming things are little endian // We defer the correct big endian calculation until after the consistency check // because we need to know the subtable export sizes specialoff = ConstTpl(ConstTpl::handle,basevn->getOffset().getHandleIndex(), ConstTpl::v_offset_plus,byteoffset); } else { if (basevn->getSize().getType() != ConstTpl::real) throw SleighError("Could not construct requested bit range"); uintb plus; if (defaultspace->isBigEndian()) plus = fullsz - (byteoffset + numbytes); else plus = byteoffset; specialoff = ConstTpl(ConstTpl::real,basevn->getOffset().getReal() + plus); } VarnodeTpl *res = new VarnodeTpl(basevn->getSpace(),specialoff,ConstTpl(ConstTpl::real,numbytes)); return res; } vector *PcodeCompile::assignBitRange(VarnodeTpl *vn,uint4 bitoffset,uint4 numbits,ExprTree *rhs) { // Create an expression assigning the rhs to a bitrange within sym string errmsg; if (numbits == 0) errmsg = "Size of bitrange is zero"; uint4 smallsize = (numbits+7)/8; // Size of input (output of rhs) bool shiftneeded = (bitoffset != 0); bool zextneeded = true; uintb mask = (uintb)2; mask = ~(((mask<<(numbits-1))-1) << bitoffset); if (vn->getSize().getType()==ConstTpl::real) { // If we know the size of the bitranged varnode, we can // do some immediate checks, and possibly simplify things uint4 symsize = vn->getSize().getReal(); if (symsize > 0) zextneeded = (symsize > smallsize); symsize *= 8; // Convert to number of bits if ((bitoffset>=symsize)||(bitoffset+numbits>symsize)) errmsg = "Assigned bitrange is bad"; else if ((bitoffset==0)&&(numbits==symsize)) errmsg = "Assigning to bitrange is superfluous"; } if (errmsg.size()>0) { // Was there an error condition reportError((const Location *)0, errmsg); // Report the error delete vn; // Clean up vector *resops = rhs->ops; // Passthru old expression rhs->ops = (vector *)0; delete rhs; return resops; } // We know what the size of the input has to be force_size(rhs->outvn,ConstTpl(ConstTpl::real,smallsize),*rhs->ops); ExprTree *res; VarnodeTpl *finalout = buildTruncatedVarnode(vn,bitoffset,numbits); if (finalout != (VarnodeTpl *)0) { delete vn; // Don't keep the original Varnode object res = createOpOutUnary(finalout,CPUI_COPY,rhs); } else { if (bitoffset + numbits > 64) errmsg = "Assigned bitrange extends past first 64 bits"; res = new ExprTree(vn); appendOp(CPUI_INT_AND,res,mask,0); if (zextneeded) createOp(CPUI_INT_ZEXT,rhs); if (shiftneeded) appendOp(CPUI_INT_LEFT,rhs,bitoffset,4); finalout = new VarnodeTpl(*vn); res = createOpOut(finalout,CPUI_INT_OR,res,rhs); } if (errmsg.size() > 0) reportError((const Location *)0, errmsg); vector *resops = res->ops; res->ops = (vector *)0; delete res; return resops; } ExprTree *PcodeCompile::createBitRange(SpecificSymbol *sym,uint4 bitoffset,uint4 numbits) { // Create an expression computing the indicated bitrange of sym // The result is truncated to the smallest byte size that can // contain the indicated number of bits. The result has the // desired bits shifted all the way to the right string errmsg; if (numbits == 0) errmsg = "Size of bitrange is zero"; VarnodeTpl *vn = sym->getVarnode(); uint4 finalsize = (numbits+7)/8; // Round up to neareast byte size uint4 truncshift = 0; bool maskneeded = ((numbits%8)!=0); bool truncneeded = true; // Special case where we can set the size, without invoking // a truncation operator if ((errmsg.size()==0)&&(bitoffset==0)&&(!maskneeded)) { if ((vn->getSpace().getType()==ConstTpl::handle)&&vn->isZeroSize()) { vn->setSize(ConstTpl(ConstTpl::real,finalsize)); ExprTree *res = new ExprTree(vn); // VarnodeTpl *cruft = buildTemporary(); // delete cruft; return res; } } if (errmsg.size()==0) { VarnodeTpl *truncvn = buildTruncatedVarnode(vn,bitoffset,numbits); if (truncvn != (VarnodeTpl *)0) { // If we are able to construct a simple truncated varnode ExprTree *res = new ExprTree(truncvn); // Return just the varnode as an expression delete vn; return res; } } if (vn->getSize().getType()==ConstTpl::real) { // If we know the size of the input varnode, we can // do some immediate checks, and possibly simplify things uint4 insize = vn->getSize().getReal(); if (insize > 0) { truncneeded = (finalsize < insize); insize *= 8; // Convert to number of bits if ((bitoffset >= insize)||(bitoffset+numbits > insize)) errmsg = "Bitrange is bad"; if (maskneeded && ((bitoffset+numbits)==insize)) maskneeded = false; } } uintb mask = (uintb)2; mask = ((mask<<(numbits-1))-1); if (truncneeded && ((bitoffset % 8)==0)) { truncshift = bitoffset/8; bitoffset = 0; } if ((bitoffset==0)&&(!truncneeded)&&(!maskneeded)) errmsg = "Superfluous bitrange"; if (maskneeded && (finalsize > 8)) errmsg = "Illegal masked bitrange producing varnode larger than 64 bits: " + sym->getName(); ExprTree *res = new ExprTree(vn); if (errmsg.size()>0) { // Check for error condition reportError(getLocation(sym), errmsg); return res; } if (bitoffset !=0) appendOp(CPUI_INT_RIGHT,res,bitoffset,4); if (truncneeded) appendOp(CPUI_SUBPIECE,res,truncshift,4); if (maskneeded) appendOp(CPUI_INT_AND,res,mask,finalsize); force_size(res->outvn,ConstTpl(ConstTpl::real,finalsize),*res->ops); return res; } VarnodeTpl *PcodeCompile::addressOf(VarnodeTpl *var,uint4 size) { // Produce constant varnode that is the offset // portion of varnode -var- if (size==0) { // If no size specified if (var->getSpace().getType() == ConstTpl::spaceid) { AddrSpace *spc = var->getSpace().getSpace(); // Look to the particular space size = spc->getAddrSize(); // to see if it has a standard address size } } VarnodeTpl *res; if ((var->getOffset().getType() == ConstTpl::real)&&(var->getSpace().getType() == ConstTpl::spaceid)) { AddrSpace *spc = var->getSpace().getSpace(); uintb off = AddrSpace::byteToAddress(var->getOffset().getReal(),spc->getWordSize()); res = new VarnodeTpl(ConstTpl(constantspace), ConstTpl(ConstTpl::real,off), ConstTpl(ConstTpl::real,size)); } else res = new VarnodeTpl(ConstTpl(constantspace),var->getOffset(),ConstTpl(ConstTpl::real,size)); delete var; return res; }