mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-08-18 05:47:55 +08:00
GP-7126 RuleAndStructure
This commit is contained in:
@@ -6075,6 +6075,7 @@ void ActionDatabase::universalAction(Architecture *conf)
|
||||
actcleanup->addRule( new RulePtrsubCharConstant("cleanup") );
|
||||
actcleanup->addRule( new RuleExtensionPush("cleanup") );
|
||||
actcleanup->addRule( new RulePieceStructure("cleanup") );
|
||||
actcleanup->addRule( new RuleAndStructure("cleanup") );
|
||||
actcleanup->addRule( new RuleSplitCopy("splitcopy") );
|
||||
actcleanup->addRule( new RuleSplitLoad("splitpointer") );
|
||||
actcleanup->addRule( new RuleSplitStore("splitpointer") );
|
||||
|
||||
@@ -7685,6 +7685,63 @@ int4 RulePieceStructure::applyOp(PcodeOp *op,Funcdata &data)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// \class RuleAndStructure
|
||||
/// \brief Convert `and(x,#mask) => zext(sub(x,#c)` when the mask corresponds to a field access
|
||||
void RuleAndStructure::getOpList(vector<uint4> &oplist) const
|
||||
|
||||
{
|
||||
oplist.push_back(CPUI_INT_AND);
|
||||
}
|
||||
|
||||
int4 RuleAndStructure::applyOp(PcodeOp *op,Funcdata &data)
|
||||
|
||||
{
|
||||
Varnode *cvn = op->getIn(1);
|
||||
if (!cvn->isConstant()) return 0;
|
||||
Varnode *vn = op->getIn(0);
|
||||
Datatype *baseType = vn->getTypeReadFacing(op);
|
||||
type_metatype meta = baseType->getMetatype();
|
||||
if (meta != TYPE_STRUCT && meta != TYPE_PARTIALSTRUCT && meta != TYPE_ARRAY)
|
||||
return 0;
|
||||
uintb off = cvn->getOffset();
|
||||
int4 count = sizeof(uintb)*8 - count_leading_zeros(off);
|
||||
int4 size = count / 8; // Number of bytes being masked off
|
||||
if (count % 8 != 0)
|
||||
size += 1;
|
||||
int8 structOff = vn->getSpace()->isBigEndian() ? vn->getSize() - size : 0;
|
||||
Datatype *ct = baseType->findSmallestContainer(structOff, size, &structOff);
|
||||
if (ct->getSize() >= vn->getSize() || structOff != 0)
|
||||
return 0;
|
||||
PcodeOp *subOp = data.newOp(2, op->getAddr());
|
||||
data.opSetOpcode(subOp, CPUI_SUBPIECE);
|
||||
data.opSetInput(subOp,data.newConstant(4, 0),1);
|
||||
data.opMarkSpecialPrint(subOp); // Mark SUBPIECE as a field extraction
|
||||
Address addr = op->getOut()->getAddr();
|
||||
if (addr.isBigEndian())
|
||||
addr = addr + (vn->getSize() - ct->getSize());
|
||||
addr.renormalize(vn->getSize()); // Allow for possible join address
|
||||
Varnode *outvn = data.newVarnodeOut(ct->getSize(), addr, subOp);
|
||||
outvn->updateType(ct);
|
||||
if (calc_mask(size) == off) {
|
||||
data.opRemoveInput(op, 1);
|
||||
data.opSetInput(op, outvn, 0);
|
||||
data.opSetOpcode(op, CPUI_INT_ZEXT);
|
||||
data.opSetInput(subOp,vn,0);
|
||||
data.opInsertBefore(subOp, op);
|
||||
}
|
||||
else {
|
||||
PcodeOp *newZext = data.newOp(1, op->getAddr());
|
||||
data.opSetOpcode(newZext, CPUI_INT_ZEXT);
|
||||
Varnode *outzext = data.newUniqueOut(vn->getSize(), newZext);
|
||||
data.opSetInput(op, outzext, 0);
|
||||
data.opSetInput(subOp, vn, 0);
|
||||
data.opSetInput(newZext,outvn,0);
|
||||
data.opInsertBefore(newZext,op);
|
||||
data.opInsertBefore(subOp,newZext);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// \class RuleSubNormal
|
||||
/// \brief Pull-back SUBPIECE through INT_RIGHT and INT_SRIGHT
|
||||
///
|
||||
|
||||
@@ -1212,6 +1212,17 @@ public:
|
||||
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
|
||||
};
|
||||
|
||||
class RuleAndStructure : public Rule {
|
||||
public:
|
||||
RuleAndStructure(const string &g) : Rule( g, 0, "andstructure") {} ///< Constructor
|
||||
virtual Rule *clone(const ActionGroupList &grouplist) const {
|
||||
if (!grouplist.contains(getGroup())) return (Rule *)0;
|
||||
return new RuleAndStructure(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
|
||||
|
||||
@@ -3032,7 +3032,22 @@ int4 RuleDumptyHumpLate::applyOp(PcodeOp *op,Funcdata &data)
|
||||
Varnode *vn = op->getIn(0);
|
||||
if (!vn->isWritten()) return 0;
|
||||
PcodeOp *pieceOp = vn->getDef();
|
||||
if (pieceOp->code() != CPUI_PIECE) return 0;
|
||||
OpCode opc = pieceOp->code();
|
||||
if (opc == CPUI_SUBPIECE) {
|
||||
// SUB(SUB(base,#c),#d) => SUB(base,#c+#d)
|
||||
Varnode *base = pieceOp->getIn(0);
|
||||
data.opSetInput(op,base,0);
|
||||
uintb trunc = op->getIn(1)->getOffset() + pieceOp->getIn(1)->getOffset();
|
||||
if (trunc != op->getIn(1)->getOffset())
|
||||
data.opSetInput(op,data.newConstant(4, trunc),1);
|
||||
if (vn->hasNoDescend() && !vn->isAutoLive()) {
|
||||
vector<PcodeOp *> scratch;
|
||||
data.opDestroyRecursive(pieceOp, scratch);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
else if (opc != CPUI_PIECE)
|
||||
return 0;
|
||||
Varnode *out = op->getOut();
|
||||
int4 outSize = out->getSize();
|
||||
int4 trunc = (int4)op->getIn(1)->getOffset();
|
||||
|
||||
@@ -360,6 +360,7 @@ public:
|
||||
/// Simplify expressions like:
|
||||
/// - `sub( concat(V,W), 0) => W`
|
||||
/// - `sub( concat(V,W), c) => V`
|
||||
/// - `sub( sub(V, c), d) => SUB(V,#c+#d)`
|
||||
///
|
||||
/// preserving the data-types and removing the SUBPIECE and PIECE operations that are discarded.
|
||||
class RuleDumptyHumpLate : public Rule {
|
||||
|
||||
@@ -589,6 +589,29 @@ bool Datatype::testForArraySlack(int8 off)
|
||||
return nearestArrayedComponentBackward(off, comp);
|
||||
}
|
||||
|
||||
/// Return the component data-type, which may be \b this if there is no smaller component, and pass back
|
||||
/// the relative offset of the start of the range into the returned component.
|
||||
/// \param off is the starting byte offset of the given range, within \b this
|
||||
/// \param sz is the number of bytes in the range
|
||||
/// \param newoff is used to pass back the relative offset into the returned component
|
||||
/// \return the component data-type contain the range
|
||||
Datatype *Datatype::findSmallestContainer(int8 off,int8 sz,int8 *newoff)
|
||||
|
||||
{
|
||||
Datatype *res = this;
|
||||
Datatype *next = res;
|
||||
int8 curOff = off;
|
||||
for(;;) {
|
||||
next = next->getSubType(curOff, &curOff);
|
||||
if (next == (Datatype *)0) break; // No smaller component
|
||||
if (curOff + sz > next->getSize()) break; // Next component down does not contain
|
||||
res = next;
|
||||
off = curOff;
|
||||
}
|
||||
*newoff = off;
|
||||
return res;
|
||||
}
|
||||
|
||||
/// Called only if the \b typedefImm field is non-null. Encode the data-type to the
|
||||
/// stream as a simple \<typedef> element including only the names and ids of \b this and
|
||||
/// the data-type it typedefs.
|
||||
|
||||
@@ -312,6 +312,7 @@ public:
|
||||
bool isPrimitiveWhole(void) const; ///< Is \b this made up of a single primitive
|
||||
bool nearestArrayedComponent(int8 off,uint4 arrayHint,int8 *newoff) const;
|
||||
bool testForArraySlack(int8 off); ///< Test if an \e out-of-bounds offset makes sense as array slack
|
||||
Datatype *findSmallestContainer(int8 off,int8 sz,int8 *newoff); ///< Find the smallest component containing the given range
|
||||
|
||||
static uint4 encodeIntegerFormat(const string &val);
|
||||
static string decodeIntegerFormat(uint4 val);
|
||||
|
||||
@@ -308,8 +308,8 @@ void HighVariable::stripType(void) const
|
||||
if (meta == TYPE_PARTIALUNION || meta == TYPE_PARTIALSTRUCT) {
|
||||
if (symbol != (Symbol *)0 && symboloffset != -1) { // If there is a bigger backing symbol
|
||||
type_metatype submeta = symbol->getType()->getMetatype();
|
||||
if (submeta == TYPE_STRUCT || submeta == TYPE_UNION)
|
||||
return; // Don't strip the partial union
|
||||
if (submeta == TYPE_STRUCT || submeta == TYPE_UNION || submeta == TYPE_ARRAY)
|
||||
return; // Don't strip the partial
|
||||
}
|
||||
}
|
||||
else if (type->isEnumType()) {
|
||||
|
||||
Reference in New Issue
Block a user