|
decompiler 1.0.0
|
Class that converts bitfield pull expressions into explicit ZPULL and SPULL operations. More...
#include <bitfield.hh>
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 | |
| Varnode * | root |
| Value being pulled from. | |
| PcodeOp * | loadOp |
| LOAD op producing root (if non-null) | |
| list< PullRecord > | pullList |
| 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. | |
| Datatype * | buildPartialType (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 | |
| Funcdata * | func |
| The containing function. | |
| TypeStruct * | parentStruct |
| Structure owning the bitfields. | |
| list< BitFieldNodeState > | workList |
| 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. | |
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.
| ghidra::BitFieldPullTransform::BitFieldPullTransform | ( | Funcdata * | f, |
| Varnode * | r, | ||
| Datatype * | dt, | ||
| int4 | off | ||
| ) |
Construct from Varnode containing bitfields.
| f | is the function |
| r | is the root Varnode with a bitfield data-type |
| dt | is the data-type containing bitfields (may be partial) |
| off | is 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.
| void ghidra::BitFieldPullTransform::apply | ( | void | ) |
Transform recovered expressions into ZPULL or SPULL operations.
For each pull record, either:
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().
|
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.
| rec | must 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().
|
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.
| rec | is the given PullRecord |
| state | is 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().
| bool ghidra::BitFieldPullTransform::doTrace | ( | void | ) |
Trace bitfields from root to points where they are pulled.
Create a PullRecord at each pull point.
References ghidra::BitFieldPullTransform::PullRecord::normal, processForward(), pullList, testCompareGroup(), and ghidra::BitFieldTransform::workList.
Referenced by ghidra::RuleBitFieldLoad::applyOp(), and ghidra::RuleBitFieldIn::applyOp().
|
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.
| loadOp | is the LOAD |
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().
|
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.
| loadOp | is 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().
|
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.
| state | is the current state of the bitfield and the Varnode holding it |
| op | is 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().
|
private |
Follow bitfield into INT_EQUAL or INT_NOTEQUAL.
| state | is the current state of the bitfield and the Varnode holding it |
| op | is 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().
|
private |
Follow bitfield forward through INT_ZEXT.
Add the output Varnode as a new bitfield state and update usage information for original root bits.
| state | is the current state of the bitfield and the Varnode holding it |
| op | is 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().
|
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.
| state | is the current state of the bitfield and the Varnode holding it |
| op | is 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().
|
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.
| state | is the current state of the bitfield and the Varnode holding it |
| op | is the arithmetic/logical op |
References ghidra::BitFieldNodeState::bitsField, ghidra::PcodeOp::getOut(), ghidra::BitRange::leastSigBit, pullList, and testConsumed().
Referenced by handleMultForward(), and processForward().
|
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.
| state | is the current state of the bitfield and the Varnode holding it |
| op | is 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().
|
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.
| state | is the current state of the bitfield and the Varnode holding it |
| op | is 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().
|
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.
| state | is the current state of the bitfield and the Varnode holding it |
| op | is 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().
|
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.
| state | is the current state of the bitfield and the Varnode holding it |
| op | is 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().
|
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.
| state | is the current state of the bitfield and the Varnode holding it |
| op | is 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().
|
private |
Follow bitfield forward one level through all its descendants.
| state | is the current state of the bitfield and the Varnode holding it |
References ghidra::Varnode::beginDescend(), ghidra::PcodeOp::code(), ghidra::CPUI_INSERT, ghidra::CPUI_INT_2COMP, ghidra::CPUI_INT_ADD, ghidra::CPUI_INT_AND, ghidra::CPUI_INT_EQUAL, ghidra::CPUI_INT_LEFT, ghidra::CPUI_INT_LESS, ghidra::CPUI_INT_LESSEQUAL, ghidra::CPUI_INT_MULT, ghidra::CPUI_INT_NEGATE, ghidra::CPUI_INT_NOTEQUAL, ghidra::CPUI_INT_OR, ghidra::CPUI_INT_RIGHT, ghidra::CPUI_INT_SEXT, ghidra::CPUI_INT_SLESS, ghidra::CPUI_INT_SLESSEQUAL, ghidra::CPUI_INT_SRIGHT, ghidra::CPUI_INT_XOR, ghidra::CPUI_INT_ZEXT, ghidra::CPUI_SUBPIECE, ghidra::BitFieldNodeState::doesSignExtensionMatch(), ghidra::Varnode::endDescend(), handleAndForward(), handleEqualForward(), handleExtForward(), handleInsertForward(), handleLeastSigOp(), handleLeftForward(), handleLessForward(), handleMultForward(), handleRightForward(), handleSubpieceForward(), ghidra::BitFieldNodeState::isFieldAligned(), ghidra::BitFieldNodeState::node, and pullList.
Referenced by doTrace().
|
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:
| iter | points to the first PullRecord 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().
|
staticprivate |
Test if all consumed bits are in the given bitfield.
| vn | is the Varnode being read |
| bitField | is the bitfield being followed |
References ghidra::BitRange::byteSize, ghidra::Varnode::getConsume(), and ghidra::BitRange::getMask().
Referenced by handleAndForward(), handleLeastSigOp(), handleLeftForward(), handleRightForward(), and handleSubpieceForward().