mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 10:49:34 +02:00
GP-4782 Refactor RulePtrsubUndo
This commit is contained in:
parent
be305db930
commit
34adcff830
7 changed files with 355 additions and 80 deletions
|
@ -4,9 +4,9 @@
|
|||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
@ -5920,30 +5920,30 @@ bool AddTreeState::spanAddTree(PcodeOp *op,uint8 treeCoeff)
|
|||
void AddTreeState::calcSubtype(void)
|
||||
|
||||
{
|
||||
if (size == 0 || nonmultsum < size)
|
||||
offset = nonmultsum;
|
||||
uint8 tmpoff = (multsum + nonmultsum) & ptrmask;
|
||||
if (size == 0 || tmpoff < size)
|
||||
offset = tmpoff;
|
||||
else {
|
||||
// For a sum that falls completely outside the data-type, there is presumably some
|
||||
// type of constant term added to an array index either at the current level or lower.
|
||||
// If we knew here whether an array of the baseType was possible we could make a slightly
|
||||
// better decision.
|
||||
intb snonmult = sign_extend(nonmultsum,ptrsize*8-1);
|
||||
snonmult = snonmult % size;
|
||||
if (snonmult >= 0)
|
||||
intb stmpoff = sign_extend(tmpoff,ptrsize*8-1);
|
||||
stmpoff = stmpoff % size;
|
||||
if (stmpoff >= 0)
|
||||
// We assume the sum is big enough it represents an array index at this level
|
||||
offset = (uint8)snonmult;
|
||||
offset = (uint8)stmpoff;
|
||||
else {
|
||||
// For a negative sum, if the baseType is a structure and there is array hints,
|
||||
// we assume the sum is an array index at a lower level
|
||||
if (baseType->getMetatype() == TYPE_STRUCT && biggestNonMultCoeff != 0)
|
||||
offset = nonmultsum;
|
||||
if (baseType->getMetatype() == TYPE_STRUCT && biggestNonMultCoeff != 0 && multsum == 0)
|
||||
offset = tmpoff;
|
||||
else
|
||||
offset = (uint8)(snonmult + size);
|
||||
offset = (uint8)(stmpoff + size);
|
||||
}
|
||||
}
|
||||
correct = nonmultsum - offset;
|
||||
nonmultsum = offset;
|
||||
multsum = (multsum + correct) & ptrmask; // Some extra multiples of size
|
||||
correct = nonmultsum; // Non-multiple constants are double counted, correct in final sum
|
||||
multsum = (tmpoff - offset) & ptrmask; // Some extra multiples of size
|
||||
if (nonmult.empty()) {
|
||||
if ((multsum == 0) && multiple.empty()) { // Is there anything at all
|
||||
valid = false;
|
||||
|
@ -5952,31 +5952,33 @@ void AddTreeState::calcSubtype(void)
|
|||
isSubtype = false; // There are no offsets INTO the pointer
|
||||
}
|
||||
else if (baseType->getMetatype() == TYPE_SPACEBASE) {
|
||||
int8 nonmultbytes = AddrSpace::addressToByteInt(nonmultsum,ct->getWordSize()); // Convert to bytes
|
||||
int8 offsetbytes = AddrSpace::addressToByteInt(offset,ct->getWordSize()); // Convert to bytes
|
||||
int8 extra;
|
||||
// Get offset into mapped variable
|
||||
if (!hasMatchingSubType(nonmultbytes, biggestNonMultCoeff, &extra)) {
|
||||
if (!hasMatchingSubType(offsetbytes, biggestNonMultCoeff, &extra)) {
|
||||
valid = false; // Cannot find mapped variable but nonmult is non-empty
|
||||
return;
|
||||
}
|
||||
extra = AddrSpace::byteToAddress(extra, ct->getWordSize()); // Convert back to address units
|
||||
offset = (nonmultsum - extra) & ptrmask;
|
||||
offset = (offset - extra) & ptrmask;
|
||||
correct = (correct - extra) & ptrmask;
|
||||
isSubtype = true;
|
||||
}
|
||||
else if (baseType->getMetatype() == TYPE_STRUCT) {
|
||||
intb snonmult = sign_extend(nonmultsum,ptrsize*8-1);
|
||||
int8 nonmultbytes = AddrSpace::addressToByteInt(snonmult,ct->getWordSize()); // Convert to bytes
|
||||
intb soffset = sign_extend(offset,ptrsize*8-1);
|
||||
int8 offsetbytes = AddrSpace::addressToByteInt(soffset,ct->getWordSize()); // Convert to bytes
|
||||
int8 extra;
|
||||
// Get offset into field in structure
|
||||
if (!hasMatchingSubType(nonmultbytes, biggestNonMultCoeff, &extra)) {
|
||||
if (nonmultbytes < 0 || nonmultbytes >= baseType->getSize()) { // Compare as bytes! not address units
|
||||
if (!hasMatchingSubType(offsetbytes, biggestNonMultCoeff, &extra)) {
|
||||
if (offsetbytes < 0 || offsetbytes >= baseType->getSize()) { // Compare as bytes! not address units
|
||||
valid = false; // Out of structure's bounds
|
||||
return;
|
||||
}
|
||||
extra = 0; // No field, but pretend there is something there
|
||||
}
|
||||
extra = AddrSpace::byteToAddressInt(extra, ct->getWordSize()); // Convert back to address units
|
||||
offset = (nonmultsum - extra) & ptrmask;
|
||||
offset = (offset - extra) & ptrmask;
|
||||
correct = (correct - extra) & ptrmask;
|
||||
if (pRelType != (TypePointerRel *)0 && offset == pRelType->getPointerOffset()) {
|
||||
// offset falls within basic ptrto
|
||||
if (!pRelType->evaluateThruParent(0)) { // If we are not representing offset 0 through parent
|
||||
|
@ -5988,12 +5990,31 @@ void AddTreeState::calcSubtype(void)
|
|||
}
|
||||
else if (baseType->getMetatype() == TYPE_ARRAY) {
|
||||
isSubtype = true;
|
||||
correct = (correct - offset) & ptrmask;
|
||||
offset = 0;
|
||||
}
|
||||
else {
|
||||
// No struct or array, but nonmult is non-empty
|
||||
valid = false; // There is substructure we don't know about
|
||||
}
|
||||
if (pRelType != (const TypePointerRel *)0) {
|
||||
int4 ptrOff = ((TypePointerRel *)ct)->getPointerOffset();
|
||||
offset = (offset - ptrOff) & ptrmask;
|
||||
correct = (correct - ptrOff) & ptrmask;
|
||||
}
|
||||
}
|
||||
|
||||
/// The data-type from the pointer input (of either a PTRSUB or PTRADD) is propagated to the
|
||||
/// output of the PcodeOp.
|
||||
/// \param op is the given PcodeOp
|
||||
void AddTreeState::assignPropagatedType(PcodeOp *op)
|
||||
|
||||
{
|
||||
Varnode *vn = op->getIn(0);
|
||||
Datatype *inType = vn->getTypeReadFacing(op);
|
||||
Datatype *newType = op->getOpcode()->propagateType(inType, op, vn, op->getOut(), 0, -1);
|
||||
if (newType != (Datatype *)0)
|
||||
op->getOut()->updateType(newType, false, false);
|
||||
}
|
||||
|
||||
/// Construct part of the tree that sums to a multiple of the base data-type size.
|
||||
|
@ -6037,7 +6058,6 @@ Varnode *AddTreeState::buildMultiples(void)
|
|||
Varnode *AddTreeState::buildExtra(void)
|
||||
|
||||
{
|
||||
correct = correct+offset; // Total correction that needs to be made
|
||||
Varnode *resNode = (Varnode *)0;
|
||||
for(int4 i=0;i<nonmult.size();++i) {
|
||||
Varnode *vn = nonmult[i];
|
||||
|
@ -6138,11 +6158,6 @@ bool AddTreeState::apply(void)
|
|||
void AddTreeState::buildTree(void)
|
||||
|
||||
{
|
||||
if (pRelType != (const TypePointerRel *)0) {
|
||||
int4 ptrOff = ((TypePointerRel *)ct)->getPointerOffset();
|
||||
offset -= ptrOff;
|
||||
offset &= ptrmask;
|
||||
}
|
||||
Varnode *multNode = buildMultiples();
|
||||
Varnode *extraNode = buildExtra();
|
||||
PcodeOp *newop = (PcodeOp *)0;
|
||||
|
@ -6152,6 +6167,8 @@ void AddTreeState::buildTree(void)
|
|||
newop = data.newOpBefore(baseOp,CPUI_PTRADD,ptr,multNode,data.newConstant(ptrsize,size));
|
||||
if (ptr->getType()->needsResolution())
|
||||
data.inheritResolution(ptr->getType(),newop, 0, baseOp, baseSlot);
|
||||
if (data.isTypeRecoveryExceeded())
|
||||
assignPropagatedType(newop);
|
||||
multNode = newop->getOut();
|
||||
}
|
||||
else
|
||||
|
@ -6162,6 +6179,8 @@ void AddTreeState::buildTree(void)
|
|||
newop = data.newOpBefore(baseOp,CPUI_PTRSUB,multNode,data.newConstant(ptrsize,offset));
|
||||
if (multNode->getType()->needsResolution())
|
||||
data.inheritResolution(multNode->getType(),newop, 0, baseOp, baseSlot);
|
||||
if (data.isTypeRecoveryExceeded())
|
||||
assignPropagatedType(newop);
|
||||
if (size != 0)
|
||||
newop->setStopTypePropagation();
|
||||
multNode = newop->getOut();
|
||||
|
@ -6555,6 +6574,8 @@ int4 RulePtraddUndo::applyOp(PcodeOp *op,Funcdata &data)
|
|||
return 1;
|
||||
}
|
||||
|
||||
const int4 RulePtrsubUndo::DEPTH_LIMIT = 8;
|
||||
|
||||
/// \class RulePtrsubUndo
|
||||
/// \brief Remove PTRSUB operations with mismatched data-type information
|
||||
///
|
||||
|
@ -6567,17 +6588,204 @@ void RulePtrsubUndo::getOpList(vector<uint4> &oplist) const
|
|||
oplist.push_back(CPUI_PTRSUB);
|
||||
}
|
||||
|
||||
/// \brief Recursively search for additive constants and multiplicative constants
|
||||
///
|
||||
/// Walking backward from the given Varnode, search for constants being added in and return
|
||||
/// the sum of all the constants. Additionally pass back the biggest constant coefficient, for any term
|
||||
/// formed with INT_MULT.
|
||||
/// \param vn is the given root Varnode of the additive tree
|
||||
/// \param multiplier will hold the biggest constant coefficient
|
||||
/// \param maxLevel is the maximum depth to search in the tree
|
||||
/// \return the sum of all constants in the additive expression
|
||||
int8 RulePtrsubUndo::getConstOffsetBack(Varnode *vn,int8 &multiplier,int4 maxLevel)
|
||||
|
||||
{
|
||||
multiplier = 1;
|
||||
int8 submultiplier;
|
||||
if (vn->isConstant())
|
||||
return vn->getOffset();
|
||||
if (!vn->isWritten())
|
||||
return 0;
|
||||
maxLevel -= 1;
|
||||
if (maxLevel < 0)
|
||||
return 0;
|
||||
PcodeOp *op = vn->getDef();
|
||||
OpCode opc = op->code();
|
||||
int8 retval = 0;
|
||||
if (opc == CPUI_INT_ADD) {
|
||||
retval += getConstOffsetBack(op->getIn(0),submultiplier,maxLevel);
|
||||
if (submultiplier > multiplier)
|
||||
multiplier = submultiplier;
|
||||
retval += getConstOffsetBack(op->getIn(1), submultiplier, maxLevel);
|
||||
if (submultiplier > multiplier)
|
||||
multiplier = submultiplier;
|
||||
}
|
||||
else if (opc == CPUI_INT_MULT) {
|
||||
Varnode *cvn = op->getIn(1);
|
||||
if (!cvn->isConstant()) return 0;
|
||||
multiplier = cvn->getOffset();
|
||||
getConstOffsetBack(op->getIn(0), submultiplier, maxLevel);
|
||||
multiplier *= submultiplier; // Only contribute to the multiplier
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/// \brief Collect constants and the biggest multiplier in the given PTRSUB expression.
|
||||
///
|
||||
/// Walking the additive expression (INT_ADD, PTRADD, and other PTRSUBs) and calculate any additional
|
||||
/// constant value being added to the PTRSUB. Additionally pass back the biggest constant coefficient of any
|
||||
/// multiplicative term in the expression.
|
||||
/// \param op is the given PTRSUB
|
||||
/// \param multiplier will hold the biggest multiplicative coefficient
|
||||
int8 RulePtrsubUndo::getExtraOffset(PcodeOp *op,int8 &multiplier)
|
||||
|
||||
{
|
||||
int8 extra = 0;
|
||||
multiplier = 1;
|
||||
int8 submultiplier;
|
||||
Varnode *outvn = op->getOut();
|
||||
op = outvn->loneDescend();
|
||||
while(op != (PcodeOp *)0) {
|
||||
OpCode opc = op->code();
|
||||
if (opc == CPUI_INT_ADD) {
|
||||
int4 slot = op->getSlot(outvn);
|
||||
extra += getConstOffsetBack(op->getIn(1-slot),submultiplier,DEPTH_LIMIT); // Get any constants from other input
|
||||
if (submultiplier > multiplier)
|
||||
multiplier = submultiplier;
|
||||
}
|
||||
else if (opc == CPUI_PTRSUB) {
|
||||
extra += op->getIn(1)->getOffset();
|
||||
}
|
||||
else if (opc == CPUI_PTRADD) {
|
||||
if (op->getIn(0) != outvn) break;
|
||||
int8 ptraddmult = op->getIn(2)->getOffset();
|
||||
Varnode *invn = op->getIn(1);
|
||||
if (invn->isConstant()) // Only contribute to the extra
|
||||
extra += ptraddmult * (int8)invn->getOffset(); // if the index is constant
|
||||
getConstOffsetBack(invn,submultiplier,DEPTH_LIMIT); // otherwise just contribute to multiplier
|
||||
submultiplier *= ptraddmult;
|
||||
if (submultiplier > multiplier)
|
||||
multiplier = submultiplier;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
outvn = op->getOut();
|
||||
op = outvn->loneDescend();
|
||||
}
|
||||
extra = sign_extend(extra, 8*outvn->getSize()-1);
|
||||
extra &= calc_mask(outvn->getSize());
|
||||
return extra;
|
||||
}
|
||||
|
||||
/// \brief Remove any constants in the additive expression rooted at the given PcodeOp
|
||||
///
|
||||
/// Walking recursively through the expression, any INT_ADD with a constant input is converted to
|
||||
/// a COPY. The INT_ADD must only contribute to the root expression.
|
||||
/// \param op is the given root PcodeOp
|
||||
/// \param slot is the input slot to walk back from
|
||||
/// \param maxLevel is the maximum depth to recurse
|
||||
/// \param data is the function containing the expression
|
||||
/// \return the sum of all constants that are removed
|
||||
int8 RulePtrsubUndo::removeLocalAddRecurse(PcodeOp *op,int4 slot,int4 maxLevel,Funcdata &data)
|
||||
|
||||
{
|
||||
Varnode *vn = op->getIn(slot);
|
||||
if (!vn->isWritten())
|
||||
return 0;
|
||||
if (vn->loneDescend() != op)
|
||||
return 0; // Varnode must not be used anywhere else
|
||||
maxLevel -= 1;
|
||||
if (maxLevel < 0)
|
||||
return 0;
|
||||
op = vn->getDef();
|
||||
int8 retval = 0;
|
||||
if (op->code() == CPUI_INT_ADD) {
|
||||
if (op->getIn(1)->isConstant()) {
|
||||
retval += (int8)op->getIn(1)->getOffset();
|
||||
data.opRemoveInput(op, 1);
|
||||
data.opSetOpcode(op, CPUI_COPY);
|
||||
}
|
||||
else {
|
||||
retval += removeLocalAddRecurse(op, 0, maxLevel, data);
|
||||
retval += removeLocalAddRecurse(op, 1, maxLevel, data);
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/// \brief Remove constants in the additive expression involving the given Varnode
|
||||
///
|
||||
/// Any additional PTRADD, PTRSUB, or INT_ADD that uses the Varnode and adds a constant is converted
|
||||
/// to a COPY. Additionally any other INT_ADD involved in the expression that adds a constant is
|
||||
/// also converted to COPY.
|
||||
/// \param vn is the given Varnode
|
||||
/// \param data is the function containing the expression
|
||||
/// \return the sum of all constants that are removed
|
||||
int8 RulePtrsubUndo::removeLocalAdds(Varnode *vn,Funcdata &data)
|
||||
|
||||
{
|
||||
int8 extra = 0;
|
||||
PcodeOp *op = vn->loneDescend();
|
||||
while(op != (PcodeOp *)0) {
|
||||
OpCode opc = op->code();
|
||||
if (opc == CPUI_INT_ADD) {
|
||||
int4 slot = op->getSlot(vn);
|
||||
if (slot == 0 && op->getIn(1)->isConstant()) {
|
||||
extra += (int8)op->getIn(1)->getOffset();
|
||||
data.opRemoveInput(op, 1);
|
||||
data.opSetOpcode(op, CPUI_COPY);
|
||||
}
|
||||
else {
|
||||
extra += removeLocalAddRecurse(op,1-slot,DEPTH_LIMIT, data); // Get any constants from other input
|
||||
}
|
||||
}
|
||||
else if (opc == CPUI_PTRSUB) {
|
||||
extra += op->getIn(1)->getOffset();
|
||||
op->clearStopTypePropagation();
|
||||
data.opRemoveInput(op, 1);
|
||||
data.opSetOpcode(op, CPUI_COPY);
|
||||
}
|
||||
else if (opc == CPUI_PTRADD) {
|
||||
if (op->getIn(0) != vn) break;
|
||||
int8 ptraddmult = op->getIn(2)->getOffset();
|
||||
Varnode *invn = op->getIn(1);
|
||||
if (invn->isConstant()) {
|
||||
extra += ptraddmult * (int8)invn->getOffset();
|
||||
data.opRemoveInput(op,2);
|
||||
data.opRemoveInput(op,1);
|
||||
data.opSetOpcode(op, CPUI_COPY);
|
||||
}
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
vn = op->getOut();
|
||||
op = vn->loneDescend();
|
||||
}
|
||||
return extra;
|
||||
}
|
||||
|
||||
int4 RulePtrsubUndo::applyOp(PcodeOp *op,Funcdata &data)
|
||||
|
||||
{
|
||||
if (!data.hasTypeRecoveryStarted()) return 0;
|
||||
|
||||
Varnode *basevn = op->getIn(0);
|
||||
if (basevn->getTypeReadFacing(op)->isPtrsubMatching(op->getIn(1)->getOffset()))
|
||||
Varnode *cvn = op->getIn(1);
|
||||
int8 val = cvn->getOffset();
|
||||
int8 multiplier;
|
||||
int8 extra = getExtraOffset(op,multiplier);
|
||||
if (basevn->getTypeReadFacing(op)->isPtrsubMatching(val,extra,multiplier))
|
||||
return 0;
|
||||
|
||||
data.opSetOpcode(op,CPUI_INT_ADD);
|
||||
op->clearStopTypePropagation();
|
||||
extra = removeLocalAdds(op->getOut(),data);
|
||||
if (extra != 0) {
|
||||
val = val + extra; // Lump extra into additive offset
|
||||
data.opSetInput(op,data.newConstant(cvn->getSize(), val & calc_mask(cvn->getSize())),1);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue