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

Class that converts bitfield pull expressions into explicit ZPULL and SPULL operations. More...

#include <bitfield.hh>

Inheritance diagram for ghidra::BitFieldPullTransform:
ghidra::BitFieldTransform

Classes

class  PullRecord
 Info about a single read by a PcodeOp that can be treated as a pull of 1 or more bitfields. More...
 
class  TransformState
 During final transformation, this is the state maintained between processing individual PullRecords. More...
 

Public Member Functions

 BitFieldPullTransform (Funcdata *f, Varnode *r, Datatype *dt, int4 off)
 Construct from Varnode containing bitfields.
 
bool doTrace (void)
 Trace bitfields from root to points where they are pulled.
 
void apply (void)
 Transform recovered expressions into ZPULL or SPULL 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

void handleLeftForward (const BitFieldNodeState &state, PcodeOp *op)
 Follow bitfield forward through INT_LEFT.
 
void handleRightForward (const BitFieldNodeState &state, PcodeOp *op)
 Follow bitfield forward through INT_RIGHT.
 
void handleAndForward (const BitFieldNodeState &state, PcodeOp *op)
 Follow bitfield forward through INT_AND.
 
void handleExtForward (const BitFieldNodeState &state, PcodeOp *op)
 Follow bitfield forward through INT_ZEXT.
 
void handleMultForward (const BitFieldNodeState &state, PcodeOp *op)
 Follow bitfield forward through INT_MULT.
 
void handleSubpieceForward (const BitFieldNodeState &state, PcodeOp *op)
 Follow bitfield forward through SUBPIECE.
 
void handleInsertForward (const BitFieldNodeState &state, PcodeOp *op)
 Follow bitfield forward into INSERT.
 
void handleLessForward (const BitFieldNodeState &state, PcodeOp *op)
 Follow bitfield forward through INT_LESS, INT_SLESS.
 
void handleLeastSigOp (const BitFieldNodeState &state, PcodeOp *op)
 Follow bitfield into INT_ADD, INT_MULT, INT_OR, INT_XOR.
 
void handleEqualForward (const BitFieldNodeState &state, PcodeOp *op)
 Follow bitfield into INT_EQUAL or INT_NOTEQUAL.
 
void processForward (BitFieldNodeState &state)
 Follow bitfield forward one level through all its descendants.
 
list< PullRecord >::iterator testCompareGroup (list< PullRecord >::iterator iter)
 Determine if pulls at a specific INT_EQUAL or INT_NOTEQUAL are consistent as a whole.
 
void applyRecord (PullRecord &rec, TransformState &state)
 Perform transform corresponding to the given PullRecord.
 
void applyCompareRecord (const PullRecord &rec)
 Perform transform on an INT_EQUAL or INT_NOTEQUAL.
 
bool foldLoad (PcodeOp *loadOp) const
 Try to mark LOAD as part of ZPULL or SPULL.
 
void foldPtrsub (PcodeOp *loadOp) const
 Try to mark PTRSUB as part of ZPULL or SPULL.
 

Static Private Member Functions

static bool testConsumed (Varnode *vn, const BitRange &bitField)
 Test if all consumed bits are in the given bitfield.
 

Private Attributes

Varnoderoot
 Value being pulled from.
 
PcodeOploadOp
 LOAD op producing root (if non-null)
 
list< PullRecordpullList
 Pull 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 pull expressions into explicit ZPULL and SPULL operations.

The doTrace() method traces forward from a root Varnode that contains bitfields to find points where an individual bitfield has been fully isolated, creating an PullRecord at each point. If all bits of the Varnode are accounted for, the apply() method transforms expressions based on any PullRecord.

Constructor & Destructor Documentation

◆ BitFieldPullTransform()

ghidra::BitFieldPullTransform::BitFieldPullTransform ( Funcdata f,
Varnode r,
Datatype dt,
int4  off 
)

Construct from Varnode containing bitfields.

Parameters
fis the function
ris the root Varnode with a bitfield data-type
dtis the data-type containing bitfields (may be partial)
offis the byte offset into the data-type to associate with root

References ghidra::PcodeOp::code(), ghidra::BitFieldTransform::containerSize, ghidra::CPUI_LOAD, ghidra::BitFieldTransform::establishFields(), ghidra::Varnode::getDef(), ghidra::Varnode::getSize(), ghidra::BitFieldTransform::initialOffset, ghidra::Varnode::isWritten(), loadOp, and root.

Member Function Documentation

◆ apply()

void ghidra::BitFieldPullTransform::apply ( void  )

Transform recovered expressions into ZPULL or SPULL operations.

For each pull record, either:

  • Redefine readVn with a ZPULL or SPULL. Delete the original op defining readVn
  • Create a Varnode for a specific readOp that effectively holds the pulled value

References applyCompareRecord(), applyRecord(), ghidra::BitFieldTransform::buildPartialType(), ghidra::BitFieldPullTransform::TransformState::count, ghidra::BitFieldPullTransform::PullRecord::equal, foldLoad(), foldPtrsub(), loadOp, ghidra::BitFieldPullTransform::TransformState::partialType, pullList, and ghidra::BitFieldPullTransform::PullRecord::type.

Referenced by ghidra::RuleBitFieldLoad::applyOp(), and ghidra::RuleBitFieldIn::applyOp().

◆ applyCompareRecord()

void ghidra::BitFieldPullTransform::applyCompareRecord ( const PullRecord rec)
private

Perform transform on an INT_EQUAL or INT_NOTEQUAL.

The first PullRecord at least must be for a comparison op. If there are more than one, the op is converted into a boolean expression with comparison for each record. Then the constant value for each comparison is adjusted to match the PullRecord bitfield. The PullRecords are not removed, but are converted to normal records so that the applyRecord() method can create the ZPULL or SPULL ops.

Parameters
recmust be the first PullRecord in pullList

References ghidra::PcodeOp::code(), ghidra::CPUI_BOOL_AND, ghidra::CPUI_BOOL_OR, ghidra::CPUI_INT_EQUAL, ghidra::BitFieldPullTransform::PullRecord::dt, ghidra::BitFieldTransform::func, ghidra::PcodeOp::getAddr(), ghidra::Funcdata::getArch(), ghidra::PcodeOp::getIn(), ghidra::Datatype::getMetatype(), ghidra::Varnode::getOffset(), ghidra::Varnode::getSize(), ghidra::BitFieldPullTransform::PullRecord::leftShift, ghidra::BitFieldPullTransform::PullRecord::mask, ghidra::Funcdata::newConstant(), ghidra::Funcdata::newOp(), ghidra::Funcdata::newUniqueOut(), ghidra::BitFieldPullTransform::PullRecord::normal, ghidra::BitFieldPullTransform::PullRecord::numBits, ghidra::Funcdata::opInsertBefore(), ghidra::Funcdata::opSetInput(), ghidra::Funcdata::opSetOpcode(), pullList, ghidra::BitFieldPullTransform::PullRecord::readOp, ghidra::BitFieldPullTransform::PullRecord::readVn, ghidra::TypeFactory::resizeInteger(), ghidra::BitFieldPullTransform::PullRecord::type, ghidra::TYPE_INT, ghidra::Architecture::types, and ghidra::Varnode::updateType().

Referenced by apply().

◆ applyRecord()

void ghidra::BitFieldPullTransform::applyRecord ( PullRecord rec,
TransformState state 
)
private

Perform transform corresponding to the given PullRecord.

Create the ZPULL or SPULL op. Duplicate the LOAD if necessary. Add an INT_LEFT if needed.

Parameters
recis the given PullRecord
stateis state maintained across all transforms

References ghidra::BitFieldTransform::containerSize, ghidra::BitFieldPullTransform::TransformState::count, ghidra::CPUI_INT_LEFT, ghidra::CPUI_LOAD, ghidra::CPUI_SPULL, ghidra::CPUI_ZPULL, ghidra::BitFieldPullTransform::TransformState::deadScratch, ghidra::BitFieldPullTransform::PullRecord::dt, ghidra::BitFieldTransform::func, ghidra::PcodeOp::getAddr(), ghidra::Funcdata::getArch(), ghidra::Varnode::getDef(), ghidra::PcodeOp::getIn(), ghidra::Datatype::getMetatype(), ghidra::PcodeOp::getOut(), ghidra::Varnode::getSize(), ghidra::PcodeOp::getSlot(), ghidra::Varnode::getType(), ghidra::Varnode::hasNoDescend(), ghidra::BitFieldPullTransform::PullRecord::leftShift, loadOp, ghidra::Funcdata::newConstant(), ghidra::Funcdata::newOp(), ghidra::Funcdata::newUnique(), ghidra::Funcdata::newUniqueOut(), ghidra::BitFieldPullTransform::PullRecord::numBits, ghidra::Funcdata::opDestroyRecursive(), ghidra::Funcdata::opInsertAfter(), ghidra::Funcdata::opInsertBefore(), ghidra::Funcdata::opMarkNonPrinting(), ghidra::Funcdata::opSetInput(), ghidra::Funcdata::opSetOpcode(), ghidra::Funcdata::opSetOutput(), ghidra::Funcdata::opUnsetOutput(), ghidra::BitFieldPullTransform::TransformState::partialType, ghidra::BitFieldPullTransform::PullRecord::pos, ghidra::BitFieldPullTransform::PullRecord::readOp, ghidra::BitFieldPullTransform::PullRecord::readVn, ghidra::TypeFactory::resizeInteger(), root, ghidra::TYPE_BOOL, ghidra::TYPE_INT, ghidra::TYPE_UNKNOWN, ghidra::Architecture::types, and ghidra::Varnode::updateType().

Referenced by apply().

◆ doTrace()

bool ghidra::BitFieldPullTransform::doTrace ( void  )

Trace bitfields from root to points where they are pulled.

Create a PullRecord at each pull point.

Returns
true if any PullRecords were created

References ghidra::BitFieldPullTransform::PullRecord::normal, processForward(), pullList, testCompareGroup(), and ghidra::BitFieldTransform::workList.

Referenced by ghidra::RuleBitFieldLoad::applyOp(), and ghidra::RuleBitFieldIn::applyOp().

◆ foldLoad()

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

Try to mark LOAD as part of ZPULL or SPULL.

Check that the output of the LOAD has only ZPULL, SPULL, or INSERT 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::CPUI_INSERT, ghidra::CPUI_SPULL, ghidra::CPUI_ZPULL, ghidra::Varnode::endDescend(), ghidra::BitFieldTransform::func, ghidra::PcodeOp::getOut(), loadOp, and ghidra::Funcdata::opMarkNonPrinting().

Referenced by apply().

◆ foldPtrsub()

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

Try to mark PTRSUB as part of ZPULL or SPULL.

Check that the pointer into the given LOAD is defined by a PTRSUB and that all descendants of the pointer are LOADs 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::Varnode::endDescend(), ghidra::BitFieldTransform::func, ghidra::Varnode::getDef(), ghidra::PcodeOp::getIn(), ghidra::Varnode::isWritten(), loadOp, ghidra::PcodeOp::notPrinted(), and ghidra::Funcdata::opMarkNonPrinting().

Referenced by apply().

◆ handleAndForward()

void ghidra::BitFieldPullTransform::handleAndForward ( const BitFieldNodeState state,
PcodeOp op 
)
private

Follow bitfield forward through INT_AND.

If the bitfield is masked into the output Varnode without losing bits, add the output as a new bitfield state and update usage information for original root bits. If every bit outside the bitfield is zeroed plus additional bits in the bitfield, create a PullRecord for this particular read.

Parameters
stateis the current state of the bitfield and the Varnode holding it
opis the INT_AND reading the bitfield Varnode

References ghidra::BitFieldNodeState::bitsField, ghidra::BitRange::byteSize, ghidra::PcodeOp::getIn(), ghidra::BitRange::getMask(), ghidra::Varnode::getOffset(), ghidra::PcodeOp::getOut(), ghidra::Varnode::isConstant(), ghidra::BitRange::isMostSignificant(), ghidra::BitFieldNodeState::node, pullList, testConsumed(), and ghidra::BitFieldTransform::workList.

Referenced by processForward().

◆ handleEqualForward()

void ghidra::BitFieldPullTransform::handleEqualForward ( const BitFieldNodeState state,
PcodeOp op 
)
private

Follow bitfield into INT_EQUAL or INT_NOTEQUAL.

Parameters
stateis the current state of the bitfield and the Varnode holding it
opis the INT_EQUAL or INT_NOTEQUAL comparison reading the bitfield Varnode

References ghidra::TypeBitField::bits, ghidra::BitFieldNodeState::bitsField, ghidra::BitRange::byteSize, ghidra::BitFieldNodeState::field, ghidra::PcodeOp::getIn(), ghidra::BitRange::getMask(), ghidra::Varnode::isConstant(), ghidra::BitRange::numBits, and pullList.

Referenced by processForward().

◆ handleExtForward()

void ghidra::BitFieldPullTransform::handleExtForward ( const BitFieldNodeState state,
PcodeOp op 
)
private

Follow bitfield forward through INT_ZEXT.

Add the output Varnode as a new bitfield state and update usage information for original root bits.

Parameters
stateis the current state of the bitfield and the Varnode holding it
opis the INT_ZEXT or INT_SEXT reading the bitfield Varnode

References ghidra::BitFieldNodeState::bitsField, ghidra::PcodeOp::code(), ghidra::CPUI_INT_SEXT, ghidra::PcodeOp::getOut(), ghidra::Varnode::getSize(), ghidra::BitFieldNodeState::isSignExtended, ghidra::BitFieldNodeState::node, and ghidra::BitFieldTransform::workList.

Referenced by processForward().

◆ handleInsertForward()

void ghidra::BitFieldPullTransform::handleInsertForward ( const BitFieldNodeState state,
PcodeOp op 
)
private

Follow bitfield forward into INSERT.

Test if we can treat the value being INSERTed as a PULL of the current bitfield. The INSERT must only be inserting bits from the bitfield, in which case we create a PullRecord directly.

Parameters
stateis the current state of the bitfield and the Varnode holding it
opis the INSERT reading the bitfield Varnode

References ghidra::BitFieldNodeState::bitsField, ghidra::PcodeOp::getIn(), ghidra::Varnode::getOffset(), ghidra::BitRange::leastSigBit, ghidra::BitFieldNodeState::node, ghidra::BitRange::numBits, and pullList.

Referenced by processForward().

◆ handleLeastSigOp()

void ghidra::BitFieldPullTransform::handleLeastSigOp ( const BitFieldNodeState state,
PcodeOp op 
)
private

Follow bitfield into INT_ADD, INT_MULT, INT_OR, INT_XOR.

This handles arithmetic/logical ops where the result on least significant bits doesn't change if the more significant bits are truncated from the inputs.

Parameters
stateis the current state of the bitfield and the Varnode holding it
opis the arithmetic/logical op

References ghidra::BitFieldNodeState::bitsField, ghidra::PcodeOp::getOut(), ghidra::BitRange::leastSigBit, pullList, and testConsumed().

Referenced by handleMultForward(), and processForward().

◆ handleLeftForward()

void ghidra::BitFieldPullTransform::handleLeftForward ( const BitFieldNodeState state,
PcodeOp op 
)
private

Follow bitfield forward through INT_LEFT.

If the bitfield is moved into the output Varnode without losing bits, add the output as a new bitfield state and update usage information for original root bits.

Parameters
stateis the current state of the bitfield and the Varnode holding it
opis the INT_LEFT reading the bitfield Varnode

References ghidra::BitFieldNodeState::bitsField, ghidra::PcodeOp::getIn(), ghidra::Varnode::getOffset(), ghidra::PcodeOp::getOut(), ghidra::Varnode::isConstant(), ghidra::BitRange::isMostSignificant(), ghidra::BitFieldNodeState::isSignExtended, ghidra::BitFieldNodeState::node, ghidra::BitRange::numBits, pullList, ghidra::BitRange::shift(), testConsumed(), and ghidra::BitFieldTransform::workList.

Referenced by processForward().

◆ handleLessForward()

void ghidra::BitFieldPullTransform::handleLessForward ( const BitFieldNodeState state,
PcodeOp op 
)
private

Follow bitfield forward through INT_LESS, INT_SLESS.

If the bitfield is the most significant bits being compared, and the constant being compared to has 1 bits in the least significant positions, create a PullRecord indicating the comparison acts on the pulled bits.

Parameters
stateis the current state of the bitfield and the Varnode holding it
opis the comparison reading the bitfield Varnode

References ghidra::BitFieldNodeState::bitsField, ghidra::PcodeOp::code(), ghidra::CPUI_INT_LESS, ghidra::CPUI_INT_LESSEQUAL, ghidra::CPUI_INT_SLESS, ghidra::CPUI_INT_SLESSEQUAL, ghidra::PcodeOp::getIn(), ghidra::Varnode::getNZMask(), ghidra::Varnode::getOffset(), ghidra::PcodeOp::getSlot(), ghidra::Varnode::isConstant(), ghidra::BitRange::isMostSignificant(), ghidra::BitRange::leastSigBit, ghidra::BitFieldNodeState::node, and pullList.

Referenced by processForward().

◆ handleMultForward()

void ghidra::BitFieldPullTransform::handleMultForward ( const BitFieldNodeState state,
PcodeOp op 
)
private

Follow bitfield forward through INT_MULT.

If the INT_MULT can be viewed as a left shift, and If the bitfield is moved into the output Varnode without losing bits, add the output as a new bitfield state and update usage information for original root bits.

Parameters
stateis the current state of the bitfield and the Varnode holding it
opis the INT_MULT reading the bitfield Varnode

References ghidra::BitFieldNodeState::bitsField, ghidra::PcodeOp::getIn(), ghidra::Varnode::getOffset(), ghidra::PcodeOp::getOut(), handleLeastSigOp(), ghidra::Varnode::isConstant(), ghidra::BitRange::isMostSignificant(), ghidra::BitFieldNodeState::isSignExtended, ghidra::BitFieldNodeState::node, ghidra::BitRange::numBits, ghidra::BitRange::shift(), and ghidra::BitFieldTransform::workList.

Referenced by processForward().

◆ handleRightForward()

void ghidra::BitFieldPullTransform::handleRightForward ( const BitFieldNodeState state,
PcodeOp op 
)
private

Follow bitfield forward through INT_RIGHT.

If the bitfield is moved into the output Varnode without losing bits, add the output as a new bitfield state and update usage information for original root bits.

Parameters
stateis the current state of the bitfield and the Varnode holding it
opis the INT_RIGHT or INT_SRIGHT reading the bitfield Varnode

References ghidra::BitFieldNodeState::bitsField, ghidra::PcodeOp::code(), ghidra::CPUI_INT_SRIGHT, ghidra::PcodeOp::getIn(), ghidra::Varnode::getOffset(), ghidra::PcodeOp::getOut(), ghidra::Varnode::isConstant(), ghidra::BitFieldNodeState::isSignExtended, ghidra::BitFieldNodeState::node, ghidra::BitRange::numBits, pullList, ghidra::BitRange::shift(), testConsumed(), and ghidra::BitFieldTransform::workList.

Referenced by processForward().

◆ handleSubpieceForward()

void ghidra::BitFieldPullTransform::handleSubpieceForward ( const BitFieldNodeState state,
PcodeOp op 
)
private

Follow bitfield forward through SUBPIECE.

If the bitfield is truncated without losing bits, add the output as a new bitfield state and update usage information for original root bits.

Parameters
stateis the current state of the bitfield and the Varnode holding it
opis the SUBPIECE reading the bitfield Varnode

References ghidra::BitFieldNodeState::bitsField, ghidra::BitRange::byteSize, ghidra::PcodeOp::getIn(), ghidra::Varnode::getOffset(), ghidra::PcodeOp::getOut(), ghidra::Varnode::getSize(), ghidra::BitFieldNodeState::isSignExtended, ghidra::BitFieldNodeState::node, ghidra::BitRange::numBits, pullList, testConsumed(), ghidra::BitRange::truncateLeastSigBytes(), ghidra::BitRange::truncateMostSigBytes(), and ghidra::BitFieldTransform::workList.

Referenced by processForward().

◆ processForward()

void ghidra::BitFieldPullTransform::processForward ( BitFieldNodeState state)
private

◆ testCompareGroup()

list< BitFieldPullTransform::PullRecord >::iterator ghidra::BitFieldPullTransform::testCompareGroup ( list< PullRecord >::iterator  iter)
private

Determine if pulls at a specific INT_EQUAL or INT_NOTEQUAL are consistent as a whole.

Run through PullRecords for a single INT_EQUAL or INT_NOTEQUAL. These records are deleted if:

  • An aborted record is present, indicating a partial field or hole is being compared
  • Other unrelated bits are being compared
Parameters
iterpoints to the first PullRecord for the op
Returns
an iterator pointing after all PullRecords for the op

References ghidra::BitFieldPullTransform::PullRecord::aborted, ghidra::PcodeOp::getIn(), ghidra::Varnode::getNZMask(), ghidra::Varnode::getOffset(), ghidra::BitFieldPullTransform::PullRecord::mask, pullList, ghidra::BitFieldPullTransform::PullRecord::readOp, and ghidra::BitFieldPullTransform::PullRecord::type.

Referenced by doTrace().

◆ testConsumed()

bool ghidra::BitFieldPullTransform::testConsumed ( Varnode vn,
const BitRange bitField 
)
staticprivate

Test if all consumed bits are in the given bitfield.

Parameters
vnis the Varnode being read
bitFieldis the bitfield being followed
Returns
true if all consumed bits are in the bitfield

References ghidra::BitRange::byteSize, ghidra::Varnode::getConsume(), and ghidra::BitRange::getMask().

Referenced by handleAndForward(), handleLeastSigOp(), handleLeftForward(), handleRightForward(), and handleSubpieceForward().


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