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

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 DatatypegetValueDatatype (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

DatatypegetComponent (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

Funcdatadata
 The containing function.
 
TypeFactorytypes
 The data-type container.
 
vector< ComponentdataTypePieces
 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.
 

Detailed Description

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.

Member Function Documentation

◆ buildInConstants()

void ghidra::SplitDatatype::buildInConstants ( Varnode rootVn,
vector< Varnode *> &  inVarnodes 
)
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.

Parameters
rootVnis the given root constant
inVarnodesis 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().

◆ buildInSubpieces()

void ghidra::SplitDatatype::buildInSubpieces ( Varnode rootVn,
PcodeOp followOp,
vector< Varnode *> &  inVarnodes 
)
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.

Parameters
rootVnis the given root Varnode
followOpis the point at which the SUBPIECEs should be inserted (before)
inVarnodesis 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().

◆ buildOutConcats()

void ghidra::SplitDatatype::buildOutConcats ( Varnode rootVn,
PcodeOp previousOp,
vector< Varnode *> &  outVarnodes 
)
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.

Parameters
rootVnis the given root Varnode
previousOpis the point at which to insert (after)
outVarnodesis 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().

◆ buildOutVarnodes()

void ghidra::SplitDatatype::buildOutVarnodes ( Varnode rootVn,
vector< Varnode *> &  outVarnodes 
)
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.

Parameters
rootVnis the given root Varnode
inVarnodesis the container for the new Varnodes

References ghidra::Varnode::getAddr(), ghidra::Datatype::getSize(), and ghidra::Address::renormalize().

Referenced by splitCopy(), and splitLoad().

◆ buildPointers()

void ghidra::SplitDatatype::buildPointers ( Varnode rootVn,
TypePointer ptrType,
int4  baseOffset,
PcodeOp followOp,
vector< Varnode *> &  ptrVarnodes,
bool  isInput 
)
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.

Parameters
rootVnis the root pointer
ptrTypeis the pointer data-type associated with the root
baseOffsetis the given base offset
followOpis the point at which the new PTRSUB ops are inserted (before)
ptrVarnodesis the container for the new pointer Varnodes
isInputspecifies 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().

◆ categorizeDatatype()

int4 ghidra::SplitDatatype::categorizeDatatype ( Datatype ct)
private

Categorize if and how data-type should be split.

For the given data-type, taking into account configuration options, return:

  • -1 for not splittable
  • 0 for data-type that needs to be split
  • 1 for data-type that can be split multiple ways
    Parameters
    ctis the given data-type
    Returns
    the categorization

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.

◆ generateConstants()

bool ghidra::SplitDatatype::generateConstants ( Varnode vn,
vector< Varnode *> &  inVarnodes 
)
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.

Parameters
vnis the given Varnode
inVarnodeswill contain the split constant Varnodes
Returns
true if the Varnode is an extended precision constant and the split is successful

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().

◆ getComponent()

Datatype * ghidra::SplitDatatype::getComponent ( Datatype ct,
int4  offset,
bool &  isHole 
)
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.

Parameters
ctis the given data-type
offsetis the specified offset
isHolepasses back whether a hole in the composite was encountered
Returns
the component data-type at the offset or null, if no such component exists

References ghidra::Datatype::getHoleSize(), ghidra::Datatype::getMetatype(), ghidra::Datatype::getSubType(), ghidra::TYPE_ARRAY, and ghidra::TYPE_UNKNOWN.

◆ getValueDatatype()

Datatype * ghidra::SplitDatatype::getValueDatatype ( PcodeOp loadStore,
int4  size,
TypeFactory tlst 
)
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.

Parameters
loadStoreis the given LOAD or STORE
sizeis the number of bytes in the value being pointed at
tlstis the TypeFactory for constructing partial data-types if necessary
Returns
the data-type description of the value or null

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().

◆ isArithmeticInput()

bool ghidra::SplitDatatype::isArithmeticInput ( Varnode vn)
staticprivate

Is this the input to an arithmetic operation.

Iterate through descendants of the given Varnode, looking for arithmetic ops.

Parameters
vnis the given Varnode
Returns
true if the Varnode has an arithmetic op as a descendant

References ghidra::Varnode::beginDescend(), ghidra::Varnode::endDescend(), ghidra::PcodeOp::getOpcode(), and ghidra::TypeOp::isArithmeticOp().

Referenced by splitCopy(), and splitLoad().

◆ isArithmeticOutput()

bool ghidra::SplitDatatype::isArithmeticOutput ( Varnode vn)
staticprivate

Is this defined by an arithmetic operation.

Check if the defining PcodeOp is arithmetic.

Parameters
vnis the given Varnode
Returns
true if the defining op is arithemetic

References ghidra::Varnode::getDef(), ghidra::PcodeOp::getOpcode(), ghidra::TypeOp::isArithmeticOp(), and ghidra::Varnode::isWritten().

Referenced by splitCopy(), and splitStore().

◆ splitCopy()

bool ghidra::SplitDatatype::splitCopy ( PcodeOp copyOp,
Datatype inType,
Datatype outType 
)

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.

Parameters
copyOpis the given COPY
inTypeis the data-type of the COPY input
outTypeis the data-type of the COPY output
Returns
true if the split was performed

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().

◆ splitLoad()

bool ghidra::SplitDatatype::splitLoad ( PcodeOp loadOp,
Datatype inType 
)

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.

Parameters
loadOpis the given LOAD to split
inTypeis the data-type associated with the value being loaded
Returns
true if the split was performed

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().

◆ splitStore()

bool ghidra::SplitDatatype::splitStore ( PcodeOp storeOp,
Datatype outType 
)

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.

Parameters
storeOpis the given STORE to split
outTypeis the data-type associated with the value being stored
Returns
true if the split was performed

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().

◆ testCopyConstraints()

bool ghidra::SplitDatatype::testCopyConstraints ( PcodeOp copyOp)
private

Test specific constraints for splitting the given COPY operation into pieces.

Don't split function inputs. Don't split hidden COPYs.

Returns
true if the split can proceed

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().

◆ testDatatypeCompatibility()

bool ghidra::SplitDatatype::testDatatypeCompatibility ( Datatype inBase,
Datatype outBase,
bool  inConstant 
)
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.

Parameters
inBaseis the data-type coming into the operation
outBaseis the data-type coming out of the operation
inConstantis true if the incoming data-type labels a constant
Returns
true if the data-types have compatible components, false otherwise

References ghidra::Datatype::getMetatype(), ghidra::Datatype::getSize(), ghidra::TYPE_STRUCT, and ghidra::TYPE_UNKNOWN.

Referenced by splitCopy(), splitLoad(), and splitStore().


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