decompiler
1.0.0
|
Split a p-code COPY, LOAD, or STORE op based on underlying composite data-type. More...
#include <subflow.hh>
Classes | |
class | Component |
A helper class describing a pair of matching data-types for the split. More... | |
class | RootPointer |
A helper class describing the pointer being passed to a LOAD or STORE. More... | |
Public Member Functions | |
SplitDatatype (Funcdata &func) | |
Constructor. | |
bool | splitCopy (PcodeOp *copyOp, Datatype *inType, Datatype *outType) |
Split a COPY operation. More... | |
bool | splitLoad (PcodeOp *loadOp, Datatype *inType) |
Split a LOAD operation. More... | |
bool | splitStore (PcodeOp *storeOp, Datatype *outType) |
Split a STORE operation. More... | |
Static Public Member Functions | |
static Datatype * | getValueDatatype (PcodeOp *loadStore, int4 size, TypeFactory *tlst) |
Get a data-type description of the value being pointed at by the given LOAD or STORE. More... | |
Private Member Functions | |
Datatype * | getComponent (Datatype *ct, int4 offset, bool &isHole) |
Obtain the component of the given data-type at the specified offset. More... | |
int4 | categorizeDatatype (Datatype *ct) |
Categorize if and how data-type should be split. More... | |
bool | testDatatypeCompatibility (Datatype *inBase, Datatype *outBase, bool inConstant) |
Can the two given data-types be mutually split into matching logical components. More... | |
bool | testCopyConstraints (PcodeOp *copyOp) |
Test specific constraints for splitting the given COPY operation into pieces. More... | |
bool | generateConstants (Varnode *vn, vector< Varnode *> &inVarnodes) |
If the given Varnode is an extended precision constant, create split constants. More... | |
void | buildInConstants (Varnode *rootVn, vector< Varnode *> &inVarnodes) |
Assuming the input is a constant, build split constants. More... | |
void | buildInSubpieces (Varnode *rootVn, PcodeOp *followOp, vector< Varnode *> &inVarnodes) |
Build input Varnodes by extracting SUBPIECEs from the root. More... | |
void | buildOutVarnodes (Varnode *rootVn, vector< Varnode *> &outVarnodes) |
Build output Varnodes with storage based on the given root. More... | |
void | buildOutConcats (Varnode *rootVn, PcodeOp *previousOp, vector< Varnode *> &outVarnodes) |
Concatenate output Varnodes into given root Varnode. More... | |
void | buildPointers (Varnode *rootVn, TypePointer *ptrType, int4 baseOffset, PcodeOp *followOp, vector< Varnode *> &ptrVarnodes, bool isInput) |
Build a a series of PTRSUB ops at different offsets, given a root pointer. More... | |
Static Private Member Functions | |
static bool | isArithmeticInput (Varnode *vn) |
Is this the input to an arithmetic operation. More... | |
static bool | isArithmeticOutput (Varnode *vn) |
Is this defined by an arithmetic operation. More... | |
Private Attributes | |
Funcdata & | data |
The containing function. | |
TypeFactory * | types |
The data-type container. | |
vector< Component > | dataTypePieces |
Sequence of all data-type pairs being copied. | |
bool | splitStructures |
Whether or not structures should be split. | |
bool | splitArrays |
Whether or not arrays should be split. | |
Split a p-code COPY, LOAD, or STORE op based on underlying composite data-type.
During the cleanup phase, if a COPY, LOAD, or STORE occurs on a partial structure or array (TypePartialStruct), try to break it up into multiple operations that each act on logical component of the structure or array.
|
private |
Assuming the input is a constant, build split constants.
Build constant input Varnodes, extracting the constant value from the given root constant based on the input offsets in dataTypePieces.
rootVn | is the given root constant |
inVarnodes | is the container for the new Varnodes |
References ghidra::calc_mask(), ghidra::Varnode::getOffset(), ghidra::Varnode::getSize(), ghidra::Datatype::getSize(), ghidra::Varnode::getSpace(), and ghidra::AddrSpace::isBigEndian().
Referenced by splitCopy(), and splitStore().
|
private |
Build input Varnodes by extracting SUBPIECEs from the root.
Extract different pieces from the given root based on the offsets and input data-types in dataTypePieces.
rootVn | is the given root Varnode |
followOp | is the point at which the SUBPIECEs should be inserted (before) |
inVarnodes | is the container for the new Varnodes |
References ghidra::CPUI_SUBPIECE, ghidra::PcodeOp::getAddr(), ghidra::Varnode::getAddr(), ghidra::Varnode::getSize(), ghidra::Datatype::getSize(), ghidra::Address::isBigEndian(), ghidra::Address::renormalize(), and ghidra::Varnode::updateType().
Referenced by splitCopy(), and splitStore().
|
private |
Concatenate output Varnodes into given root Varnode.
Insert PIECE operators concatenating all output Varnodes from most significant to least significant producing the root Varnode as the final result.
rootVn | is the given root Varnode |
previousOp | is the point at which to insert (after) |
outVarnodes | is the list of output Varnodes |
References ghidra::CPUI_PIECE, ghidra::PcodeOp::getAddr(), ghidra::Varnode::getAddr(), ghidra::Varnode::getSize(), ghidra::Varnode::hasNoDescend(), ghidra::Varnode::isAddrTied(), ghidra::Address::isBigEndian(), ghidra::Address::renormalize(), ghidra::PcodeOp::setPartialRoot(), and ghidra::Varnode::setProtoPartial().
Referenced by splitCopy(), and splitLoad().
|
private |
Build output Varnodes with storage based on the given root.
Extract different pieces from the given root based on the offsets and output data-types in dataTypePieces.
rootVn | is the given root Varnode |
inVarnodes | is the container for the new Varnodes |
References ghidra::Varnode::getAddr(), ghidra::Datatype::getSize(), and ghidra::Address::renormalize().
Referenced by splitCopy(), and splitLoad().
|
private |
Build a a series of PTRSUB ops at different offsets, given a root pointer.
Offsets and data-types are based on dataTypePieces, taking input data-types if isInput is true, output data-types otherwise. The data-types, relative to the root pointer, are assumed to start at the given base offset.
rootVn | is the root pointer |
ptrType | is the pointer data-type associated with the root |
baseOffset | is the given base offset |
followOp | is the point at which the new PTRSUB ops are inserted (before) |
ptrVarnodes | is the container for the new pointer Varnodes |
isInput | specifies either input (true) or output (false) data-types |
References ghidra::AddrSpace::byteToAddressInt(), ghidra::CPUI_PTRADD, ghidra::CPUI_PTRSUB, ghidra::PcodeOp::getAddr(), ghidra::Datatype::getMetatype(), ghidra::TypePointer::getPtrTo(), ghidra::Varnode::getSize(), ghidra::Datatype::getSize(), ghidra::Datatype::getSubType(), ghidra::TypePointer::getWordSize(), ghidra::TransformManager::newOp(), ghidra::TYPE_ARRAY, ghidra::TYPE_INT, and ghidra::Varnode::updateType().
Referenced by splitLoad(), and splitStore().
|
private |
Categorize if and how data-type should be split.
For the given data-type, taking into account configuration options, return:
ct | is the given data-type |
References ghidra::Datatype::getMetatype(), ghidra::Datatype::getSize(), ghidra::Datatype::numDepend(), ghidra::TYPE_ARRAY, ghidra::TYPE_INT, ghidra::TYPE_PARTIALSTRUCT, ghidra::TYPE_STRUCT, ghidra::TYPE_UINT, and ghidra::TYPE_UNKNOWN.
|
private |
If the given Varnode is an extended precision constant, create split constants.
Look for ZEXT(#c) and CONCAT(#c1,#c2) forms. Try to split into single precision Varnodes.
vn | is the given Varnode |
inVarnodes | will contain the split constant Varnodes |
References ghidra::calc_mask(), ghidra::PcodeOp::code(), ghidra::CPUI_INT_ZEXT, ghidra::CPUI_PIECE, ghidra::Varnode::getDef(), ghidra::PcodeOp::getIn(), ghidra::Varnode::getOffset(), ghidra::Varnode::getSize(), ghidra::Datatype::getSize(), ghidra::Varnode::getSpace(), ghidra::AddrSpace::isBigEndian(), ghidra::Varnode::isConstant(), ghidra::Varnode::isWritten(), and ghidra::Varnode::loneDescend().
|
private |
Obtain the component of the given data-type at the specified offset.
The data-type must be a composite of some form. This method finds a component data-type starting exactly at the offset, if it exists. The component may be nested more than 1 level deep. If the given data-type is of composite form and has no component defined at the specified offset, an undefined data-type matching the size of the hole is returned and isHole is set to true.
ct | is the given data-type |
offset | is the specified offset |
isHole | passes back whether a hole in the composite was encountered |
References ghidra::Datatype::getHoleSize(), ghidra::Datatype::getMetatype(), ghidra::Datatype::getSubType(), ghidra::TYPE_ARRAY, and ghidra::TYPE_UNKNOWN.
|
static |
Get a data-type description of the value being pointed at by the given LOAD or STORE.
Take the data-type of the pointer and construct the data-type of the thing being pointed at so that it matches a specific size. This takes into account TypePointerRel and can produce TypePartialStruct in order to match the size. If no interpretation of the value as a splittable data-type is possible, null is returned.
loadStore | is the given LOAD or STORE |
size | is the number of bytes in the value being pointed at |
tlst | is the TypeFactory for constructing partial data-types if necessary |
References ghidra::AddrSpace::addressToByteInt(), ghidra::TypeFactory::getExactPiece(), ghidra::PcodeOp::getIn(), ghidra::Datatype::getMetatype(), ghidra::TypePointerRel::getParent(), ghidra::TypePointerRel::getPointerOffset(), ghidra::Varnode::getTypeReadFacing(), ghidra::TypePointer::getWordSize(), ghidra::Datatype::isPointerRel(), ghidra::TYPE_ARRAY, ghidra::TYPE_PTR, and ghidra::TYPE_STRUCT.
Referenced by ghidra::RuleSplitLoad::applyOp(), ghidra::RuleSplitStore::applyOp(), and splitStore().
|
staticprivate |
Is this the input to an arithmetic operation.
Iterate through descendants of the given Varnode, looking for arithmetic ops.
vn | is the given Varnode |
References ghidra::Varnode::beginDescend(), ghidra::Varnode::endDescend(), ghidra::PcodeOp::getOpcode(), and ghidra::TypeOp::isArithmeticOp().
Referenced by splitCopy(), and splitLoad().
|
staticprivate |
Is this defined by an arithmetic operation.
Check if the defining PcodeOp is arithmetic.
vn | is the given Varnode |
References ghidra::Varnode::getDef(), ghidra::PcodeOp::getOpcode(), ghidra::TypeOp::isArithmeticOp(), and ghidra::Varnode::isWritten().
Referenced by splitCopy(), and splitStore().
Split a COPY operation.
Based on the input and output data-types, determine if and how the given COPY operation should be split into pieces. Then if possible, perform the split.
copyOp | is the given COPY |
inType | is the data-type of the COPY input |
outType | is the data-type of the COPY output |
References buildInConstants(), buildInSubpieces(), buildOutConcats(), buildOutVarnodes(), ghidra::CPUI_COPY, data, ghidra::PcodeOp::getAddr(), ghidra::PcodeOp::getIn(), ghidra::PcodeOp::getOut(), isArithmeticInput(), isArithmeticOutput(), ghidra::Varnode::isConstant(), ghidra::Funcdata::newOp(), ghidra::Funcdata::opDestroy(), ghidra::Funcdata::opInsertBefore(), ghidra::Funcdata::opSetInput(), ghidra::Funcdata::opSetOpcode(), ghidra::Funcdata::opSetOutput(), testCopyConstraints(), and testDatatypeCompatibility().
Referenced by ghidra::RuleSplitCopy::applyOp().
Split a LOAD operation.
Based on the LOAD data-type, determine if the given LOAD can be split into smaller LOADs. Then, if possible, perform the split. The input data-type describes the size and composition of the value being loaded. Check for the special case where, the LOAD output is a lone input to a COPY, and split the outputs of the COPY as well.
loadOp | is the given LOAD to split |
inType | is the data-type associated with the value being loaded |
References ghidra::SplitDatatype::RootPointer::baseOffset, buildOutConcats(), buildOutVarnodes(), buildPointers(), ghidra::PcodeOp::code(), ghidra::CPUI_COPY, ghidra::CPUI_LOAD, ghidra::CPUI_STORE, data, ghidra::SplitDatatype::RootPointer::find(), ghidra::SplitDatatype::RootPointer::freePointerChain(), ghidra::PcodeOp::getAddr(), ghidra::PcodeOp::getIn(), ghidra::PcodeOp::getOut(), ghidra::Varnode::getSpaceFromConst(), ghidra::Varnode::getTypeDefFacing(), ghidra::Varnode::isAddrTied(), isArithmeticInput(), ghidra::Varnode::loneDescend(), ghidra::Funcdata::newOp(), ghidra::Funcdata::newVarnodeSpace(), ghidra::Funcdata::opDestroy(), ghidra::Funcdata::opInsertBefore(), ghidra::Funcdata::opSetInput(), ghidra::Funcdata::opSetOpcode(), ghidra::Funcdata::opSetOutput(), ghidra::SplitDatatype::RootPointer::pointer, ghidra::SplitDatatype::RootPointer::ptrType, and testDatatypeCompatibility().
Referenced by ghidra::RuleSplitLoad::applyOp().
Split a STORE operation.
Based on the STORE data-type, determine if the given STORE can be split into smaller STOREs. Then, if possible, perform the split. The output data-type describes the size and composition of the value being stored.
storeOp | is the given STORE to split |
outType | is the data-type associated with the value being stored |
References ghidra::SplitDatatype::RootPointer::baseOffset, buildInConstants(), buildInSubpieces(), buildPointers(), ghidra::PcodeOp::code(), ghidra::CPUI_LOAD, ghidra::CPUI_STORE, data, dataTypePieces, ghidra::SplitDatatype::RootPointer::find(), ghidra::SplitDatatype::RootPointer::freePointerChain(), ghidra::PcodeOp::getAddr(), ghidra::Funcdata::getArch(), ghidra::Varnode::getDef(), ghidra::PcodeOp::getIn(), ghidra::Varnode::getSize(), ghidra::Datatype::getSize(), ghidra::Varnode::getSpaceFromConst(), ghidra::Varnode::getTypeReadFacing(), getValueDatatype(), isArithmeticOutput(), ghidra::Varnode::isConstant(), ghidra::Varnode::isWritten(), ghidra::Varnode::loneDescend(), ghidra::Funcdata::newOp(), ghidra::Funcdata::newUniqueOut(), ghidra::Funcdata::newVarnodeSpace(), ghidra::Funcdata::opDestroy(), ghidra::Funcdata::opInsertAfter(), ghidra::Funcdata::opInsertBefore(), ghidra::Funcdata::opSetInput(), ghidra::Funcdata::opSetOpcode(), ghidra::SplitDatatype::RootPointer::pointer, ghidra::SplitDatatype::RootPointer::ptrType, testDatatypeCompatibility(), ghidra::Architecture::types, and ghidra::Varnode::updateType().
Referenced by ghidra::RuleSplitStore::applyOp().
|
private |
Test specific constraints for splitting the given COPY operation into pieces.
Don't split function inputs. Don't split hidden COPYs.
References ghidra::PcodeOp::code(), ghidra::CPUI_LOAD, ghidra::Varnode::getAddr(), ghidra::Varnode::getDef(), ghidra::PcodeOp::getIn(), ghidra::PcodeOp::getOut(), ghidra::Varnode::isAddrTied(), ghidra::Varnode::isInput(), ghidra::Varnode::isWritten(), and ghidra::Varnode::loneDescend().
Referenced by splitCopy().
|
private |
Can the two given data-types be mutually split into matching logical components.
Test if the data-types have components with matching size and offset. If so, the component data-types and offsets are saved to the pieces array and true is returned. At least one of the data-types must be a partial data-type, but the other may be a TYPE_UNKNOWN, which this method assumes can be split into components of arbitrary size.
inBase | is the data-type coming into the operation |
outBase | is the data-type coming out of the operation |
inConstant | is true if the incoming data-type labels a constant |
References ghidra::Datatype::getMetatype(), ghidra::Datatype::getSize(), ghidra::TYPE_STRUCT, and ghidra::TYPE_UNKNOWN.
Referenced by splitCopy(), splitLoad(), and splitStore().