GP-2470 Support for partial enums

This commit is contained in:
caheckman 2024-11-01 15:54:39 +00:00
parent d5f4d3b9bc
commit 55a026b3ba
21 changed files with 1176 additions and 706 deletions

View File

@ -25,6 +25,7 @@ src/decompile/datatests/divopt.xml||GHIDRA||||END|
src/decompile/datatests/doublemove.xml||GHIDRA||||END|
src/decompile/datatests/dupptr.xml||GHIDRA||||END|
src/decompile/datatests/elseif.xml||GHIDRA||||END|
src/decompile/datatests/enum.xml||GHIDRA||||END|
src/decompile/datatests/floatcast.xml||GHIDRA||||END|
src/decompile/datatests/floatconv.xml||GHIDRA||||END|
src/decompile/datatests/floatprint.xml||GHIDRA||||END|

View File

@ -5600,6 +5600,7 @@ void ActionDatabase::universalAction(Architecture *conf)
actcleanup->addRule( new Rule2Comp2Sub("cleanup") );
actcleanup->addRule( new RuleSubRight("cleanup") );
actcleanup->addRule( new RuleFloatSignCleanup("cleanup") );
actcleanup->addRule( new RuleExpandLoad("cleanup") );
actcleanup->addRule( new RulePtrsubCharConstant("cleanup") );
actcleanup->addRule( new RuleExtensionPush("cleanup") );
actcleanup->addRule( new RulePieceStructure("cleanup") );

View File

@ -3112,7 +3112,7 @@ int grammarerror(const char *str)
Datatype *parse_type(istream &s,string &name,Architecture *glb)
{
CParse parser(glb,1000);
CParse parser(glb,4096);
if (!parser.parseStream(s,CParse::doc_parameter_declaration))
throw ParseError(parser.getError());
@ -3131,7 +3131,7 @@ Datatype *parse_type(istream &s,string &name,Architecture *glb)
void parse_protopieces(PrototypePieces &pieces,
istream &s,Architecture *glb)
{
CParse parser(glb,1000);
CParse parser(glb,4096);
if (!parser.parseStream(s,CParse::doc_declaration))
throw ParseError(parser.getError());
@ -3151,7 +3151,7 @@ void parse_protopieces(PrototypePieces &pieces,
void parse_C(Architecture *glb,istream &s)
{ // Load type data straight into datastructures
CParse parser(glb,1000);
CParse parser(glb,4096);
if (!parser.parseStream(s,CParse::doc_declaration))
throw ParseError(parser.getError());

View File

@ -1366,7 +1366,7 @@ int grammarerror(const char *str)
Datatype *parse_type(istream &s,string &name,Architecture *glb)
{
CParse parser(glb,1000);
CParse parser(glb,4096);
if (!parser.parseStream(s,CParse::doc_parameter_declaration))
throw ParseError(parser.getError());
@ -1385,7 +1385,7 @@ Datatype *parse_type(istream &s,string &name,Architecture *glb)
void parse_protopieces(PrototypePieces &pieces,
istream &s,Architecture *glb)
{
CParse parser(glb,1000);
CParse parser(glb,4096);
if (!parser.parseStream(s,CParse::doc_declaration))
throw ParseError(parser.getError());
@ -1405,7 +1405,7 @@ void parse_protopieces(PrototypePieces &pieces,
void parse_C(Architecture *glb,istream &s)
{ // Load type data straight into datastructures
CParse parser(glb,1000);
CParse parser(glb,4096);
if (!parser.parseStream(s,CParse::doc_declaration))
throw ParseError(parser.getError());

View File

@ -959,7 +959,7 @@ void PrintC::opPtrsub(const PcodeOp *op)
if (ct->getMetatype() == TYPE_STRUCT || ct->getMetatype() == TYPE_UNION) {
int8 suboff = (int4)in1const; // How far into container
if (ptrel != (TypePointerRel *)0) {
suboff += ptrel->getPointerOffset();
suboff += ptrel->getAddressOffset();
suboff &= calc_mask(ptype->getSize());
if (suboff == 0) {
// Special case where we do not print a field
@ -1666,22 +1666,23 @@ void PrintC::pushCharConstant(uintb val,const Datatype *ct,tagtype tag,const Var
void PrintC::pushEnumConstant(uintb val,const TypeEnum *ct,tagtype tag,
const Varnode *vn,const PcodeOp *op)
{
vector<string> valnames;
TypeEnum::Representation rep;
bool complement = ct->getMatches(val,valnames);
if (valnames.size() > 0) {
if (complement)
ct->getMatches(val,rep);
if (rep.matchname.size() > 0) {
if (rep.shiftAmount != 0)
pushOp(&shift_right,op);
if (rep.complement)
pushOp(&bitwise_not,op);
for(int4 i=valnames.size()-1;i>0;--i)
for(int4 i=rep.matchname.size()-1;i>0;--i)
pushOp(&enum_cat,op);
for(int4 i=0;i<valnames.size();++i)
pushAtom(Atom(valnames[i],tag,EmitMarkup::const_color,op,vn,val));
for(int4 i=0;i<rep.matchname.size();++i)
pushAtom(Atom(rep.matchname[i],tag,EmitMarkup::const_color,op,vn,val));
if (rep.shiftAmount != 0)
push_integer(rep.shiftAmount,4,false,tag,vn,op);
}
else {
push_integer(val,ct->getSize(),false,tag,vn,op);
// ostringstream s;
// s << "BAD_ENUM(0x" << hex << val << ")";
// pushAtom(Atom(s.str(),vartoken,EmitMarkup::const_color,op,vn));
}
}
@ -1793,8 +1794,11 @@ void PrintC::pushConstant(uintb val,const Datatype *ct,tagtype tag,
case TYPE_SPACEBASE:
case TYPE_CODE:
case TYPE_ARRAY:
case TYPE_ENUM_INT:
case TYPE_ENUM_UINT:
case TYPE_STRUCT:
case TYPE_UNION:
case TYPE_PARTIALENUM:
case TYPE_PARTIALSTRUCT:
case TYPE_PARTIALUNION:
break;

View File

@ -15,7 +15,6 @@
*/
#include "ruleaction.hh"
#include "coreaction.hh"
#include "subflow.hh"
#include "rangeutil.hh"
#include "multiprecision.hh"
@ -5679,7 +5678,7 @@ void AddTreeState::clear(void)
nonmultsum = 0;
biggestNonMultCoeff = 0;
if (pRelType != (const TypePointerRel *)0) {
nonmultsum = ((TypePointerRel *)ct)->getPointerOffset();
nonmultsum = ((TypePointerRel *)ct)->getAddressOffset();
nonmultsum &= ptrmask;
}
multiple.clear();
@ -5733,7 +5732,7 @@ AddTreeState::AddTreeState(Funcdata &d,PcodeOp *op,int4 slot)
if (ct->isFormalPointerRel()) {
pRelType = (const TypePointerRel *)ct;
baseType = pRelType->getParent();
nonmultsum = pRelType->getPointerOffset();
nonmultsum = pRelType->getAddressOffset();
nonmultsum &= ptrmask;
}
if (baseType->isVariableLength())
@ -6012,7 +6011,7 @@ void AddTreeState::calcSubtype(void)
extra = AddrSpace::byteToAddressInt(extra, ct->getWordSize()); // Convert back to address units
offset = (offset - extra) & ptrmask;
correct = (correct - extra) & ptrmask;
if (pRelType != (TypePointerRel *)0 && offset == pRelType->getPointerOffset()) {
if (pRelType != (TypePointerRel *)0 && offset == pRelType->getAddressOffset()) {
// offset falls within basic ptrto
if (!pRelType->evaluateThruParent(0)) { // If we are not representing offset 0 through parent
valid = false; // Use basic (alternate) form
@ -6031,7 +6030,7 @@ void AddTreeState::calcSubtype(void)
valid = false; // There is substructure we don't know about
}
if (pRelType != (const TypePointerRel *)0) {
int4 ptrOff = ((TypePointerRel *)ct)->getPointerOffset();
int4 ptrOff = ((TypePointerRel *)ct)->getAddressOffset();
offset = (offset - ptrOff) & ptrmask;
correct = (correct - ptrOff) & ptrmask;
}
@ -6398,8 +6397,7 @@ int4 RuleStructOffset0::applyOp(PcodeOp *op,Funcdata &data)
baseType = ptRel->getParent();
if (baseType->getMetatype() != TYPE_STRUCT)
return 0;
int8 iOff = ptRel->getPointerOffset();
iOff = AddrSpace::addressToByteInt(iOff, ptRel->getWordSize());
int8 iOff = ptRel->getByteOffset();
if (iOff >= baseType->getSize())
return 0;
offset = iOff;
@ -6864,7 +6862,6 @@ int4 RuleAddUnsigned::applyOp(PcodeOp *op,Funcdata &data)
Datatype *dt = constvn->getTypeReadFacing(op);
if (dt->getMetatype() != TYPE_UINT) return 0;
if (dt->isCharPrint()) return 0; // Only change integer forms
if (dt->isEnumType()) return 0;
uintb val = constvn->getOffset();
uintb mask = calc_mask(constvn->getSize());
int4 sa = constvn->getSize() * 6; // 1/4 less than full bitsize
@ -6877,8 +6874,14 @@ int4 RuleAddUnsigned::applyOp(PcodeOp *op,Funcdata &data)
return 0; // Dont transform a named equate
}
}
uintb negatedVal = (-val) & mask;
if (dt->isEnumType()) {
TypeEnum *enumType = (TypeEnum *)dt;
if (!enumType->hasNamedValue(negatedVal) && enumType->hasNamedValue((~val)&mask))
return 0;
}
data.opSetOpcode(op,CPUI_INT_SUB);
Varnode *cvn = data.newConstant(constvn->getSize(), (-val) & mask);
Varnode *cvn = data.newConstant(constvn->getSize(), negatedVal);
cvn->copySymbol(constvn);
data.opSetInput(op,cvn,1);
return 1;
@ -7369,86 +7372,6 @@ int4 RulePieceStructure::applyOp(PcodeOp *op,Funcdata &data)
return 1;
}
/// \class RuleSplitCopy
/// \brief Split COPY ops based on TypePartialStruct
///
/// If more than one logical component of a structure or array is copied at once,
/// rewrite the COPY operator as multiple COPYs.
void RuleSplitCopy::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_COPY);
}
int4 RuleSplitCopy::applyOp(PcodeOp *op,Funcdata &data)
{
Datatype *inType = op->getIn(0)->getTypeReadFacing(op);
Datatype *outType = op->getOut()->getTypeDefFacing();
type_metatype metain = inType->getMetatype();
type_metatype metaout = outType->getMetatype();
if (metain != TYPE_PARTIALSTRUCT && metaout != TYPE_PARTIALSTRUCT &&
metain != TYPE_ARRAY && metaout != TYPE_ARRAY &&
metain != TYPE_STRUCT && metaout != TYPE_STRUCT)
return false;
SplitDatatype splitter(data);
if (splitter.splitCopy(op, inType, outType))
return 1;
return 0;
}
/// \class RuleSplitLoad
/// \brief Split LOAD ops based on TypePartialStruct
///
/// If more than one logical component of a structure or array is loaded at once,
/// rewrite the LOAD operator as multiple LOADs.
void RuleSplitLoad::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_LOAD);
}
int4 RuleSplitLoad::applyOp(PcodeOp *op,Funcdata &data)
{
Datatype *inType = SplitDatatype::getValueDatatype(op, op->getOut()->getSize(), data.getArch()->types);
if (inType == (Datatype *)0)
return 0;
type_metatype metain = inType->getMetatype();
if (metain != TYPE_STRUCT && metain != TYPE_ARRAY && metain != TYPE_PARTIALSTRUCT)
return 0;
SplitDatatype splitter(data);
if (splitter.splitLoad(op, inType))
return 1;
return 0;
}
/// \class RuleSplitStore
/// \brief Split STORE ops based on TypePartialStruct
///
/// If more than one logical component of a structure or array is stored at once,
/// rewrite the STORE operator as multiple STOREs.
void RuleSplitStore::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_STORE);
}
int4 RuleSplitStore::applyOp(PcodeOp *op,Funcdata &data)
{
Datatype *outType = SplitDatatype::getValueDatatype(op, op->getIn(2)->getSize(), data.getArch()->types);
if (outType == (Datatype *)0)
return 0;
type_metatype metain = outType->getMetatype();
if (metain != TYPE_STRUCT && metain != TYPE_ARRAY && metain != TYPE_PARTIALSTRUCT)
return 0;
SplitDatatype splitter(data);
if (splitter.splitStore(op, outType))
return 1;
return 0;
}
/// \class RuleSubNormal
/// \brief Pull-back SUBPIECE through INT_RIGHT and INT_SRIGHT
///
@ -8779,138 +8702,6 @@ int4 RuleSegment::applyOp(PcodeOp *op,Funcdata &data)
return 0;
}
/// \class RuleSubvarAnd
/// \brief Perform SubVariableFlow analysis triggered by INT_AND
void RuleSubvarAnd::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_AND);
}
int4 RuleSubvarAnd::applyOp(PcodeOp *op,Funcdata &data)
{
if (!op->getIn(1)->isConstant()) return 0;
Varnode *vn = op->getIn(0);
Varnode *outvn = op->getOut();
// if (vn->getSize() != 1) return 0; // Only for bitsize variables
if (outvn->getConsume() != op->getIn(1)->getOffset()) return 0;
if ((outvn->getConsume() & 1)==0) return 0;
uintb cmask;
if (outvn->getConsume() == (uintb)1)
cmask = (uintb)1;
else {
cmask = calc_mask(vn->getSize());
cmask >>=8;
while(cmask != 0) {
if (cmask == outvn->getConsume()) break;
cmask >>=8;
}
}
if (cmask == 0) return 0;
// if (vn->getConsume() == 0) return 0;
// if ((vn->getConsume() & 0xff)==0xff) return 0;
// if (op->getIn(1)->getOffset() != (uintb)1) return 0;
if (op->getOut()->hasNoDescend()) return 0;
SubvariableFlow subflow(&data,vn,cmask,false,false,false);
if (!subflow.doTrace()) return 0;
subflow.doReplacement();
return 1;
}
/// \class RuleSubvarSubpiece
/// \brief Perform SubVariableFlow analysis triggered by SUBPIECE
void RuleSubvarSubpiece::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_SUBPIECE);
}
int4 RuleSubvarSubpiece::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vn = op->getIn(0);
Varnode *outvn = op->getOut();
int4 flowsize = outvn->getSize();
uintb mask = calc_mask( flowsize );
mask <<= 8*((int4)op->getIn(1)->getOffset());
bool aggressive = outvn->isPtrFlow();
if (!aggressive) {
if ((vn->getConsume() & mask) != vn->getConsume()) return 0;
if (op->getOut()->hasNoDescend()) return 0;
}
bool big = false;
if (flowsize >= 8 && vn->isInput()) {
// Vector register inputs getting truncated to what actually gets used
// happens occasionally. We let SubvariableFlow deal with this special case
// to avoid overlapping inputs
// TODO: ActionLaneDivide should be handling this
if (vn->loneDescend() == op)
big = true;
}
SubvariableFlow subflow(&data,vn,mask,aggressive,false,big);
if (!subflow.doTrace()) return 0;
subflow.doReplacement();
return 1;
}
/// \class RuleSplitFlow
/// \brief Try to detect and split artificially joined Varnodes
///
/// Look for SUBPIECE coming from a PIECE that has come through INDIRECTs and/or MULTIEQUAL
/// Then: check if the input to SUBPIECE can be viewed as two independent pieces
/// If so: split the pieces into independent data-flows
void RuleSplitFlow::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_SUBPIECE);
}
int4 RuleSplitFlow::applyOp(PcodeOp *op,Funcdata &data)
{
int4 loSize = (int4)op->getIn(1)->getOffset();
if (loSize == 0) // Make sure SUBPIECE doesn't take least significant part
return 0;
Varnode *vn = op->getIn(0);
if (!vn->isWritten())
return 0;
if (vn->isPrecisLo() || vn->isPrecisHi())
return 0;
if (op->getOut()->getSize() + loSize != vn->getSize())
return 0; // Make sure SUBPIECE is taking most significant part
PcodeOp *concatOp = (PcodeOp *)0;
PcodeOp *multiOp = vn->getDef();
while(multiOp->code() == CPUI_INDIRECT) { // PIECE may come through INDIRECT
Varnode *tmpvn = multiOp->getIn(0);
if (!tmpvn->isWritten()) return 0;
multiOp = tmpvn->getDef();
}
if (multiOp->code() == CPUI_PIECE) {
if (vn->getDef() != multiOp)
concatOp = multiOp;
}
else if (multiOp->code() == CPUI_MULTIEQUAL) { // Otherwise PIECE comes through MULTIEQUAL
for(int4 i=0;i<multiOp->numInput();++i) {
Varnode *invn = multiOp->getIn(i);
if (!invn->isWritten()) continue;
PcodeOp *tmpOp = invn->getDef();
if (tmpOp->code() == CPUI_PIECE) {
concatOp = tmpOp;
break;
}
}
}
if (concatOp == (PcodeOp *)0) // Didn't find the concatenate
return 0;
if (concatOp->getIn(1)->getSize() != loSize)
return 0;
SplitFlow splitFlow(&data,vn,loSize);
if (!splitFlow.doTrace()) return 0;
splitFlow.apply();
return 1;
}
/// \class RulePtrFlow
/// \brief Mark Varnode and PcodeOp objects that are carrying or operating on pointers
///
@ -9111,178 +8902,6 @@ int4 RulePtrFlow::applyOp(PcodeOp *op,Funcdata &data)
return madeChange;
}
/// \class RuleSubvarCompZero
/// \brief Perform SubvariableFlow analysis triggered by testing of a single bit
///
/// Given a comparison (INT_EQUAL or INT_NOTEEQUAL_ to a constant,
/// check that input has only 1 bit that can possibly be non-zero
/// and that the constant is testing this. This then triggers
/// the full SubvariableFlow analysis.
void RuleSubvarCompZero::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_NOTEQUAL);
oplist.push_back(CPUI_INT_EQUAL);
}
int4 RuleSubvarCompZero::applyOp(PcodeOp *op,Funcdata &data)
{
if (!op->getIn(1)->isConstant()) return 0;
Varnode *vn = op->getIn(0);
uintb mask = vn->getNZMask();
int4 bitnum = leastsigbit_set(mask);
if (bitnum == -1) return 0;
if ((mask >> bitnum) != 1) return 0; // Check if only one bit active
// Check if the active bit is getting tested
if ((op->getIn(1)->getOffset()!=mask)&&
(op->getIn(1)->getOffset()!=0))
return 0;
if (op->getOut()->hasNoDescend()) return 0;
// We do a basic check that the stream from which it looks like
// the bit is getting pulled is not fully consumed
if (vn->isWritten()) {
PcodeOp *andop = vn->getDef();
if (andop->numInput()==0) return 0;
Varnode *vn0 = andop->getIn(0);
switch(andop->code()) {
case CPUI_INT_AND:
case CPUI_INT_OR:
case CPUI_INT_RIGHT:
{
if (vn0->isConstant()) return 0;
uintb mask0 = vn0->getConsume() & vn0->getNZMask();
uintb wholemask = calc_mask(vn0->getSize()) & mask0;
// We really need a popcnt here
// We want: if the number of bits that are both consumed
// and not known to be zero are "big" then don't continue
// because it doesn't look like a few bits getting manipulated
// within a status register
if ((wholemask & 0xff)==0xff) return 0;
if ((wholemask & 0xff00)==0xff00) return 0;
}
break;
default:
break;
}
}
SubvariableFlow subflow(&data,vn,mask,false,false,false);
if (!subflow.doTrace()) {
return 0;
}
subflow.doReplacement();
return 1;
}
/// \class RuleSubvarShift
/// \brief Perform SubvariableFlow analysis triggered by INT_RIGHT
///
/// If the INT_RIGHT input has only 1 bit that can possibly be non-zero
/// and it is getting shifted into the least significant bit position,
/// trigger the full SubvariableFlow analysis.
void RuleSubvarShift::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_RIGHT);
}
int4 RuleSubvarShift::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vn = op->getIn(0);
if (vn->getSize() != 1) return 0;
if (!op->getIn(1)->isConstant()) return 0;
int4 sa = (int4)op->getIn(1)->getOffset();
uintb mask = vn->getNZMask();
if ((mask >> sa) != (uintb)1) return 0; // Pulling out a single bit
mask = (mask >> sa) << sa;
if (op->getOut()->hasNoDescend()) return 0;
SubvariableFlow subflow(&data,vn,mask,false,false,false);
if (!subflow.doTrace()) return 0;
subflow.doReplacement();
return 1;
}
/// \class RuleSubvarZext
/// \brief Perform SubvariableFlow analysis triggered by INT_ZEXT
void RuleSubvarZext::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_ZEXT);
}
int4 RuleSubvarZext::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vn = op->getOut();
Varnode *invn = op->getIn(0);
uintb mask = calc_mask(invn->getSize());
SubvariableFlow subflow(&data,vn,mask,invn->isPtrFlow(),false,false);
if (!subflow.doTrace()) return 0;
subflow.doReplacement();
return 1;
}
/// \class RuleSubvarSext
/// \brief Perform SubvariableFlow analysis triggered by INT_SEXT
void RuleSubvarSext::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_SEXT);
}
int4 RuleSubvarSext::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vn = op->getOut();
Varnode *invn = op->getIn(0);
uintb mask = calc_mask(invn->getSize());
SubvariableFlow subflow(&data,vn,mask,isaggressive,true,false);
if (!subflow.doTrace()) return 0;
subflow.doReplacement();
return 1;
}
void RuleSubvarSext::reset(Funcdata &data)
{
isaggressive = data.getArch()->aggressive_ext_trim;
}
/// \class RuleSubfloatConvert
/// \brief Perform SubfloatFlow analysis triggered by FLOAT_FLOAT2FLOAT
void RuleSubfloatConvert::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_FLOAT_FLOAT2FLOAT);
}
int4 RuleSubfloatConvert::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *invn = op->getIn(0);
Varnode *outvn = op->getOut();
int4 insize = invn->getSize();
int4 outsize = outvn->getSize();
if (outsize > insize) {
SubfloatFlow subflow(&data,outvn,insize);
if (!subflow.doTrace()) return 0;
subflow.apply();
}
else {
SubfloatFlow subflow(&data,invn,outsize);
if (!subflow.doTrace()) return 0;
subflow.apply();
}
return 1;
}
/// \class RuleNegateNegate
/// \brief Simplify INT_NEGATE chains: `~~V => V`
void RuleNegateNegate::getOpList(vector<uint4> &oplist) const
@ -10926,4 +10545,145 @@ int4 RuleOrCompare::applyOp(PcodeOp *op,Funcdata &data)
return 1;
}
/// \brief Check that all uses of given Varnode are of the form `(V & C) == D`
///
/// \param vn is the given Varnode
/// \return \b true if all uses match the INT_AND form
bool RuleExpandLoad::checkAndComparison(Varnode *vn)
{
list<PcodeOp *>::const_iterator iter;
for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) {
PcodeOp *op = *iter;
if (op->code() != CPUI_INT_AND) return false;
if (!op->getIn(1)->isConstant()) return false;
PcodeOp *compOp = op->getOut()->loneDescend();
if (compOp == (PcodeOp *)0) return false;
OpCode opc = compOp->code();
if (opc != CPUI_INT_EQUAL && opc != CPUI_INT_NOTEQUAL) return false;
if (!compOp->getIn(1)->isConstant()) return false;
}
return true;
}
/// \brief Expand the constants in the previously scanned forms: `(V & C) == D`
///
/// The method checkAndComparison() must have returned \b true for \b oldVn. Change the size and
/// data-type of all the constants in these expressions.
/// \param data is the function containing the expressions
/// \param oldVn is incoming variable in all the expressions
/// \param newVn is the new bigger variable
/// \param dt is the data-type to associate with the constants
/// \param offset is the number of least significant (zero) bytes to add to each constant
void RuleExpandLoad::modifyAndComparison(Funcdata &data,Varnode *oldVn,Varnode *newVn,Datatype *dt,int4 offset)
{
offset = 8*offset; // Convert to shift amount
list<PcodeOp *>::const_iterator iter = oldVn->beginDescend();
while(iter != oldVn->endDescend()) {
PcodeOp *andOp = *iter;
++iter; // Advance iterator before modifying op
PcodeOp *compOp = andOp->getOut()->loneDescend();
uintb newOff = andOp->getIn(1)->getOffset();
newOff <<= offset;
Varnode *vn = data.newConstant(dt->getSize(), newOff);
vn->updateType(dt, false, false);
data.opSetInput(andOp, newVn, 0);
data.opSetInput(andOp, vn, 1);
newOff = compOp->getIn(1)->getOffset();
newOff <<= offset;
vn = data.newConstant(dt->getSize(), newOff);
vn->updateType(dt, false, false);
data.opSetInput(compOp,vn,1);
}
}
/// \class RuleExpandLoad
/// \brief Convert LOAD size to match pointer data-type
///
/// Change LOAD output to a larger size if used for INT_AND comparisons or if a truncation is natural
void RuleExpandLoad::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_LOAD);
}
int4 RuleExpandLoad::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *outVn = op->getOut();
int4 outSize = outVn->getSize();
Varnode *rootPtr = op->getIn(1);
PcodeOp *addOp = (PcodeOp *)0;
int4 offset = 0;
Datatype *elType;
if (rootPtr->isWritten()) {
PcodeOp *defOp = rootPtr->getDef();
if (defOp->code() == CPUI_INT_ADD && defOp->getIn(1)->isConstant()) {
addOp = defOp;
rootPtr = defOp->getIn(0);
offset = defOp->getIn(1)->getOffset();
if (offset > 16) return 0; // INT_ADD offset must be small
if (defOp->getOut()->loneDescend() == (PcodeOp *)0) return 0; // INT_ADD must be used only once
elType = rootPtr->getTypeReadFacing(defOp);
}
else
elType = rootPtr->getTypeReadFacing(op);
}
else
elType = rootPtr->getTypeReadFacing(op);
if (elType->getMetatype() != TYPE_PTR) return 0;
elType = ((TypePointer *)elType)->getPtrTo();
if (elType->getSize() <= outSize) return 0; // Pointer data-type must be bigger than LOAD
if (elType->getSize() < outSize + offset) return 0;
type_metatype meta = elType->getMetatype();
if (meta == TYPE_UNKNOWN) return 0;
bool addForm = checkAndComparison(outVn);
AddrSpace *spc = op->getIn(0)->getSpaceFromConst();
int4 lsbCut = 0;
if (addForm) {
if (spc->isBigEndian()) {
lsbCut = elType->getSize() - outSize - offset;
}
else
lsbCut = offset;
}
else {
// Check for natural integer truncation
if (meta != TYPE_INT && meta != TYPE_UINT) return 0;
type_metatype outMeta = outVn->getTypeDefFacing()->getMetatype();
if (outMeta != TYPE_INT && outMeta != TYPE_UINT && outMeta != TYPE_UNKNOWN && outMeta != TYPE_BOOL)
return false;
// Check that LOAD is grabbing least significant bytes
if (spc->isBigEndian()) {
if (outSize + offset != elType->getSize()) return 0;
}
else {
if (offset != 0) return 0;
}
}
// Modify the LOAD
Varnode *newOut = data.newUnique(elType->getSize(), elType);
data.opSetOutput(op, newOut);
if (addOp != (PcodeOp *)0) {
data.opSetInput(op, rootPtr, 1);
data.opDestroy(addOp);
}
if (addForm) {
if (meta != TYPE_INT && meta != TYPE_UINT)
elType = data.getArch()->types->getBase(elType->getSize(), TYPE_UINT);
modifyAndComparison(data, outVn, newOut, elType, lsbCut);
}
else {
PcodeOp *subOp = data.newOp(2,op->getAddr());
data.opSetOpcode(subOp, CPUI_SUBPIECE);
data.opSetInput(subOp,newOut,0); // Truncate new bigger LOAD output
data.opSetInput(subOp, data.newConstant(4, 0), 1);
data.opSetOutput(subOp, outVn); // Original LOAD output is now defined by SUBPIECE
data.opInsertAfter(subOp, op);
}
return 1;
}
} // End namespace ghidra

View File

@ -1181,39 +1181,6 @@ public:
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RuleSplitCopy : public Rule {
public:
RuleSplitCopy(const string &g) : Rule( g, 0, "splitcopy") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSplitCopy(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RuleSplitLoad : public Rule {
public:
RuleSplitLoad(const string &g) : Rule( g, 0, "splitload") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSplitLoad(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RuleSplitStore : public Rule {
public:
RuleSplitStore(const string &g) : Rule( g, 0, "splitstore") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSplitStore(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RuleSubNormal : public Rule {
public:
RuleSubNormal(const string &g) : Rule( g, 0, "subnormal") {} ///< Constructor
@ -1398,39 +1365,6 @@ public:
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RuleSubvarAnd : public Rule {
public:
RuleSubvarAnd(const string &g) : Rule( g, 0, "subvar_and") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSubvarAnd(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RuleSubvarSubpiece : public Rule {
public:
RuleSubvarSubpiece(const string &g) : Rule( g, 0, "subvar_subpiece") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSubvarSubpiece(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RuleSplitFlow : public Rule {
public:
RuleSplitFlow(const string &g) : Rule( g, 0, "splitflow") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSplitFlow(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RulePtrFlow : public Rule {
Architecture *glb; ///< The address space manager
bool hasTruncations; ///< \b true if this architecture needs truncated pointers
@ -1448,63 +1382,6 @@ public:
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RuleSubvarCompZero : public Rule {
public:
RuleSubvarCompZero(const string &g) : Rule( g, 0, "subvar_compzero") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSubvarCompZero(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RuleSubvarShift : public Rule {
public:
RuleSubvarShift(const string &g) : Rule( g, 0, "subvar_shift") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSubvarShift(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RuleSubvarZext : public Rule {
public:
RuleSubvarZext(const string &g) : Rule( g, 0, "subvar_zext") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSubvarZext(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RuleSubvarSext : public Rule {
int4 isaggressive; ///< Is it guaranteed the root is a sub-variable needing to be trimmed
public:
RuleSubvarSext(const string &g) : Rule( g, 0, "subvar_sext") { isaggressive = false; } ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSubvarSext(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
virtual void reset(Funcdata &data);
};
class RuleSubfloatConvert : public Rule {
public:
RuleSubfloatConvert(const string &g) : Rule( g, 0, "subfloat_convert") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSubfloatConvert(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RuleNegateNegate : public Rule {
public:
RuleNegateNegate(const string &g) : Rule( g, 0, "negatenegate") {} ///< Constructor
@ -1695,5 +1572,18 @@ public:
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
class RuleExpandLoad : public Rule {
static bool checkAndComparison(Varnode *vn);
static void modifyAndComparison(Funcdata &data,Varnode *oldVn,Varnode *newVn,Datatype *dt,int4 offset);
public:
RuleExpandLoad(const string &g) : Rule( g, 0, "expandload") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleExpandLoad(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
} // End namespace ghidra
#endif

View File

@ -14,6 +14,7 @@
* limitations under the License.
*/
#include "subflow.hh"
#include "funcdata.hh"
namespace ghidra {
@ -1506,6 +1507,204 @@ void SubvariableFlow::doReplacement(void)
}
}
void RuleSubvarAnd::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_AND);
}
int4 RuleSubvarAnd::applyOp(PcodeOp *op,Funcdata &data)
{
if (!op->getIn(1)->isConstant()) return 0;
Varnode *vn = op->getIn(0);
Varnode *outvn = op->getOut();
// if (vn->getSize() != 1) return 0; // Only for bitsize variables
if (outvn->getConsume() != op->getIn(1)->getOffset()) return 0;
if ((outvn->getConsume() & 1)==0) return 0;
uintb cmask;
if (outvn->getConsume() == (uintb)1)
cmask = (uintb)1;
else {
cmask = calc_mask(vn->getSize());
cmask >>=8;
while(cmask != 0) {
if (cmask == outvn->getConsume()) break;
cmask >>=8;
}
}
if (cmask == 0) return 0;
// if (vn->getConsume() == 0) return 0;
// if ((vn->getConsume() & 0xff)==0xff) return 0;
// if (op->getIn(1)->getOffset() != (uintb)1) return 0;
if (op->getOut()->hasNoDescend()) return 0;
SubvariableFlow subflow(&data,vn,cmask,false,false,false);
if (!subflow.doTrace()) return 0;
subflow.doReplacement();
return 1;
}
void RuleSubvarSubpiece::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_SUBPIECE);
}
int4 RuleSubvarSubpiece::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vn = op->getIn(0);
Varnode *outvn = op->getOut();
int4 flowsize = outvn->getSize();
uintb mask = calc_mask( flowsize );
mask <<= 8*((int4)op->getIn(1)->getOffset());
bool aggressive = outvn->isPtrFlow();
if (!aggressive) {
if ((vn->getConsume() & mask) != vn->getConsume()) return 0;
if (op->getOut()->hasNoDescend()) return 0;
}
bool big = false;
if (flowsize >= 8 && vn->isInput()) {
// Vector register inputs getting truncated to what actually gets used
// happens occasionally. We let SubvariableFlow deal with this special case
// to avoid overlapping inputs
// TODO: ActionLaneDivide should be handling this
if (vn->loneDescend() == op)
big = true;
}
SubvariableFlow subflow(&data,vn,mask,aggressive,false,big);
if (!subflow.doTrace()) return 0;
subflow.doReplacement();
return 1;
}
void RuleSubvarCompZero::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_NOTEQUAL);
oplist.push_back(CPUI_INT_EQUAL);
}
int4 RuleSubvarCompZero::applyOp(PcodeOp *op,Funcdata &data)
{
if (!op->getIn(1)->isConstant()) return 0;
Varnode *vn = op->getIn(0);
uintb mask = vn->getNZMask();
int4 bitnum = leastsigbit_set(mask);
if (bitnum == -1) return 0;
if ((mask >> bitnum) != 1) return 0; // Check if only one bit active
// Check if the active bit is getting tested
if ((op->getIn(1)->getOffset()!=mask)&&
(op->getIn(1)->getOffset()!=0))
return 0;
if (op->getOut()->hasNoDescend()) return 0;
// We do a basic check that the stream from which it looks like
// the bit is getting pulled is not fully consumed
if (vn->isWritten()) {
PcodeOp *andop = vn->getDef();
if (andop->numInput()==0) return 0;
Varnode *vn0 = andop->getIn(0);
switch(andop->code()) {
case CPUI_INT_AND:
case CPUI_INT_OR:
case CPUI_INT_RIGHT:
{
if (vn0->isConstant()) return 0;
uintb mask0 = vn0->getConsume() & vn0->getNZMask();
uintb wholemask = calc_mask(vn0->getSize()) & mask0;
// We really need a popcnt here
// We want: if the number of bits that are both consumed
// and not known to be zero are "big" then don't continue
// because it doesn't look like a few bits getting manipulated
// within a status register
if ((wholemask & 0xff)==0xff) return 0;
if ((wholemask & 0xff00)==0xff00) return 0;
}
break;
default:
break;
}
}
SubvariableFlow subflow(&data,vn,mask,false,false,false);
if (!subflow.doTrace()) {
return 0;
}
subflow.doReplacement();
return 1;
}
void RuleSubvarShift::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_RIGHT);
}
int4 RuleSubvarShift::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vn = op->getIn(0);
if (vn->getSize() != 1) return 0;
if (!op->getIn(1)->isConstant()) return 0;
int4 sa = (int4)op->getIn(1)->getOffset();
uintb mask = vn->getNZMask();
if ((mask >> sa) != (uintb)1) return 0; // Pulling out a single bit
mask = (mask >> sa) << sa;
if (op->getOut()->hasNoDescend()) return 0;
SubvariableFlow subflow(&data,vn,mask,false,false,false);
if (!subflow.doTrace()) return 0;
subflow.doReplacement();
return 1;
}
void RuleSubvarZext::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_ZEXT);
}
int4 RuleSubvarZext::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vn = op->getOut();
Varnode *invn = op->getIn(0);
uintb mask = calc_mask(invn->getSize());
SubvariableFlow subflow(&data,vn,mask,invn->isPtrFlow(),false,false);
if (!subflow.doTrace()) return 0;
subflow.doReplacement();
return 1;
}
void RuleSubvarSext::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_SEXT);
}
int4 RuleSubvarSext::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *vn = op->getOut();
Varnode *invn = op->getIn(0);
uintb mask = calc_mask(invn->getSize());
SubvariableFlow subflow(&data,vn,mask,isaggressive,true,false);
if (!subflow.doTrace()) return 0;
subflow.doReplacement();
return 1;
}
void RuleSubvarSext::reset(Funcdata &data)
{
isaggressive = data.getArch()->aggressive_ext_trim;
}
/// \brief Find or build the placeholder objects for a Varnode that needs to be split
///
/// Mark the Varnode so it doesn't get revisited.
@ -1797,6 +1996,57 @@ bool SplitFlow::doTrace(void)
return true;
}
void RuleSplitFlow::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_SUBPIECE);
}
int4 RuleSplitFlow::applyOp(PcodeOp *op,Funcdata &data)
{
int4 loSize = (int4)op->getIn(1)->getOffset();
if (loSize == 0) // Make sure SUBPIECE doesn't take least significant part
return 0;
Varnode *vn = op->getIn(0);
if (!vn->isWritten())
return 0;
if (vn->isPrecisLo() || vn->isPrecisHi())
return 0;
if (op->getOut()->getSize() + loSize != vn->getSize())
return 0; // Make sure SUBPIECE is taking most significant part
PcodeOp *concatOp = (PcodeOp *)0;
PcodeOp *multiOp = vn->getDef();
while(multiOp->code() == CPUI_INDIRECT) { // PIECE may come through INDIRECT
Varnode *tmpvn = multiOp->getIn(0);
if (!tmpvn->isWritten()) return 0;
multiOp = tmpvn->getDef();
}
if (multiOp->code() == CPUI_PIECE) {
if (vn->getDef() != multiOp)
concatOp = multiOp;
}
else if (multiOp->code() == CPUI_MULTIEQUAL) { // Otherwise PIECE comes through MULTIEQUAL
for(int4 i=0;i<multiOp->numInput();++i) {
Varnode *invn = multiOp->getIn(i);
if (!invn->isWritten()) continue;
PcodeOp *tmpOp = invn->getDef();
if (tmpOp->code() == CPUI_PIECE) {
concatOp = tmpOp;
break;
}
}
}
if (concatOp == (PcodeOp *)0) // Didn't find the concatenate
return 0;
if (concatOp->getIn(1)->getSize() != loSize)
return 0;
SplitFlow splitFlow(&data,vn,loSize);
if (!splitFlow.doTrace()) return 0;
splitFlow.apply();
return 1;
}
/// If \b pointer Varnode is written by a COPY, INT_ADD, PTRSUB, or PTRADD from another pointer to a
/// - structure
/// - array OR
@ -2628,8 +2878,7 @@ Datatype *SplitDatatype::getValueDatatype(PcodeOp *loadStore,int4 size,TypeFacto
if (ptrType->isPointerRel()) {
TypePointerRel *ptrRel = (TypePointerRel *)ptrType;
resType = ptrRel->getParent();
baseOffset = ptrRel->getPointerOffset();
baseOffset = AddrSpace::addressToByteInt(baseOffset, ptrRel->getWordSize());
baseOffset = ptrRel->getByteOffset();
}
else {
resType = ((TypePointer *)ptrType)->getPtrTo();
@ -2649,6 +2898,71 @@ Datatype *SplitDatatype::getValueDatatype(PcodeOp *loadStore,int4 size,TypeFacto
return (Datatype *)0;
}
void RuleSplitCopy::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_COPY);
}
int4 RuleSplitCopy::applyOp(PcodeOp *op,Funcdata &data)
{
Datatype *inType = op->getIn(0)->getTypeReadFacing(op);
Datatype *outType = op->getOut()->getTypeDefFacing();
type_metatype metain = inType->getMetatype();
type_metatype metaout = outType->getMetatype();
if (metain != TYPE_PARTIALSTRUCT && metaout != TYPE_PARTIALSTRUCT &&
metain != TYPE_ARRAY && metaout != TYPE_ARRAY &&
metain != TYPE_STRUCT && metaout != TYPE_STRUCT)
return false;
SplitDatatype splitter(data);
if (splitter.splitCopy(op, inType, outType))
return 1;
return 0;
}
void RuleSplitLoad::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_LOAD);
}
int4 RuleSplitLoad::applyOp(PcodeOp *op,Funcdata &data)
{
Datatype *inType = SplitDatatype::getValueDatatype(op, op->getOut()->getSize(), data.getArch()->types);
if (inType == (Datatype *)0)
return 0;
type_metatype metain = inType->getMetatype();
if (metain != TYPE_STRUCT && metain != TYPE_ARRAY && metain != TYPE_PARTIALSTRUCT)
return 0;
SplitDatatype splitter(data);
if (splitter.splitLoad(op, inType))
return 1;
return 0;
}
void RuleSplitStore::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_STORE);
}
int4 RuleSplitStore::applyOp(PcodeOp *op,Funcdata &data)
{
Datatype *outType = SplitDatatype::getValueDatatype(op, op->getIn(2)->getSize(), data.getArch()->types);
if (outType == (Datatype *)0)
return 0;
type_metatype metain = outType->getMetatype();
if (metain != TYPE_STRUCT && metain != TYPE_ARRAY && metain != TYPE_PARTIALSTRUCT)
return 0;
SplitDatatype splitter(data);
if (splitter.splitStore(op, outType))
return 1;
return 0;
}
/// This method distinguishes between a floating-point variable with \e full precision, where all the
/// storage can vary (or is unknown), versus a value that is extended from a floating-point variable with
/// smaller storage. Within the data-flow above the given Varnode, we search for the maximum
@ -3062,6 +3376,32 @@ bool SubfloatFlow::doTrace(void)
return true;
}
void RuleSubfloatConvert::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_FLOAT_FLOAT2FLOAT);
}
int4 RuleSubfloatConvert::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *invn = op->getIn(0);
Varnode *outvn = op->getOut();
int4 insize = invn->getSize();
int4 outsize = outvn->getSize();
if (outsize > insize) {
SubfloatFlow subflow(&data,outvn,insize);
if (!subflow.doTrace()) return 0;
subflow.apply();
}
else {
SubfloatFlow subflow(&data,invn,outsize);
if (!subflow.doTrace()) return 0;
subflow.apply();
}
return 1;
}
/// \brief Find or build the placeholder objects for a Varnode that needs to be split into lanes
///
/// The Varnode is split based on the given subset of the lane description.

View File

@ -18,7 +18,8 @@
#ifndef __SUBFLOW_HH__
#define __SUBFLOW_HH__
#include "funcdata.hh"
#include "ruleaction.hh"
#include "transform.hh"
namespace ghidra {
@ -128,6 +129,89 @@ public:
void doReplacement(void); ///< Perform the discovered transform, making logical values explicit
};
/// \brief Perform SubVariableFlow analysis triggered by INT_AND
class RuleSubvarAnd : public Rule {
public:
RuleSubvarAnd(const string &g) : Rule( g, 0, "subvar_and") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSubvarAnd(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
/// \brief Perform SubVariableFlow analysis triggered by SUBPIECE
class RuleSubvarSubpiece : public Rule {
public:
RuleSubvarSubpiece(const string &g) : Rule( g, 0, "subvar_subpiece") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSubvarSubpiece(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
/// \brief Perform SubvariableFlow analysis triggered by testing of a single bit
///
/// Given a comparison (INT_EQUAL or INT_NOTEEQUAL_ to a constant,
/// check that input has only 1 bit that can possibly be non-zero
/// and that the constant is testing this. This then triggers
/// the full SubvariableFlow analysis.
class RuleSubvarCompZero : public Rule {
public:
RuleSubvarCompZero(const string &g) : Rule( g, 0, "subvar_compzero") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSubvarCompZero(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
/// \brief Perform SubvariableFlow analysis triggered by INT_RIGHT
///
/// If the INT_RIGHT input has only 1 bit that can possibly be non-zero
/// and it is getting shifted into the least significant bit position,
/// trigger the full SubvariableFlow analysis.
class RuleSubvarShift : public Rule {
public:
RuleSubvarShift(const string &g) : Rule( g, 0, "subvar_shift") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSubvarShift(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
/// \brief Perform SubvariableFlow analysis triggered by INT_ZEXT
class RuleSubvarZext : public Rule {
public:
RuleSubvarZext(const string &g) : Rule( g, 0, "subvar_zext") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSubvarZext(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
/// \brief Perform SubvariableFlow analysis triggered by INT_SEXT
class RuleSubvarSext : public Rule {
int4 isaggressive; ///< Is it guaranteed the root is a sub-variable needing to be trimmed
public:
RuleSubvarSext(const string &g) : Rule( g, 0, "subvar_sext") { isaggressive = false; } ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSubvarSext(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
virtual void reset(Funcdata &data);
};
/// \brief Class for splitting up Varnodes that hold 2 logical variables
///
/// Starting from a \e root Varnode provided to the constructor, \b this class looks for data-flow
@ -147,6 +231,22 @@ public:
bool doTrace(void); ///< Trace split through data-flow, constructing transform
};
/// \brief Try to detect and split artificially joined Varnodes
///
/// Look for SUBPIECE coming from a PIECE that has come through INDIRECTs and/or MULTIEQUAL
/// Then: check if the input to SUBPIECE can be viewed as two independent pieces
/// If so: split the pieces into independent data-flows
class RuleSplitFlow : public Rule {
public:
RuleSplitFlow(const string &g) : Rule( g, 0, "splitflow") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSplitFlow(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
/// \brief Split a p-code COPY, LOAD, or STORE op based on underlying composite data-type
///
/// During the cleanup phase, if a COPY, LOAD, or STORE occurs on a partial structure or array
@ -208,6 +308,51 @@ public:
static Datatype *getValueDatatype(PcodeOp *loadStore,int4 size,TypeFactory *tlst);
};
/// \brief Split COPY ops based on TypePartialStruct
///
/// If more than one logical component of a structure or array is copied at once,
/// rewrite the COPY operator as multiple COPYs.
class RuleSplitCopy : public Rule {
public:
RuleSplitCopy(const string &g) : Rule( g, 0, "splitcopy") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSplitCopy(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
/// \brief Split LOAD ops based on TypePartialStruct
///
/// If more than one logical component of a structure or array is loaded at once,
/// rewrite the LOAD operator as multiple LOADs.
class RuleSplitLoad : public Rule {
public:
RuleSplitLoad(const string &g) : Rule( g, 0, "splitload") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSplitLoad(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
/// \brief Split STORE ops based on TypePartialStruct
///
/// If more than one logical component of a structure or array is stored at once,
/// rewrite the STORE operator as multiple STOREs.
class RuleSplitStore : public Rule {
public:
RuleSplitStore(const string &g) : Rule( g, 0, "splitstore") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSplitStore(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
/// \brief Class for tracing changes of precision in floating point variables
///
/// It follows the flow of a logical lower precision value stored in higher precision locations
@ -242,6 +387,18 @@ public:
bool doTrace(void); ///< Trace logical value as far as possible
};
/// \brief Perform SubfloatFlow analysis triggered by FLOAT_FLOAT2FLOAT
class RuleSubfloatConvert : public Rule {
public:
RuleSubfloatConvert(const string &g) : Rule( g, 0, "subfloat_convert") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RuleSubfloatConvert(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
};
/// \brief Class for splitting data-flow on \e laned registers
///
/// From a root Varnode and a description of its \e lanes, trace data-flow as far as

View File

@ -113,6 +113,24 @@ void FunctionTestCollection::clear(void)
console->reset();
}
/// Remove any carriage return character as well.
/// \param ref is the string to strip
/// \return the stripped string
string FunctionTestCollection::stripNewlines(const string &ref)
{
string res;
for(int4 i=0;i<ref.size();++i) {
char c = ref[i];
if (c == '\r') continue; // Remove carriage return
if (c == '\n')
c = ' '; // Convert newline to space
res.push_back(c);
}
return res;
}
/// \param el is the root \<script> tag
void FunctionTestCollection::restoreXmlCommands(const Element *el)
@ -122,7 +140,7 @@ void FunctionTestCollection::restoreXmlCommands(const Element *el)
for(iter=list.begin();iter!=list.end();++iter) {
const Element *subel = *iter;
commands.push_back(subel->getContent());
commands.push_back(stripNewlines(subel->getContent()));
}
}

View File

@ -77,6 +77,7 @@ class FunctionTestCollection {
mutable int4 numTestsApplied; ///< Count of tests that were executed
mutable int4 numTestsSucceeded; ///< Count of tests that passed
void clear(void); ///< Clear any previous architecture and function
static string stripNewlines(const string &ref); ///< Convert any \e newline character to a \e space
void restoreXmlCommands(const Element *el); ///< Reconstruct commands from an XML tag
void buildProgram(DocumentStorage &store); ///< Build program (Architecture) from \<binaryimage> tag
void startTests(void) const; ///< Initialize each FunctionTestProperty

View File

@ -20,16 +20,17 @@ namespace ghidra {
/// The base propagation ordering associated with each meta-type.
/// The array elements correspond to the ordering of #type_metatype.
sub_metatype Datatype::base2sub[15] = {
SUB_PARTIALUNION, SUB_PARTIALSTRUCT, SUB_UNION, SUB_STRUCT, SUB_ARRAY, SUB_PTRREL, SUB_PTR, SUB_FLOAT, SUB_CODE,
SUB_BOOL, SUB_UINT_PLAIN, SUB_INT_PLAIN, SUB_UNKNOWN, SUB_SPACEBASE, SUB_VOID
sub_metatype Datatype::base2sub[18] = {
SUB_PARTIALUNION, SUB_PARTIALSTRUCT, SUB_UINT_ENUM, SUB_UNION, SUB_STRUCT, SUB_INT_ENUM, SUB_UINT_ENUM,
SUB_ARRAY, SUB_PTRREL, SUB_PTR, SUB_FLOAT, SUB_CODE, SUB_BOOL, SUB_UINT_PLAIN, SUB_INT_PLAIN, SUB_UNKNOWN,
SUB_SPACEBASE, SUB_VOID
};
AttributeId ATTRIB_ALIGNMENT = AttributeId("alignment",47);
AttributeId ATTRIB_ARRAYSIZE = AttributeId("arraysize",48);
AttributeId ATTRIB_CHAR = AttributeId("char",49);
AttributeId ATTRIB_CORE = AttributeId("core",50);
AttributeId ATTRIB_ENUM = AttributeId("enum",51);
//AttributeId ATTRIB_ENUM = AttributeId("enum",51); // deprecated
AttributeId ATTRIB_INCOMPLETE = AttributeId("incomplete",52);
//AttributeId ATTRIB_ENUMSIZE = AttributeId("enumsize",53); // deprecated
//AttributeId ATTRIB_INTSIZE = AttributeId("intsize",54); // deprecated
@ -250,12 +251,21 @@ void metatype2string(type_metatype metatype,string &res)
case TYPE_ARRAY:
res = "array";
break;
case TYPE_PARTIALENUM:
res = "partenum";
break;
case TYPE_PARTIALSTRUCT:
res = "partstruct";
break;
case TYPE_PARTIALUNION:
res = "partunion";
break;
case TYPE_ENUM_INT:
res = "enum_int";
break;
case TYPE_ENUM_UINT:
res = "enum_uint";
break;
case TYPE_STRUCT:
res = "struct";
break;
@ -309,6 +319,12 @@ type_metatype string2metatype(const string &metastring)
if (metastring=="array")
return TYPE_ARRAY;
break;
case 'e':
if (metastring=="enum_int")
return TYPE_ENUM_INT;
else if (metastring == "enum_uint")
return TYPE_ENUM_UINT;
break;
case 's':
if (metastring=="struct")
return TYPE_STRUCT;
@ -1083,6 +1099,12 @@ TypePointer *TypePointer::downChain(int8 &off,TypePointer *&par,int8 &parOff,boo
}
}
if (ptrto->isEnumType()) {
// Go "into" the enumeration
Datatype *tmp = typegrp.getBase(1, TYPE_UINT);
off = 0;
return typegrp.getTypePointer(size,tmp,wordsize);
}
type_metatype meta = ptrto->getMetatype();
bool isArray = (meta == TYPE_ARRAY);
if (isArray || meta == TYPE_STRUCT) {
@ -1325,81 +1347,22 @@ TypeEnum::TypeEnum(const TypeEnum &op) : TypeBase(op)
{
namemap = op.namemap;
masklist = op.masklist;
flags |= (op.flags&poweroftwo)|enumtype;
}
/// Set the map. Calculate the independent bit-fields within the named values of the enumeration
/// Two bits are in the same bit-field if there is a name in the map whose value
/// has those two bits set. Bit-fields must be a contiguous range of bits.
void TypeEnum::setNameMap(const map<uintb,string> &nmap)
/// \param val is the given value to test
/// \return \b true if \b this enumeration has a name with the value
bool TypeEnum::hasNamedValue(uintb val) const
{
map<uintb,string>::const_iterator iter;
uintb curmask,lastmask;
int4 maxbit;
int4 curmaxbit;
bool fieldisempty;
namemap = nmap;
masklist.clear();
flags &= ~((uint4)poweroftwo);
maxbit = 8 * size - 1;
curmaxbit = 0;
while(curmaxbit <= maxbit) {
curmask = 1;
curmask <<= curmaxbit;
lastmask = 0;
fieldisempty = true;
while(curmask != lastmask) { // Repeat until there is no change in the current mask
lastmask = curmask; // Note changes from last time through
for(iter=namemap.begin();iter!=namemap.end();++iter) { // For every named enumeration value
uintb val = (*iter).first;
if ((val & curmask) != 0) { // If the value shares ANY bits in common with the current mask
curmask |= val; // Absorb ALL defined bits of the value into the current mask
fieldisempty = false;
}
}
// Fill in any holes in the mask (bit field must consist of contiguous bits
int4 lsb = leastsigbit_set(curmask);
int4 msb = mostsigbit_set(curmask);
if (msb > curmaxbit)
curmaxbit = msb;
uintb mask1 = 1;
mask1 = (mask1 << lsb) - 1; // every bit below lsb is set to 1
uintb mask2 = 1;
mask2 <<= msb;
mask2 <<= 1;
mask2 -= 1; // every bit below or equal to msb is set to 1
curmask = mask1 ^ mask2;
}
if (fieldisempty) { // If no value hits this bit
if (!masklist.empty())
masklist.back() |= curmask; // Include the bit with the previous mask
else
masklist.push_back(curmask);
}
else
masklist.push_back(curmask);
curmaxbit += 1;
}
if (masklist.size() > 1)
flags |= poweroftwo;
return (namemap.find(val) != namemap.end());
}
/// Given a specific value of the enumeration, calculate the named representation of that value.
/// The representation is returned as a list of names that must logically ORed and possibly complemented.
/// If no representation is possible, no names will be returned.
/// \param val is the value to find the representation for
/// \param valnames will hold the returned list of names
/// \return true if the representation needs to be complemented
bool TypeEnum::getMatches(uintb val,vector<string> &valnames) const
/// \param rep will contain the individual names in the representation and other transforms
void TypeEnum::getMatches(uintb val,Representation &rep) const
{
map<uintb,string>::const_iterator iter;
@ -1407,33 +1370,47 @@ bool TypeEnum::getMatches(uintb val,vector<string> &valnames) const
for(count=0;count<2;++count) {
bool allmatch = true;
if (val == 0) { // Zero handled specially, it crosses all masks
if (val == 0) { // Zero handled specially
iter = namemap.find(val);
if (iter != namemap.end())
valnames.push_back( (*iter).second );
rep.matchname.push_back( (*iter).second );
else
allmatch = false;
}
else {
for(int4 i=0;i<masklist.size();++i) {
uintb maskedval = val & masklist[i];
if (maskedval == 0) // No component of -val- in this mask
continue; // print nothing
iter = namemap.find(maskedval);
if (iter != namemap.end())
valnames.push_back( (*iter).second ); // Found name for this component
else { // If no name for this component
allmatch = false; // Give up on representation
break; // Stop searching for other components
uintb bitsleft = val;
uintb target = val;
while(target != 0) {
// Find named value that matches the largest number of most significant bits in bitsleft
iter = namemap.upper_bound(target);
if (iter == namemap.begin()) break; // All named values are greater than target
--iter; // Biggest named value less than or equal to target
uintb curval = (*iter).first;
uintb diff = coveringmask(bitsleft ^ curval);
if (diff >= bitsleft) break; // Could not match most significant bit of bitsleft
if ((curval & diff) == 0) {
// Found a named value that matches at least most significant bit of bitsleft
rep.matchname.push_back( (*iter).second ); // Accept the name
bitsleft ^= curval; // Remove the bits from bitsleft
target = bitsleft; // Continue searching for named value that match the new bitsleft
}
else {
// Not all the (one) bits of curval match into bitsleft, but we can restrict a further search.
// Bits above diff in curval are the maximum we can hope to match with one named value.
// Zero out bits below this and prepare to search at or below this value
target = curval & ~diff;
}
}
allmatch = (bitsleft == 0);
}
if (allmatch) { // If we have a complete representation
rep.complement = (count==1); // Set whether we represented original value or complement
return;
}
if (allmatch) // If we have a complete representation
return (count==1); // Return whether we represented original value or complement
val = val ^ calc_mask(size); // Switch value we are trying to represent (to complement)
valnames.clear(); // Clear out old attempt
rep.matchname.clear(); // Clear out old attempt
}
return false; // If we reach here, no representation was possible, -valnames- is empty
// If we reach here, no representation was possible, -matchname- is empty
}
int4 TypeEnum::compare(const Datatype &op,int4 level) const
@ -1475,8 +1452,7 @@ void TypeEnum::encode(Encoder &encoder) const
return;
}
encoder.openElement(ELEM_TYPE);
encodeBasic(metatype,-1,encoder);
encoder.writeString(ATTRIB_ENUM, "true");
encodeBasic((metatype == TYPE_INT) ? TYPE_ENUM_INT : TYPE_ENUM_UINT,-1,encoder);
map<uintb,string>::const_iterator iter;
for(iter=namemap.begin();iter!=namemap.end();++iter) {
encoder.openElement(ELEM_VAL);
@ -1496,7 +1472,7 @@ string TypeEnum::decode(Decoder &decoder,TypeFactory &typegrp)
{
// uint4 elemId = decoder.openElement();
decodeBasic(decoder);
submeta = (metatype == TYPE_INT) ? SUB_INT_ENUM : SUB_UINT_ENUM;
metatype = (metatype == TYPE_ENUM_INT) ? TYPE_INT : TYPE_UINT; // Use TYPE_INT or TYPE_UINT internally
map<uintb,string> nmap;
string warning;
@ -2265,6 +2241,81 @@ void TypeUnion::assignFieldOffsets(vector<TypeField> &list,int4 &newSize,int4 &n
}
}
TypePartialEnum::TypePartialEnum(const TypePartialEnum &op)
: TypeEnum(op)
{
stripped = op.stripped;
parent = op.parent;
offset = op.offset;
}
TypePartialEnum::TypePartialEnum(TypeEnum *par,int4 off,int4 sz,Datatype *strip)
: TypeEnum(sz, TYPE_PARTIALENUM)
{
flags |= has_stripped;
stripped = strip;
parent = par;
offset = off;
}
void TypePartialEnum::printRaw(ostream &s) const
{
parent->printRaw(s);
s << "[off=" << dec << offset << ",sz=" << size << ']';
}
bool TypePartialEnum::hasNamedValue(uintb val) const
{
val <<= 8*offset;
return parent->hasNamedValue(val);
}
void TypePartialEnum::getMatches(uintb val,Representation &rep) const
{
val <<= 8*offset;
rep.shiftAmount = offset * 8;
parent->getMatches(val,rep);
}
int4 TypePartialEnum::compare(const Datatype &op,int4 level) const
{
int4 res = Datatype::compare(op,level);
if (res != 0) return res;
// Both must be partial
TypePartialEnum *tp = (TypePartialEnum *) &op;
if (offset != tp->offset) return (offset < tp->offset) ? -1 : 1;
level -= 1;
if (level < 0) {
if (id == op.getId()) return 0;
return (id < op.getId()) ? -1 : 1;
}
return parent->compare(*tp->parent,level); // Compare the underlying union
}
int4 TypePartialEnum::compareDependency(const Datatype &op) const
{
if (submeta != op.getSubMeta()) return (submeta < op.getSubMeta()) ? -1 : 1;
TypePartialEnum *tp = (TypePartialEnum *) &op; // Both must be partial
if (parent != tp->parent) return (parent < tp->parent) ? -1 : 1; // Compare absolute pointers
if (offset != tp->offset) return (offset < tp->offset) ? -1 : 1;
return (op.getSize()-size);
}
void TypePartialEnum::encode(Encoder &encoder) const
{
encoder.openElement(ELEM_TYPE);
encodeBasic(TYPE_PARTIALENUM,-1,encoder);
encoder.writeSignedInteger(ATTRIB_OFFSET, offset);
parent->encodeRef(encoder);
encoder.closeElement(ELEM_TYPE);
}
TypePartialStruct::TypePartialStruct(const TypePartialStruct &op)
: Datatype(op)
{
@ -3111,7 +3162,7 @@ void TypeFactory::setupSizes(void)
setDefaultAlignmentMap();
if (enumsize == 0) {
enumsize = glb->getDefaultSize();
enumtype = TYPE_UINT;
enumtype = TYPE_ENUM_UINT;
}
}
@ -3866,6 +3917,11 @@ TypeStruct *TypeFactory::getTypeStruct(const string &n)
return (TypeStruct *) findAdd(tmp);
}
/// Create a data-type representing storage of part of an \e array or \e structure.
/// \param contain is the parent \e array or \e structure data-type that we are taking a part of.
/// \param off is the offset (in bytes) within the parent that the partial data-type starts at
/// \param sz is the number of bytes in the partial data-type
/// \return the TypePartialStruct object
TypePartialStruct *TypeFactory::getTypePartialStruct(Datatype *contain,int4 off,int4 sz)
{
@ -3887,6 +3943,11 @@ TypeUnion *TypeFactory::getTypeUnion(const string &n)
return (TypeUnion *) findAdd(tmp);
}
/// Create a data-type representing storage of part of a \e union data-type.
/// \param contain is the parent \e union data-type that we are taking a part of.
/// \param off is the offset (in bytes) within the parent that the partial data-type starts at
/// \param sz is the number of bytes in the partial data-type
/// \return the TypePartialUnion object
TypePartialUnion *TypeFactory::getTypePartialUnion(TypeUnion *contain,int4 off,int4 sz)
{
@ -3907,6 +3968,19 @@ TypeEnum *TypeFactory::getTypeEnum(const string &n)
return (TypeEnum *) findAdd(tmp);
}
/// Create a data-type representing storage of part of an \e enumeration.
/// \param contain is the parent \e enumeration data-type that we are taking a part of.
/// \param off is the offset (in bytes) within the parent that the partial data-type starts at
/// \param sz is the number of bytes in the partial data-type
/// \return the TypePartialEnum object
TypePartialEnum *TypeFactory::getTypePartialEnum(TypeEnum *contain,int4 off,int4 sz)
{
Datatype *strip = getBase(sz, TYPE_UNKNOWN);
TypePartialEnum tpe(contain,off,sz,strip);
return (TypePartialEnum *) findAdd(tpe);
}
/// Creates the special TypeSpacebase with an associated address space and scope
/// \param id is the address space
/// \param addr specifies the function scope, or isInvalid() for global scope
@ -4032,6 +4106,8 @@ Datatype *TypeFactory::getExactPiece(Datatype *ct,int4 offset,int4 size)
// If we reach here, lastType is bigger than size
if (lastType->getMetatype() == TYPE_STRUCT || lastType->getMetatype() == TYPE_ARRAY)
return getTypePartialStruct(lastType, lastOff, size);
else if (lastType->isEnumType() && !lastType->hasStripped())
return getTypePartialEnum((TypeEnum *)lastType, lastOff, size);
}
return (Datatype *)0;
}
@ -4238,7 +4314,7 @@ Datatype *TypeFactory::decodeTypedef(Decoder &decoder)
Datatype *TypeFactory::decodeEnum(Decoder &decoder,bool forcecore)
{
TypeEnum te(1,TYPE_INT); // size and metatype are replaced
TypeEnum te(1,TYPE_ENUM_INT); // metatype and size are replaced
string warning = te.decode(decoder,*this);
if (forcecore)
te.flags |= Datatype::coretype;
@ -4399,6 +4475,10 @@ Datatype *TypeFactory::decodeTypeNoRef(Decoder &decoder,bool forcecore)
ct = findAdd(ta);
}
break;
case TYPE_ENUM_INT:
case TYPE_ENUM_UINT:
ct = decodeEnum(decoder,forcecore);
break;
case TYPE_STRUCT:
ct = decodeStruct(decoder,forcecore);
break;
@ -4438,12 +4518,6 @@ Datatype *TypeFactory::decodeTypeNoRef(Decoder &decoder,bool forcecore)
decoder.closeElement(elemId);
return ct;
}
else if (attribId == ATTRIB_ENUM && decoder.readBool()) {
decoder.rewindAttributes();
ct = decodeEnum(decoder, forcecore);
decoder.closeElement(elemId);
return ct;
}
else if (attribId == ATTRIB_UTF && decoder.readBool()) {
TypeUnicode tu;
decoder.rewindAttributes();
@ -4587,9 +4661,9 @@ void TypeFactory::parseEnumConfig(Decoder &decoder)
uint4 elemId = decoder.openElement(ELEM_ENUM);
enumsize = decoder.readSignedInteger(ATTRIB_SIZE);
if (decoder.readBool(ATTRIB_SIGNED))
enumtype = TYPE_INT;
enumtype = TYPE_ENUM_INT;
else
enumtype = TYPE_UINT;
enumtype = TYPE_ENUM_UINT;
decoder.closeElement(elemId);
}

View File

@ -27,7 +27,7 @@ extern AttributeId ATTRIB_ALIGNMENT; ///< Marshaling attribute "alignment"
extern AttributeId ATTRIB_ARRAYSIZE; ///< Marshaling attribute "arraysize"
extern AttributeId ATTRIB_CHAR; ///< Marshaling attribute "char"
extern AttributeId ATTRIB_CORE; ///< Marshaling attribute "core"
extern AttributeId ATTRIB_ENUM; ///< Marshaling attribute "enum"
//extern AttributeId ATTRIB_ENUM; ///< Marshaling attribute "enum" deprecated
extern AttributeId ATTRIB_INCOMPLETE; ///< Marshaling attribute "incomplete"
//extern AttributeId ATTRIB_ENUMSIZE; ///< Marshaling attribute "enumsize" deprecated
//extern AttributeId ATTRIB_INTSIZE; ///< Marshaling attribute "intsize" deprecated
@ -77,20 +77,23 @@ extern void print_data(ostream &s,uint1 *buffer,int4 size,const Address &baseadd
/// The core meta-types supported by the decompiler. These are sizeless templates
/// for the elements making up the type algebra. Index is important for Datatype::base2sub array.
enum type_metatype {
TYPE_VOID = 14, ///< Standard "void" type, absence of type
TYPE_SPACEBASE = 13, ///< Placeholder for symbol/type look-up calculations
TYPE_UNKNOWN = 12, ///< An unknown low-level type. Treated as an unsigned integer.
TYPE_INT = 11, ///< Signed integer. Signed is considered less specific than unsigned in C
TYPE_UINT = 10, ///< Unsigned integer
TYPE_BOOL = 9, ///< Boolean
TYPE_CODE = 8, ///< Data is actual executable code
TYPE_FLOAT = 7, ///< Floating-point
TYPE_VOID = 17, ///< Standard "void" type, absence of type
TYPE_SPACEBASE = 16, ///< Placeholder for symbol/type look-up calculations
TYPE_UNKNOWN = 15, ///< An unknown low-level type. Treated as an unsigned integer.
TYPE_INT = 14, ///< Signed integer. Signed is considered less specific than unsigned in C
TYPE_UINT = 13, ///< Unsigned integer
TYPE_BOOL = 12, ///< Boolean
TYPE_CODE = 11, ///< Data is actual executable code
TYPE_FLOAT = 10, ///< Floating-point
TYPE_PTR = 6, ///< Pointer data-type
TYPE_PTRREL = 5, ///< Pointer relative to another data-type (specialization of TYPE_PTR)
TYPE_ARRAY = 4, ///< Array data-type, made up of a sequence of "element" datatype
TYPE_STRUCT = 3, ///< Structure data-type, made up of component datatypes
TYPE_UNION = 2, ///< An overlapping union of multiple datatypes
TYPE_PTR = 9, ///< Pointer data-type
TYPE_PTRREL = 8, ///< Pointer relative to another data-type (specialization of TYPE_PTR)
TYPE_ARRAY = 7, ///< Array data-type, made up of a sequence of "element" datatype
TYPE_ENUM_UINT = 6, ///< Unsigned enumeration data-type (specialization of TYPE_UINT)
TYPE_ENUM_INT = 5, ///< Signed enumeration data-type (specialization of TYPE_INT)
TYPE_STRUCT = 4, ///< Structure data-type, made up of component datatypes
TYPE_UNION = 3, ///< An overlapping union of multiple datatypes
TYPE_PARTIALENUM = 2, ///< Part of an enumerated value (specialization of TYPE_UINT)
TYPE_PARTIALSTRUCT = 1, ///< Part of a structure, stored separately from the whole
TYPE_PARTIALUNION = 0 ///< Part of a union
};
@ -160,7 +163,7 @@ struct DatatypeCompare;
/// Used for symbols, function prototypes, type propagation etc.
class Datatype {
protected:
static sub_metatype base2sub[15];
static sub_metatype base2sub[18];
/// Boolean properties of datatypes
enum {
coretype = 1, ///< This is a basic type which will never be redefined
@ -213,7 +216,6 @@ public:
bool isCoreType(void) const { return ((flags&coretype)!=0); } ///< Is this a core data-type
bool isCharPrint(void) const { return ((flags&(chartype|utf16|utf32|opaque_string))!=0); } ///< Does this print as a 'char'
bool isEnumType(void) const { return ((flags&enumtype)!=0); } ///< Is this an enumerated type
bool isPowerOfTwo(void) const { return ((flags&poweroftwo)!=0); } ///< Is this a flag-based enumeration
bool isASCII(void) const { return ((flags&chartype)!=0); } ///< Does this print as an ASCII 'char'
bool isUTF16(void) const { return ((flags&utf16)!=0); } ///< Does this print as UTF16 'wchar'
bool isUTF32(void) const { return ((flags&utf32)!=0); } ///< Does this print as UTF32 'wchar'
@ -466,24 +468,33 @@ public:
/// This supports combinations of the enumeration values (using logical OR and bit-wise complement)
/// by defining independent \b bit-fields.
class TypeEnum : public TypeBase {
public:
/// \brief Class describing how a particular enumeration value is constructed using tokens
class Representation {
public:
vector<string> matchname; ///< Name tokens that are ORed together
bool complement; ///< If \b true, bitwise complement value after ORing
int4 shiftAmount; ///< Number of bits to left-shift final value
Representation(void) { complement = false; shiftAmount = 0; } ///< Constructor
};
protected:
friend class TypeFactory;
map<uintb,string> namemap; ///< Map from integer to name
vector<uintb> masklist; ///< Masks for each bitfield within the enum
void setNameMap(const map<uintb,string> &nmap); ///< Establish the value -> name map
void setNameMap(const map<uintb,string> &nmap) { namemap = nmap; } ///< Establish the value -> name map
string decode(Decoder &decoder,TypeFactory &typegrp); ///< Restore \b this enum data-type from a stream
public:
/// Construct from another TypeEnum
TypeEnum(const TypeEnum &op);
/// Construct from a size and meta-type (TYPE_INT or TYPE_UINT)
TypeEnum(int4 s,type_metatype m) : TypeBase(s,m) {
flags |= enumtype; submeta = (m==TYPE_INT) ? SUB_INT_ENUM : SUB_UINT_ENUM; }
flags |= enumtype; metatype = (m==TYPE_ENUM_INT) ? TYPE_INT : TYPE_UINT; }
/// Construct from a size, meta-type, and name
TypeEnum(int4 s,type_metatype m,const string &nm) : TypeBase(s,m,nm) {
flags |= enumtype; submeta = (m==TYPE_INT) ? SUB_INT_ENUM : SUB_UINT_ENUM; }
flags |= enumtype; metatype = (m==TYPE_ENUM_INT) ? TYPE_INT : TYPE_UINT; }
map<uintb,string>::const_iterator beginEnum(void) const { return namemap.begin(); } ///< Beginning of name map
map<uintb,string>::const_iterator endEnum(void) const { return namemap.end(); } ///< End of name map
bool getMatches(uintb val,vector<string> &matchname) const; ///< Recover the named representation
virtual bool hasNamedValue(uintb val) const; ///< Does \b this have a (single) name for the given value
virtual void getMatches(uintb val,Representation &rep) const; ///< Recover the named representation
virtual int4 compare(const Datatype &op,int4 level) const;
virtual int4 compareDependency(const Datatype &op) const;
virtual Datatype *clone(void) const { return new TypeEnum(*this); }
@ -553,6 +564,27 @@ public:
static void assignFieldOffsets(vector<TypeField> &list,int4 &newSize,int4 &newAlign,TypeUnion *tu); ///< Assign field offsets
};
/// \brief A data-type thats holds part of a TypeEnum and possible additional padding
class TypePartialEnum : public TypeEnum {
friend class TypeFactory;
Datatype *stripped; ///< The \e undefined data-type to use if a formal data-type is required.
TypeEnum *parent; ///< The enumeration data-type \b this is based on
int4 offset; ///< Byte offset with the parent enum where \b this starts
public:
TypePartialEnum(const TypePartialEnum &op); ///< Construct from another TypePartialEnum
TypePartialEnum(TypeEnum *par,int4 off,int4 sz,Datatype *strip); ///< Constructor
int4 getOffset(void) const { return offset; } ///< Get the byte offset into the containing data-type
Datatype *getParent(void) const { return parent; } ///< Get the enumeration containing \b this piece
virtual void printRaw(ostream &s) const;
virtual bool hasNamedValue(uintb val) const;
virtual void getMatches(uintb val,Representation &rep) const;
virtual int4 compare(const Datatype &op,int4 level) const;
virtual int4 compareDependency(const Datatype &op) const;
virtual Datatype *clone(void) const { return new TypePartialEnum(*this); }
virtual void encode(Encoder &encoder) const;
virtual Datatype *getStripped(void) const { return stripped; }
};
/// \brief A data-type that holds \e part of a TypeStruct or TypeArray
class TypePartialStruct : public Datatype {
friend class TypeFactory;
@ -634,7 +666,12 @@ public:
/// \brief Get offset of \b this pointer relative to start of the containing data-type
///
/// \return the offset value in \e address \e units
int4 getPointerOffset(void) const { return AddrSpace::byteToAddressInt(offset, wordsize); }
int4 getAddressOffset(void) const { return AddrSpace::byteToAddressInt(offset, wordsize); }
/// \brief Get offset of \b this pointer relative to start of the containing data-type
///
/// \return the offset value in \e byte units
int4 getByteOffset(void) const { return offset; }
virtual void printRaw(ostream &s) const;
virtual int4 compare(const Datatype &op,int4 level) const;
virtual int4 compareDependency(const Datatype &op) const;
@ -803,6 +840,7 @@ public:
TypeUnion *getTypeUnion(const string &n); ///< Create an (empty) union
TypePartialUnion *getTypePartialUnion(TypeUnion *contain,int4 off,int4 sz); ///< Create a partial union
TypeEnum *getTypeEnum(const string &n); ///< Create an (empty) enumeration
TypePartialEnum *getTypePartialEnum(TypeEnum *contain,int4 off,int4 sz); ///< Create a partial enumeration
TypeSpacebase *getTypeSpacebase(AddrSpace *id,const Address &addr); ///< Create a "spacebase" type
TypeCode *getTypeCode(const PrototypePieces &proto); ///< Create a "function" datatype
Datatype *getTypedef(Datatype *ct,const string &name,uint8 id,uint4 format); ///< Create a new \e typedef data-type

View File

@ -175,10 +175,11 @@ OpCode TypeOp::floatSignManipulation(PcodeOp *op)
return CPUI_MAX;
}
/// \brief Propagate a dereferenced data-type up to its pointer data-type
/// \brief Propagate a dereferenced data-type up to its pointer data-type through a LOAD or STORE
///
/// Don't create more than a depth of 1, i.e. ptr->ptr
/// \param pt is the pointed-to data-type
/// \param t is the TypeFactory containing the data-types
/// \param dt is the pointed-to data-type
/// \param sz is the size of the pointer
/// \param wordsz is the wordsize associated with the pointer
/// \return the TypePointer object
@ -196,6 +197,36 @@ Datatype *TypeOp::propagateToPointer(TypeFactory *t,Datatype *dt,int4 sz,int4 wo
return t->getTypePointer(sz,dt,wordsz);
}
/// \brief Propagate a pointer data-type down to its element data-type through a LOAD or STORE
///
/// \param t is the TypeFactory containing the data-types
/// \param dt is the pointer data-type
/// \param sz is the size of the dereferenced pointer
/// \return the dereferenced data-type
Datatype *TypeOp::propagateFromPointer(TypeFactory *t,Datatype *dt,int4 sz)
{
if (dt->getMetatype() != TYPE_PTR)
return (Datatype *)0;
Datatype *ptrto = ((TypePointer *)dt)->getPtrTo();
if (ptrto->isVariableLength())
return (Datatype *)0;
if (ptrto->getSize() == sz)
return ptrto;
// If we reach here, there is a size mismatch between the pointer data-type and the dereferenced value.
// We only propagate (partial) enumerations in this case.
if (dt->isPointerRel()) {
TypePointerRel *ptrrel = (TypePointerRel *)dt;
Datatype *res = t->getExactPiece(ptrrel->getParent(), ptrrel->getByteOffset(), sz);
if (res != (Datatype *)0 && res->isEnumType())
return res;
}
else if (ptrto->isEnumType() && !ptrto->hasStripped()) {
return t->getTypePartialEnum((TypeEnum *)ptrto, 0, sz);
}
return (Datatype *)0;
}
/// \param t is the TypeFactory used to construct data-types
/// \param opc is the op-code value the new object will represent
/// \param n is the display name that will represent the op-code
@ -463,13 +494,8 @@ Datatype *TypeOpLoad::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,
AddrSpace *spc = op->getIn(0)->getSpaceFromConst();
newtype = propagateToPointer(tlst,alttype,outvn->getSize(),spc->getWordSize());
}
else if (alttype->getMetatype()==TYPE_PTR) {
newtype = ((TypePointer *)alttype)->getPtrTo();
if (newtype->getSize() != outvn->getSize() || newtype->isVariableLength()) // Size must be appropriate
newtype = (Datatype *)0;
}
else
newtype = (Datatype *)0; // Don't propagate anything
newtype = propagateFromPointer(tlst, alttype, outvn->getSize());
return newtype;
}
@ -538,13 +564,8 @@ Datatype *TypeOpStore::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn
AddrSpace *spc = op->getIn(0)->getSpaceFromConst();
newtype = propagateToPointer(tlst,alttype,outvn->getSize(),spc->getWordSize());
}
else if (alttype->getMetatype()==TYPE_PTR) {
newtype = ((TypePointer *)alttype)->getPtrTo();
if (newtype->getSize() != outvn->getSize() || newtype->isVariableLength())
newtype = (Datatype *)0;
}
else
newtype = (Datatype *)0; // Don't propagate anything
newtype = propagateFromPointer(tlst, alttype, outvn->getSize());
return newtype;
}
@ -933,7 +954,7 @@ Datatype *TypeOpEqual::propagateAcrossCompare(Datatype *alttype,TypeFactory *typ
}
else if (alttype->isPointerRel() && !outvn->isConstant()) {
TypePointerRel *relPtr = (TypePointerRel *)alttype;
if (relPtr->getParent()->getMetatype() == TYPE_STRUCT && relPtr->getPointerOffset() >= 0) {
if (relPtr->getParent()->getMetatype() == TYPE_STRUCT && relPtr->getByteOffset() >= 0) {
// If we know the pointer is in the middle of a structure, don't propagate across comparison operators
// as the two sides of the operator are likely to be different types , and the other side can also
// get data-type information from the structure pointer
@ -1383,7 +1404,7 @@ Datatype *TypeOpIntXor::getOutputToken(const PcodeOp *op,CastStrategy *castStrat
Datatype *TypeOpIntXor::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot)
{
if (!alttype->isPowerOfTwo()) {
if (!alttype->isEnumType()) {
if (alttype->getMetatype() != TYPE_FLOAT)
return (Datatype *)0;
if (floatSignManipulation(op) == CPUI_MAX)
@ -1416,7 +1437,7 @@ Datatype *TypeOpIntAnd::getOutputToken(const PcodeOp *op,CastStrategy *castStrat
Datatype *TypeOpIntAnd::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot)
{
if (!alttype->isPowerOfTwo()) {
if (!alttype->isEnumType()) {
if (alttype->getMetatype() != TYPE_FLOAT)
return (Datatype *)0;
if (floatSignManipulation(op) == CPUI_MAX)
@ -1449,7 +1470,7 @@ Datatype *TypeOpIntOr::getOutputToken(const PcodeOp *op,CastStrategy *castStrate
Datatype *TypeOpIntOr::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot)
{
if (!alttype->isPowerOfTwo()) return (Datatype *)0; // Only propagate flag enums
if (!alttype->isEnumType()) return (Datatype *)0; // Only propagate enums
Datatype *newtype;
if (invn->isSpacebase()) {
AddrSpace *spc = tlst->getArch()->getDefaultDataSpace();

View File

@ -181,6 +181,7 @@ public:
/// \brief Return the floating-point operation associated with the \e sign bit manipulation by the given PcodeOp
static OpCode floatSignManipulation(PcodeOp *op);
static Datatype *propagateToPointer(TypeFactory *t,Datatype *dt,int4 sz,int4 wordsz);
static Datatype *propagateFromPointer(TypeFactory *t,Datatype *dt,int4 sz);
};
// Major classes of operations

View File

@ -297,6 +297,27 @@ void HighVariable::transferPiece(HighVariable *tv2)
tv2->highflags &= ~(uint4)(intersectdirty | extendcoverdirty);
}
/// Except in specific circumstances, convert \b type into its stripped form.
void HighVariable::stripType(void) const
{
if (!type->hasStripped())
return;
if (type->getMetatype() == TYPE_PARTIALUNION) {
if (symbol != (Symbol *)0 && symboloffset != -1) {
type_metatype meta = symbol->getType()->getMetatype();
if (meta != TYPE_STRUCT && meta != TYPE_UNION) // If partial union does not have a bigger backing symbol
type = type->getStripped(); // strip the partial union
}
}
else if (type->isEnumType()) {
if (inst.size() != 1 || !inst[0]->isConstant()) // Only preserve partial enum on a constant
type = type->getStripped();
}
else
type = type->getStripped();
}
/// Only update if the cover is marked as \e dirty.
/// Merge the covers of all Varnode instances.
void HighVariable::updateInternalCover(void) const
@ -386,17 +407,7 @@ void HighVariable::updateType(void) const
vn = getTypeRepresentative();
type = vn->getType();
if (type->hasStripped()) {
if (type->getMetatype() == TYPE_PARTIALUNION) {
if (symbol != (Symbol *)0 && symboloffset != -1) {
type_metatype meta = symbol->getType()->getMetatype();
if (meta != TYPE_STRUCT && meta != TYPE_UNION) // If partial union does not have a bigger backing symbol
type = type->getStripped(); // strip the partial union
}
}
else
type = type->getStripped();
}
stripType();
// Update lock flags
flags &= ~Varnode::typelock;
if (vn->isTypeLock())
@ -549,17 +560,7 @@ void HighVariable::finalizeDatatype(TypeFactory *typeFactory)
if (tp == (Datatype *)0 || tp->getMetatype() == TYPE_UNKNOWN)
return;
type = tp;
if (type->hasStripped()) {
if (type->getMetatype() == TYPE_PARTIALUNION) {
if (symboloffset != -1) {
type_metatype meta = symbol->getType()->getMetatype();
if (meta != TYPE_STRUCT && meta != TYPE_UNION) // If partial union does not have a bigger backing symbol
type = type->getStripped(); // strip the partial union
}
}
else
type = type->getStripped();
}
stripType();
highflags |= type_finalized;
}

View File

@ -167,6 +167,7 @@ private:
void symbolDirty(void) const { highflags |= symboldirty; } ///< Mark the symbol as \e dirty
void setUnmerged(void) const { highflags |= unmerged; } ///< Mark \b this as having merge problems
bool isCoverDirty(void) const; ///< Is the cover returned by getCover() up-to-date
void stripType(void) const; ///< Take the stripped form of the current data-type.
public:
HighVariable(Varnode *vn); ///< Construct a HighVariable with a single member Varnode
~HighVariable(void); ///< Destructor

View File

@ -0,0 +1,108 @@
<decompilertest>
<binaryimage arch="x86:LE:64:default:gcc">
<!--
Functions that read enum values and compare with constant values that should be printed by name.
-->
<bytechunk space="ram" offset="0x100000" readonly="true">
4883ec184889e7e8f40f0000f6442408
4175054883c418c3bf00000000e8e60f
0000ebef4883ec184889e7e8d00f0000
f744240c0003000075054883c418c3bf
00000000e8bf0f0000ebef
</bytechunk>
<bytechunk space="ram" offset="0x100065" readonly="true">
f647082c7501c34883ec08
bf02000000e88e0f00004883c408c3f7
470c571300007501c34883ec08bf0300
0000e8710f00004883c408c3
</bytechunk>
<bytechunk space="ram" offset="0x1000d3" readonly="true">
48817f08000810007401c34883
ec08bf06000000e81c0f00004883c408
c3
</bytechunk>
<symbol space="ram" offset="0x100000" name="stackenumlow"/>
<symbol space="ram" offset="0x100024" name="stackenumhigh"/>
<symbol space="ram" offset="0x100065" name="ptrenumlow"/>
<symbol space="ram" offset="0x10007f" name="ptrenumhigh"/>
<symbol space="ram" offset="0x1000d3" name="ptrenumequal"/>
<symbol space="ram" offset="0x101000" name="setStruct"/>
</binaryimage>
<script>
<com>parse line enum flags {
FLAG_1=1,
FLAG_2 = 2,
FLAG_4 = 4,
FLAG_8 = 8,
FLAG_10 = 0x10,
FLAG_20 = 0x20,
FLAG_40 = 0x40,
FLAG_80 = 0x80,
FLAG_100 = 0x100,
FLAG_200 = 0x200,
FLAG_400 = 0x400,
FLAG_800 = 0x800,
FLAG_1000 = 0x1000,
FLAG_2000 = 0x2000,
FLAG_4000 = 0x4000,
FLAG_8000 = 0x8000,
FLAG_10000 = 0x10000,
FLAG_20000 = 0x20000,
FLAG_40000 = 0x40000,
FLAG_80000 = 0x80000,
FLAG_100000 = 0x100000,
FLAG_200000 = 0x200000,
FLAG_400000 = 0x400000,
FLAG_800000 = 0x800000,
HIGH_1 = 0x100000000,
HIGH_2 = 0x200000000,
HIGH_4 = 0x400000000,
HIGH_8 = 0x800000000,
HIGH_10 = 0x1000000000,
HIGH_20 = 0x2000000000,
HIGH_40 = 0x4000000000,
HIGH_80 = 0x8000000000,
HIGH_100 = 0x10000000000,
HIGH_200 = 0x20000000000,
HIGH_400 = 0x40000000000,
HIGH_800 = 0x80000000000,
HIGH_1000 = 0x100000000000,
HIGH_2000 = 0x200000000000,
HIGH_4000 = 0x400000000000,
HIGH_8000 = 0x800000000000,
HIGH_10000 = 0x1000000000000,
HIGH_20000 = 0x2000000000000,
HIGH_40000 = 0x4000000000000,
HIGH_80000 = 0x8000000000000,
HIGH_100000 = 0x10000000000000,
HIGH_200000 = 0x20000000000000,
HIGH_400000 = 0x40000000000000,
HIGH_800000 = 0x80000000000000 };</com>
<com>parse line struct enumstruct { int4 a; int4 b; flags flagfield; };</com>
<com>parse line extern void setStruct(enumstruct *ptr);</com>
<com>parse line extern void ptrenumlow(enumstruct *ptr);</com>
<com>parse line extern void ptrenumhigh(enumstruct *ptrhigh);</com>
<com>parse line extern void ptrenumequal(enumstruct *ptrequal);</com>
<com>lo fu stackenumlow</com>
<com>decompile</com>
<com>print C</com>
<com>lo fu stackenumhigh</com>
<com>decompile</com>
<com>print C</com>
<com>lo fu ptrenumlow</com>
<com>decompile</com>
<com>print C</com>
<com>lo fu ptrenumhigh</com>
<com>decompile</com>
<com>print C</com>
<com>lo fu ptrenumequal</com>
<com>decompile</com>
<com>print C</com>
<com>quit</com>
</script>
<stringmatch name="Enum Reading #1" min="1" max="1">Stack_18\.flagfield &amp; \(FLAG_40\|FLAG_1\)\) .= 0\)</stringmatch>
<stringmatch name="Enum Reading #2" min="1" max="1">Stack_18\.flagfield\._4_4_ &amp; \(HIGH_200\|HIGH_100\) &gt;&gt; 0x20\) .= 0\)</stringmatch>
<stringmatch name="Enum Reading #3" min="1" max="1">ptr-&gt;flagfield &amp; \(FLAG_20\|FLAG_8\|FLAG_4\)\) .= 0\)</stringmatch>
<stringmatch name="Enum Reading #4" min="1" max="1">if \(\(ptrhigh-&gt;flagfield &amp; \(HIGH_1000\|HIGH_200\|HIGH_100\|HIGH_40\|HIGH_10\|HIGH_4\|HIGH_2\|HIGH_1\)\) .= 0</stringmatch>
<stringmatch name="Enum Reading #5" min="1" max="1">if \(ptrequal-&gt;flagfield .= \(FLAG_100000\|FLAG_800\)\)</stringmatch>
</decompilertest>

View File

@ -212,4 +212,52 @@ TEST(cast_integertoken) {
ASSERT(!longPrinted(CPUI_INT_RIGHT,parse("uint8"),0x100000000));
}
TEST(enum_matching) {
TypeTestEnvironment::build();
TypeEnum *enum3 = (TypeEnum *)parse("enum enum3 { ZERO=0, ONE=1, TWO=2, FOUR=4, EIGHT=8 }");
TypeEnum::Representation rep;
enum3->getMatches(5, rep);
ASSERT(rep.matchname.size() == 2);
ASSERT(rep.matchname[0] == "FOUR");
ASSERT(rep.matchname[1] == "ONE");
ASSERT(!rep.complement);
rep.matchname.clear();
enum3->getMatches(0xfffffffffffffff7,rep);
ASSERT(rep.matchname.size() == 1);
ASSERT(rep.matchname[0] == "EIGHT");
ASSERT(rep.complement);
rep.matchname.clear();
rep.complement = false;
enum3->getMatches(0,rep);
ASSERT(rep.matchname.size() == 1);
ASSERT(rep.matchname[0] == "ZERO");
ASSERT(!rep.complement);
rep.matchname.clear();
enum3->getMatches(0x10, rep);
ASSERT(rep.matchname.size() == 0);
ASSERT(!rep.complement);
}
TEST(enum_matching2) {
TypeTestEnvironment::build();
TypeEnum *enum4 = (TypeEnum *)parse("enum enum4 { ZERO=0, ONE=1, TWO=2, FOUR=4, SIX=6, EIGHT=8, ELEVEN=11 }");
TypeEnum::Representation rep;
enum4->getMatches(12,rep);
ASSERT(rep.matchname.size()==2);
ASSERT(rep.matchname[0] == "EIGHT");
ASSERT(rep.matchname[1] == "FOUR");
ASSERT(!rep.complement);
rep.matchname.clear();
enum4->getMatches(7,rep);
ASSERT(rep.matchname.size()==2);
ASSERT(rep.matchname[0] == "SIX");
ASSERT(rep.matchname[1] == "ONE");
ASSERT(!rep.complement);
rep.matchname.clear();
enum4->getMatches(11,rep);
ASSERT(rep.matchname.size()==1);
ASSERT(rep.matchname[0] == "ELEVEN");
ASSERT(!rep.complement);
}
} // End namespace ghidra

View File

@ -114,7 +114,7 @@ public record AttributeId(String name, int id) {
public static final AttributeId ATTRIB_ARRAYSIZE = new AttributeId("arraysize", 48);
public static final AttributeId ATTRIB_CHAR = new AttributeId("char", 49);
public static final AttributeId ATTRIB_CORE = new AttributeId("core", 50);
public static final AttributeId ATTRIB_ENUM = new AttributeId("enum", 51);
// public static final AttributeId ATTRIB_ENUM = new AttributeId("enum", 51); // deprecated
public static final AttributeId ATTRIB_INCOMPLETE = new AttributeId("incomplete", 52);
// public static final AttributeId ATTRIB_ENUMSIZE = new AttributeId("enumsize", 53); // deprecated
// public static final AttributeId ATTRIB_INTSIZE = new AttributeId("intsize", 54); // deprecated

View File

@ -278,6 +278,13 @@ public class PcodeDataTypeManager {
decoder.closeElement(el);
return new PartialUnion(progDataTypes, dt, offset, size);
}
else if (meta.equals("partenum")) {
int size = (int) decoder.readSignedInteger(ATTRIB_SIZE);
// int offset = (int) decoder.readSignedInteger(ATTRIB_OFFSET);
// DataType dt = decodeDataType(decoder);
decoder.closeElementSkipping(el);
return AbstractIntegerDataType.getUnsignedDataType(size, progDataTypes);
}
else { // We typically reach here if the decompiler invents a new type
// probably an unknown with a non-standard size
int size = (int) decoder.readSignedInteger(ATTRIB_SIZE);
@ -541,11 +548,10 @@ public class PcodeDataTypeManager {
private void encodeEnum(Encoder encoder, Enum type, int size) throws IOException {
encoder.openElement(ELEM_TYPE);
encodeNameIdAttributes(encoder, type);
String metatype = type.isSigned() ? "int" : "uint";
String metatype = type.isSigned() ? "enum_int" : "enum_uint";
String[] names = type.getNames();
encoder.writeString(ATTRIB_METATYPE, metatype);
encoder.writeSignedInteger(ATTRIB_SIZE, type.getLength());
encoder.writeBool(ATTRIB_ENUM, true);
for (String name : names) {
encoder.openElement(ELEM_VAL);
encoder.writeString(ATTRIB_NAME, name);