decompiler 1.0.0
Classes | Public Member Functions | Private Member Functions | Private Attributes | List of all members
ghidra::BitFieldInsertTransform Class Reference

Class that converts bitfield insertion expressions into explicit INSERT operations. More...

#include <bitfield.hh>

Inheritance diagram for ghidra::BitFieldInsertTransform:
ghidra::BitFieldTransform

Classes

class  InsertRecord
 Info about a Varnode that can be treated as a write to a single bitfield. More...
 

Public Member Functions

 BitFieldInsertTransform (Funcdata *f, PcodeOp *op, Datatype *dt, int4 off)
 Construct from a terminating op.
 
bool doTrace (void)
 Trace bitfields backward from the terminating op.
 
void apply (void)
 Transform recovered expressions into INSERT operations.
 
- Public Member Functions inherited from ghidra::BitFieldTransform
 BitFieldTransform (Funcdata *f, Datatype *dt, int4 off)
 Constructor setting up basic info about bitfield data-type.
 

Private Member Functions

bool verifyLoadStoreOriginalValue (uintb mask) const
 Test for other STORE ops interfering with the original value.
 
bool verifyMappedOriginalValue (uintb mask) const
 Test for other ops interfering with the mapped original value.
 
uintb constructOriginalValueMask (void) const
 Calculate mask where 1 bits represent all the bits being preserved.
 
bool verifyOriginalValueBits (void) const
 Do final check that unINSERTed bits come from the original value.
 
bool isOverwrittenPartial (const BitFieldNodeState &state)
 Is given state a partial field that is overwritten later.
 
bool checkPulledOriginalValue (BitFieldNodeState &state)
 Is this an original value defined by ZPULL or SPULL.
 
bool checkOriginalBase (Varnode *vn)
 Check if the given Varnode is the original LOAD or mapped value.
 
bool isOriginalValue (BitFieldNodeState &state)
 Is the given Varnode a (partial) copy of the original value being INSERTed into.
 
bool addConstantWrite (BitFieldNodeState &state)
 Create InsertRecord writing a constant into the field.
 
bool addZeroOut (BitFieldNodeState &state)
 Create InsertRecord writing 0 into the field.
 
void addFieldWrite (BitFieldNodeState &state)
 Create InsertRecord writing Varnode into the field.
 
bool handleAndBack (BitFieldNodeState &state, PcodeOp *op)
 Follow bitfield back through INT_AND with a mask.
 
bool handleOrBack (BitFieldNodeState &state, PcodeOp *op)
 Follow bitfield back through one branch of INT_OR.
 
bool handleAddBack (BitFieldNodeState &state, PcodeOp *op)
 Follow bitfield back through one branch of INT_AND.
 
bool handleLeftBack (BitFieldNodeState &state, PcodeOp *op)
 Follow bitfield back through INT_LEFT by a constant.
 
bool handleRightBack (BitFieldNodeState &state, PcodeOp *op)
 Follow bitfield back through INT_SRIGHT by a constant.
 
bool handleZextBack (BitFieldNodeState &state, PcodeOp *op)
 Follow bitfield back through INT_ZEXT.
 
bool handleMultBack (BitFieldNodeState &state, PcodeOp *op)
 Follow bitfield back through INT_MULT.
 
bool handleSubpieceBack (BitFieldNodeState &state, PcodeOp *op)
 Follow bitfield back through SUBPIECE.
 
bool testCallOriginal (BitFieldNodeState &state, PcodeOp *op)
 Test if a call is producing the original value.
 
bool processBackward (BitFieldNodeState &state)
 Follow field back, creating an InsertRecord if possible.
 
PcodeOpsetInsertInputs (PcodeOp *op, const InsertRecord &rec)
 Fill-in INSERT inputs based on given InsertRecord.
 
void addFieldShift (PcodeOp *insertOp, const InsertRecord &rec)
 Create any shift p-code op specified by given InsertRecord.
 
bool foldLoad (PcodeOp *loadOp) const
 Try to mark LOAD as part of INSERT.
 
void foldPtrsub (PcodeOp *loadOp) const
 Try to mark PTRSUB as part of INSERT.
 
void checkRedundancy (const InsertRecord &rec)
 Check if value is getting INSERTed twice and remove second.
 

Private Attributes

PcodeOpfinalWriteOp
 STORE to bitfields or op outputing to bitfields.
 
VarnodeoriginalValue
 Value prior to insertion.
 
VarnodemappedVn
 Bitfield container written to.
 
list< InsertRecordinsertList
 Insertion actions.
 

Additional Inherited Members

- Protected Member Functions inherited from ghidra::BitFieldTransform
void establishFields (Varnode *vn, bool followHoles)
 Build worklist for each bitfield overlapped by given Varnode.
 
DatatypebuildPartialType (void)
 Build the (partial) data-type associated with the root bitfield container.
 
- Static Protected Member Functions inherited from ghidra::BitFieldTransform
static bool findOverwrite (Varnode *vn, BlockBasic *bl, const BitRange &range)
 Return true if specified bits in a Varnode are overwritten in the same basic block.
 
- Protected Attributes inherited from ghidra::BitFieldTransform
Funcdatafunc
 The containing function.
 
TypeStructparentStruct
 Structure owning the bitfields.
 
list< BitFieldNodeStateworkList
 Fields that are being followed.
 
int4 initialOffset
 Byte offset into parent structure.
 
int4 containerSize
 Size of Varnode containing bitfields.
 
bool isBigEndian
 Endianness associated with bitfields.
 

Detailed Description

Class that converts bitfield insertion expressions into explicit INSERT operations.

The doTrace() method traces backward from a root Varnode that contains bitfields to find points that can be treated as a value written to an individual bitfield, creating an InsertRecord at each point. If all bits of the Varnode are accounted for, the apply() method transforms expressions based on any InsertRecord.

Constructor & Destructor Documentation

◆ BitFieldInsertTransform()

ghidra::BitFieldInsertTransform::BitFieldInsertTransform ( Funcdata f,
PcodeOp op,
Datatype dt,
int4  off 
)

Construct from a terminating op.

Parameters
fis the function
opis the p-code terminating the putative bitfield expression
dtis the structure containing bitfields
offis the amount of offset

References ghidra::PcodeOp::code(), ghidra::BitFieldTransform::containerSize, ghidra::CPUI_INDIRECT, ghidra::CPUI_STORE, ghidra::BitFieldTransform::establishFields(), finalWriteOp, ghidra::Varnode::getDef(), ghidra::PcodeOp::getIn(), ghidra::PcodeOp::getOut(), ghidra::Varnode::getSize(), ghidra::BitFieldTransform::initialOffset, ghidra::Varnode::isWritten(), mappedVn, and originalValue.

Member Function Documentation

◆ addConstantWrite()

bool ghidra::BitFieldInsertTransform::addConstantWrite ( BitFieldNodeState state)
private

◆ addFieldShift()

void ghidra::BitFieldInsertTransform::addFieldShift ( PcodeOp insertOp,
const InsertRecord rec 
)
private

◆ addFieldWrite()

void ghidra::BitFieldInsertTransform::addFieldWrite ( BitFieldNodeState state)
private

◆ addZeroOut()

bool ghidra::BitFieldInsertTransform::addZeroOut ( BitFieldNodeState state)
private

Create InsertRecord writing 0 into the field.

If the state is not following a specific field, false is returned. The state will no longer be followed.

Parameters
statedescribes the field
Returns
true if an InsertRecord was created

References ghidra::TypeBitField::bits, ghidra::BitFieldNodeState::field, insertList, ghidra::BitFieldNodeState::node, ghidra::BitRange::numBits, ghidra::BitFieldNodeState::origLeastSigBit, and ghidra::TypeBitField::type.

Referenced by handleAndBack(), handleLeftBack(), handleMultBack(), handleZextBack(), and processBackward().

◆ checkOriginalBase()

bool ghidra::BitFieldInsertTransform::checkOriginalBase ( Varnode vn)
private

Check if the given Varnode is the original LOAD or mapped value.

If the Varnode is a the initial value of the storage being inserted into, return true. This can be either the result of the initial LOAD or the mapped storage location being read directly.

Parameters
vnis the given Varnode to check
Returns
true if it is the original value

References ghidra::PcodeOp::code(), ghidra::CPUI_LOAD, ghidra::CPUI_STORE, finalWriteOp, ghidra::Varnode::getAddr(), ghidra::Varnode::getDef(), ghidra::PcodeOp::getIn(), ghidra::PcodeOp::getParent(), ghidra::Varnode::getSize(), ghidra::Varnode::isAddrTied(), ghidra::Varnode::isWritten(), mappedVn, and originalValue.

Referenced by checkPulledOriginalValue(), and isOriginalValue().

◆ checkRedundancy()

void ghidra::BitFieldInsertTransform::checkRedundancy ( const InsertRecord rec)
private

Check if value is getting INSERTed twice and remove second.

Look for (first) two INSERT descendants of value being inserted. If these exist and are of the same form and in the same basic block, delete the second one.

Parameters
recis the record referencing the INSERTed value

References ghidra::Varnode::beginDescend(), ghidra::PcodeOp::code(), ghidra::CPUI_INSERT, ghidra::CPUI_INT_RIGHT, ghidra::CPUI_STORE, ghidra::Varnode::endDescend(), finalWriteOp, ghidra::BitFieldTransform::func, ghidra::PcodeOp::getIn(), ghidra::Varnode::getOffset(), ghidra::SeqNum::getOrder(), ghidra::PcodeOp::getOut(), ghidra::PcodeOp::getParent(), ghidra::PcodeOp::getSeqNum(), ghidra::Varnode::loneDescend(), ghidra::Funcdata::opDestroyRecursive(), and ghidra::BitFieldInsertTransform::InsertRecord::vn.

Referenced by apply().

◆ constructOriginalValueMask()

uintb ghidra::BitFieldInsertTransform::constructOriginalValueMask ( void  ) const
private

Calculate mask where 1 bits represent all the bits being preserved.

Collect all bits which are not being INSERTed to by this transform. These must be from the original value of the storage location.

Returns
a mask representing any bits coming from the original value

References ghidra::calc_mask(), ghidra::Varnode::getSize(), insertList, ghidra::BitFieldInsertTransform::InsertRecord::numBits, originalValue, and ghidra::BitFieldInsertTransform::InsertRecord::pos.

Referenced by verifyOriginalValueBits().

◆ doTrace()

bool ghidra::BitFieldInsertTransform::doTrace ( void  )

Trace bitfields backward from the terminating op.

Follow all field in the workList back and try to match insert expressions.

Returns
true if all fields match

References insertList, isOverwrittenPartial(), processBackward(), verifyOriginalValueBits(), and ghidra::BitFieldTransform::workList.

Referenced by ghidra::RuleBitFieldStore::applyOp(), and ghidra::RuleBitFieldOut::applyOp().

◆ foldLoad()

bool ghidra::BitFieldInsertTransform::foldLoad ( PcodeOp loadOp) const
private

Try to mark LOAD as part of INSERT.

Check that the output of the LOAD has only INSERT, ZPULL, SPULL, or the finalWriteOp as a descendant. If so mark the LOAD as non-printing.

Parameters
loadOpis the LOAD
Returns
true if the LOAD was marked as non-printing

References ghidra::Varnode::beginDescend(), ghidra::PcodeOp::code(), ghidra::CPUI_INSERT, ghidra::CPUI_SPULL, ghidra::CPUI_ZPULL, ghidra::Varnode::endDescend(), finalWriteOp, ghidra::BitFieldTransform::func, ghidra::PcodeOp::getOut(), and ghidra::Funcdata::opMarkNonPrinting().

Referenced by apply().

◆ foldPtrsub()

void ghidra::BitFieldInsertTransform::foldPtrsub ( PcodeOp loadOp) const
private

Try to mark PTRSUB as part of INSERT.

Check that the pointer into the given LOAD is defined by a PTRSUB and that all descendants of the pointer are LOADs or STOREs that have been absorbed. If so mark the PTRSUB as non-printing.

Parameters
loadOpis the LOAD

References ghidra::Varnode::beginDescend(), ghidra::PcodeOp::code(), ghidra::CPUI_LOAD, ghidra::CPUI_PTRSUB, ghidra::CPUI_STORE, ghidra::PcodeOp::doesSpecialPrinting(), ghidra::Varnode::endDescend(), ghidra::BitFieldTransform::func, ghidra::Varnode::getDef(), ghidra::PcodeOp::getIn(), ghidra::Varnode::isWritten(), ghidra::PcodeOp::notPrinted(), and ghidra::Funcdata::opMarkNonPrinting().

Referenced by apply().

◆ handleAndBack()

bool ghidra::BitFieldInsertTransform::handleAndBack ( BitFieldNodeState state,
PcodeOp op 
)
private

Follow bitfield back through INT_AND with a mask.

The second input must be a constant mask. If the mask zeroes out the field, create a zero InsertRecord. If the mask fully contains the field, follow the field through the first input. Otherwise return false.

Parameters
stateis the field being followed
opis the INT_AND
Returns
true if the field is followed or zeroed out

References addZeroOut(), ghidra::BitFieldNodeState::bitsField, ghidra::BitFieldNodeState::bitsUsed, ghidra::BitRange::byteSize, ghidra::PcodeOp::getIn(), ghidra::BitRange::getMask(), ghidra::Varnode::getOffset(), ghidra::BitRange::intersectMask(), ghidra::Varnode::isConstant(), and ghidra::BitFieldNodeState::node.

Referenced by processBackward().

◆ handleLeftBack()

bool ghidra::BitFieldInsertTransform::handleLeftBack ( BitFieldNodeState state,
PcodeOp op 
)
private

Follow bitfield back through INT_LEFT by a constant.

Update the state to reflect the shift. If the field has been completely filled with zeroes by the shift, create a zero InsertRecord. If the field is only partially filled, return false.

Parameters
stateis the field being followed
opis the INT_LEFT
Returns
true if the field is followed or been zeroed out

References addZeroOut(), ghidra::BitFieldNodeState::bitsField, ghidra::BitFieldNodeState::bitsUsed, ghidra::PcodeOp::getIn(), ghidra::Varnode::getOffset(), ghidra::Varnode::isConstant(), ghidra::BitFieldNodeState::node, ghidra::BitRange::numBits, and ghidra::BitRange::shift().

Referenced by processBackward().

◆ handleMultBack()

bool ghidra::BitFieldInsertTransform::handleMultBack ( BitFieldNodeState state,
PcodeOp op 
)
private

Follow bitfield back through INT_MULT.

Treat INT_MULT by a power of 2 like INT_LEFT.

Parameters
stateis the field being followed
opis the INT_MULT
Returns
true if field is followed or zeroed out

References addZeroOut(), ghidra::BitFieldNodeState::bitsField, ghidra::BitFieldNodeState::bitsUsed, ghidra::PcodeOp::getIn(), ghidra::Varnode::getOffset(), ghidra::Varnode::isConstant(), ghidra::BitFieldNodeState::node, ghidra::BitRange::numBits, and ghidra::BitRange::shift().

Referenced by processBackward().

◆ handleOrBack()

bool ghidra::BitFieldInsertTransform::handleOrBack ( BitFieldNodeState state,
PcodeOp op 
)
private

Follow bitfield back through one branch of INT_OR.

Follow the field through the input that has not masked off its bitrange. If neither input has mased off the bitrange, or if both have, return false;

Parameters
stateis the field being followed
opis the INT_OR
Returns
true if the field is followed through a single input

References ghidra::BitFieldNodeState::bitsField, ghidra::BitRange::byteSize, ghidra::PcodeOp::getIn(), ghidra::BitRange::getMask(), ghidra::Varnode::getNZMask(), ghidra::Varnode::isConstant(), and ghidra::BitFieldNodeState::node.

Referenced by processBackward().

◆ handleRightBack()

bool ghidra::BitFieldInsertTransform::handleRightBack ( BitFieldNodeState state,
PcodeOp op 
)
private

Follow bitfield back through INT_SRIGHT by a constant.

Update the state to reflect the shift.

Parameters
stateis the field being followed
opis the INT_RIGHT
Returns
true if the field is followed

References ghidra::BitFieldNodeState::bitsField, ghidra::BitFieldNodeState::bitsUsed, ghidra::PcodeOp::getIn(), ghidra::Varnode::getOffset(), ghidra::Varnode::isConstant(), ghidra::BitFieldNodeState::node, ghidra::BitRange::numBits, and ghidra::BitRange::shift().

Referenced by processBackward().

◆ handleSubpieceBack()

bool ghidra::BitFieldInsertTransform::handleSubpieceBack ( BitFieldNodeState state,
PcodeOp op 
)
private

Follow bitfield back through SUBPIECE.

Follow the field into the input of the SUBPIECE, which may have shifted it

Parameters
stateis the field being followed
opis the SUBPIECE
Returns
true if field is followed

References ghidra::BitFieldNodeState::bitsField, ghidra::BitFieldNodeState::bitsUsed, ghidra::BitRange::extendBytes(), ghidra::PcodeOp::getIn(), ghidra::Varnode::getOffset(), ghidra::Varnode::getSize(), ghidra::BitFieldNodeState::node, ghidra::BitRange::numBits, and ghidra::BitRange::shift().

Referenced by processBackward().

◆ handleZextBack()

bool ghidra::BitFieldInsertTransform::handleZextBack ( BitFieldNodeState state,
PcodeOp op 
)
private

Follow bitfield back through INT_ZEXT.

Follow the field to the input, and update the state to reflect the smaller byte container. If the extension puts zero bits in field, return false.

Parameters
stateis the field being followed
opis the INT_ZEXT
Returns
true if field is followed

References addZeroOut(), ghidra::BitFieldNodeState::bitsField, ghidra::BitFieldNodeState::bitsUsed, ghidra::PcodeOp::getIn(), ghidra::PcodeOp::getOut(), ghidra::Varnode::getSize(), ghidra::BitFieldNodeState::node, ghidra::BitRange::numBits, and ghidra::BitRange::truncateMostSigBytes().

Referenced by processBackward().

◆ isOriginalValue()

bool ghidra::BitFieldInsertTransform::isOriginalValue ( BitFieldNodeState state)
private

Is the given Varnode a (partial) copy of the original value being INSERTed into.

Parameters
stateis the given Varnode
Returns
true if the Varnode contains the original value for the bitfield(s)

References ghidra::BitFieldNodeState::bitsField, checkOriginalBase(), checkPulledOriginalValue(), ghidra::BitRange::leastSigBit, ghidra::BitFieldNodeState::node, originalValue, and ghidra::BitFieldNodeState::origLeastSigBit.

Referenced by processBackward().

◆ isOverwrittenPartial()

bool ghidra::BitFieldInsertTransform::isOverwrittenPartial ( const BitFieldNodeState state)
private

Is given state a partial field that is overwritten later.

If the state is for a partial field whose storage location is overwritten later in the same basic block, return true

Parameters
stateis the field
Returns
true if a partial field has been overwritten

References ghidra::BitFieldNodeState::bitsField, ghidra::BitRange::byteSize, ghidra::PcodeOp::code(), ghidra::CPUI_STORE, ghidra::BitFieldNodeState::field, finalWriteOp, ghidra::BitFieldTransform::findOverwrite(), ghidra::PcodeOp::getParent(), ghidra::Varnode::getSize(), ghidra::BitFieldTransform::initialOffset, ghidra::BitFieldTransform::isBigEndian, mappedVn, ghidra::BitRange::numBits, and ghidra::BitFieldNodeState::origLeastSigBit.

Referenced by doTrace().

◆ processBackward()

bool ghidra::BitFieldInsertTransform::processBackward ( BitFieldNodeState state)
private

◆ setInsertInputs()

PcodeOp * ghidra::BitFieldInsertTransform::setInsertInputs ( PcodeOp op,
const InsertRecord rec 
)
private

◆ testCallOriginal()

bool ghidra::BitFieldInsertTransform::testCallOriginal ( BitFieldNodeState state,
PcodeOp op 
)
private

Test if a call is producing the original value.

If the call produces the bitfield structure directly, we can treat the return value as the original value, even though the storage is not address tied.

Parameters
stateis the field being followed
opis the call
Returns
true if the return value can be treated as the original value

References ghidra::BitFieldNodeState::bitsField, ghidra::PcodeOp::code(), ghidra::CPUI_STORE, finalWriteOp, ghidra::Datatype::getMetatype(), ghidra::TypePartialStruct::getOffset(), ghidra::PcodeOp::getOut(), ghidra::TypePartialStruct::getParent(), ghidra::Varnode::getTypeDefFacing(), ghidra::BitFieldTransform::initialOffset, ghidra::Varnode::isAddrTied(), ghidra::PcodeOp::isCall(), ghidra::BitRange::leastSigBit, mappedVn, originalValue, ghidra::BitFieldNodeState::origLeastSigBit, ghidra::BitFieldTransform::parentStruct, ghidra::TYPE_PARTIALSTRUCT, and ghidra::TYPE_STRUCT.

Referenced by processBackward().

◆ verifyLoadStoreOriginalValue()

bool ghidra::BitFieldInsertTransform::verifyLoadStoreOriginalValue ( uintb  mask) const
private

Test for other STORE ops interfering with the original value.

Verify that any STORE between the original value LOAD and the final STORE does not affect any of the known original value bits.

Parameters
maskis the set of bits that must come from the putative original value
Returns
true if there is no interference

References ghidra::BlockBasic::beginOp(), ghidra::PcodeOp::code(), ghidra::CPUI_INSERT, ghidra::CPUI_STORE, finalWriteOp, ghidra::PcodeOp::getBasicIter(), ghidra::Varnode::getDef(), ghidra::PcodeOp::getIn(), ghidra::Varnode::getOffset(), ghidra::PcodeOp::getParent(), ghidra::InsertExpression::getRangeMask(), ghidra::PcodeOp::isCall(), ghidra::Varnode::isWritten(), and originalValue.

Referenced by verifyOriginalValueBits().

◆ verifyMappedOriginalValue()

bool ghidra::BitFieldInsertTransform::verifyMappedOriginalValue ( uintb  mask) const
private

Test for other ops interfering with the mapped original value.

Verify that any write to the mapped storage location between the original value LOAD and the STORE does not affect any of the known original value bits

Parameters
maskis the set of bits that must come from the putative original value
Returns
true if there is no interference

References ghidra::BlockBasic::beginOp(), ghidra::PcodeOp::code(), ghidra::CPUI_INSERT, finalWriteOp, ghidra::Varnode::getAddr(), ghidra::PcodeOp::getBasicIter(), ghidra::Varnode::getDef(), ghidra::PcodeOp::getOut(), ghidra::PcodeOp::getParent(), ghidra::InsertExpression::getRangeMask(), ghidra::Varnode::getSize(), ghidra::PcodeOp::isCall(), ghidra::Varnode::isWritten(), and originalValue.

Referenced by verifyOriginalValueBits().

◆ verifyOriginalValueBits()

bool ghidra::BitFieldInsertTransform::verifyOriginalValueBits ( void  ) const
private

Do final check that unINSERTed bits come from the original value.

Returns
true if putative original value bits are unaffected

References ghidra::PcodeOp::code(), constructOriginalValueMask(), ghidra::CPUI_STORE, finalWriteOp, originalValue, verifyLoadStoreOriginalValue(), and verifyMappedOriginalValue().

Referenced by doTrace().


The documentation for this class was generated from the following files: