decompiler
1.0.0
|
Analyze data-flow to resolve which field of a union data-type is being accessed. More...
#include <unionresolve.hh>
Classes | |
class | Trial |
A trial data-type fitted to a specific place in the data-flow. More... | |
class | VisitMark |
A mark accumulated when a given Varnode is visited with a specific field index. More... | |
Public Member Functions | |
ScoreUnionFields (TypeFactory &tgrp, Datatype *parentType, PcodeOp *op, int4 slot) | |
Score a given data-type involving a union against data-flow. More... | |
ScoreUnionFields (TypeFactory &tgrp, TypeUnion *unionType, int4 offset, PcodeOp *op) | |
Score a union data-type against data-flow, where there is a SUBPIECE. More... | |
ScoreUnionFields (TypeFactory &tgrp, TypeUnion *unionType, int4 offset, PcodeOp *op, int4 slot) | |
Score a union data-type against data-flow, where there is an implied truncation. More... | |
const ResolvedUnion & | getResult (void) const |
Get the resulting best field resolution. | |
Private Member Functions | |
bool | testArrayArithmetic (PcodeOp *op, int4 inslot) |
Check if given PcodeOp is operating on array with union elements. More... | |
bool | testSimpleCases (PcodeOp *op, int4 inslot, Datatype *parent) |
Preliminary checks before doing full scoring. More... | |
int4 | scoreLockedType (Datatype *ct, Datatype *lockType) |
Score trial data-type against a locked data-type. More... | |
int4 | scoreParameter (Datatype *ct, const PcodeOp *callOp, int4 paramSlot) |
Score trial data-type against a parameter. More... | |
int4 | scoreReturnType (Datatype *ct, const PcodeOp *callOp) |
Score trial data-type against return data-type of function. More... | |
Datatype * | derefPointer (Datatype *ct, Varnode *vn, int4 &score) |
Score trial data-type as a pointer to LOAD/STORE. More... | |
void | newTrialsDown (Varnode *vn, Datatype *ct, int4 scoreIndex, bool isArray) |
Create new trials based an reads of given Varnode. More... | |
void | newTrials (PcodeOp *op, int4 slot, Datatype *ct, int4 scoreIndex, bool isArray) |
Create new trials based on given input slot. More... | |
void | scoreTrialDown (const Trial &trial, bool lastLevel) |
Try to fit the given trial following data-flow down. More... | |
void | scoreTrialUp (const Trial &trial, bool lastLevel) |
Try to fit the given trial following data-flow up. | |
Datatype * | scoreTruncation (Datatype *ct, Varnode *vn, int4 offset, int4 scoreIndex) |
Score a truncation in the data-flow. More... | |
void | scoreConstantFit (const Trial &trial) |
Score trial data-type against a constant. More... | |
void | runOneLevel (bool lastPass) |
Score all the current trials. More... | |
void | computeBestIndex (void) |
Assuming scoring is complete, compute the best index. | |
void | run (void) |
Calculate best fitting field. More... | |
Private Attributes | |
TypeFactory & | typegrp |
The factory containing data-types. | |
vector< int4 > | scores |
Score for each field, indexed by fieldNum + 1 (whole union is index=0) | |
vector< Datatype * > | fields |
Field corresponding to each score. | |
set< VisitMark > | visited |
Places that have already been visited. | |
list< Trial > | trialCurrent |
Current trials being pushed. | |
list< Trial > | trialNext |
Next set of trials. | |
ResolvedUnion | result |
The best result. | |
int4 | trialCount |
Number of trials evaluated so far. | |
Static Private Attributes | |
static const int4 | maxPasses = 6 |
Maximum number of levels to score through. | |
static const int4 | threshold = 256 |
Threshold of trials over which to cancel additional passes. | |
static const int4 | maxTrials = 1024 |
Maximum number of trials to evaluate. | |
Analyze data-flow to resolve which field of a union data-type is being accessed.
A Varnode with a data-type that is either a union, a pointer to union, or a part of a union, can be accessed in multiple ways. Each individual read (or write) of the Varnode may be accessing either a specific field of the union or accessing the union as a whole. The particular access may not be explicitly known but can sometimes be inferred from data-flow near the Varnode. This class scores all the possible fields of a data-type involving a union for a specific Varnode.
Because the answer may be different for different accesses, the Varnode must be specified as an access edge, a PcodeOp and a slot. A slot >= 0 indicates the index of a Varnode that is being read by the PcodeOp, a slot == -1 indicates the output Varnode being written by the PcodeOp.
The result of scoring is returned as a ResolvedUnion record.
ghidra::ScoreUnionFields::ScoreUnionFields | ( | TypeFactory & | tgrp, |
Datatype * | parentType, | ||
PcodeOp * | op, | ||
int4 | slot | ||
) |
Score a given data-type involving a union against data-flow.
The data-type must either be a union or a pointer to union. Set up the initial set of trials based on the given data-flow edge (PcodeOp and slot).
tgrp | is the TypeFactory owning the data-types |
parentType | is the given data-type to score |
op | is PcodeOp of the given data-flow edge |
slot | is slot of the given data-flow edge |
References ghidra::ResolvedUnion::baseType, computeBestIndex(), fields, ghidra::Datatype::getDepend(), ghidra::PcodeOp::getIn(), ghidra::Datatype::getMetatype(), ghidra::PcodeOp::getOut(), ghidra::Varnode::getSize(), ghidra::Datatype::getSize(), ghidra::TypeFactory::getTypePointerStripArray(), ghidra::Datatype::numDepend(), result, run(), scores, testSimpleCases(), trialCurrent, ghidra::TYPE_ARRAY, ghidra::TYPE_PTR, typegrp, and visited.
ghidra::ScoreUnionFields::ScoreUnionFields | ( | TypeFactory & | tgrp, |
TypeUnion * | unionType, | ||
int4 | offset, | ||
PcodeOp * | op | ||
) |
Score a union data-type against data-flow, where there is a SUBPIECE.
A truncation is fit to each union field before doing the fit against data-flow. Only fields that match the offset and the truncation size (of the SUBPIECE) are scored further. If there is a good fit, the scoring for that field recurses into the given data-flow edge. This is only used where there is a SUBPIECE and the base scoring indicates the whole union is the best match for the input.
tgrp | is the TypeFactory owning the data-types |
unionType | is the data-type to score, which must be a TypeUnion |
offset | is the given starting offset of the truncation |
op | is the SUBPIECE op |
References computeBestIndex(), fields, ghidra::TypeUnion::getField(), ghidra::PcodeOp::getOut(), ghidra::Varnode::getSize(), ghidra::Datatype::getSize(), newTrialsDown(), ghidra::TypeUnion::numDepend(), ghidra::TypeField::offset, run(), scores, trialCurrent, trialNext, and ghidra::TypeField::type.
ghidra::ScoreUnionFields::ScoreUnionFields | ( | TypeFactory & | tgrp, |
TypeUnion * | unionType, | ||
int4 | offset, | ||
PcodeOp * | op, | ||
int4 | slot | ||
) |
Score a union data-type against data-flow, where there is an implied truncation.
A truncation is fit to each union field before doing the fit against data-flow, starting with the given PcodeOp and input slot.
tgrp | is the TypeFactory owning the data-types |
unionType | is the data-type to score, which must be a TypeUnion |
offset | is the given starting offset of the truncation |
op | is the PcodeOp initially reading/writing the union |
slot | is the -1 if the op is writing, >= 0 if reading |
References computeBestIndex(), fields, ghidra::TypeUnion::getField(), ghidra::PcodeOp::getIn(), ghidra::PcodeOp::getOut(), ghidra::TypeUnion::numDepend(), ghidra::TypeField::offset, run(), scores, scoreTruncation(), trialCurrent, ghidra::TypeField::type, and visited.
|
private |
Score trial data-type as a pointer to LOAD/STORE.
Test if the data-type is a pointer and if the pointed-to data-type is compatible with the size of the value being loaded or stored. A score is passed back for how closely the data-type fits this scenario, and if it does we return the data-type of the pointer value.
ct | is the trial data-type |
vn | is the Varnode holding the value being loaded or stored |
score | is used to pass back the score |
References ghidra::Datatype::getMetatype(), ghidra::Varnode::getSize(), ghidra::Datatype::getSize(), ghidra::Datatype::getSubType(), and ghidra::TYPE_PTR.
|
private |
Create new trials based on given input slot.
If the input slot is a Varnode that has already been visited, no new trial is created
op | is the PcodeOp with the given slot |
slot | is the index of the given input slot |
ct | is the data-type to associate with the trial |
scoreIndex | is the field index to score the trial against |
isArray | is true if the data-type to fit is a pointer to an array |
References ghidra::Varnode::beginDescend(), ghidra::Varnode::endDescend(), ghidra::PcodeOp::getIn(), ghidra::PcodeOp::getSlot(), ghidra::Varnode::getType(), and ghidra::Varnode::isTypeLock().
|
private |
Create new trials based an reads of given Varnode.
If the Varnode has already been visited, no new trials are created
vn | is the given Varnode |
ct | is the data-type to associate with the trial |
scoreIndex | is the field index to score the trial against |
isArray | is true if the data-type to fit is a pointer to an array |
References ghidra::Varnode::beginDescend(), ghidra::Varnode::endDescend(), ghidra::PcodeOp::getSlot(), ghidra::Varnode::getType(), and ghidra::Varnode::isTypeLock().
Referenced by ScoreUnionFields().
|
private |
Calculate best fitting field.
Try to fit each possible field over multiple levels of the data-flow. Return the index of the highest scoring field or -1 if the union data-type itself is the best fit.
Referenced by ScoreUnionFields().
|
private |
Score all the current trials.
Run through each trial in the current list and compute a score. If the trial recurses and this is not the final pass, build new trials for the recursion.
lastPass | is true if this is the last pass |
|
private |
Score trial data-type against a constant.
Assume the constant has no data-type of its own to match against. Evaluate if the constant looks like an integer or pointer etc. and score the trial data-type against that.
trial | is the trial of the constant Varnode |
References ghidra::FloatFormat::extractExponentCode(), ghidra::ScoreUnionFields::Trial::fitType, ghidra::Datatype::getMetatype(), ghidra::Varnode::getOffset(), ghidra::AddrSpace::getPointerLowerBound(), ghidra::AddrSpace::getPointerUpperBound(), ghidra::Varnode::getSize(), ghidra::ScoreUnionFields::Trial::scoreIndex, ghidra::TYPE_BOOL, ghidra::TYPE_FLOAT, ghidra::TYPE_INT, ghidra::TYPE_PTR, ghidra::TYPE_UINT, and ghidra::ScoreUnionFields::Trial::vn.
Score trial data-type against a locked data-type.
A trial that encounters a locked data-type does not propagate through it but scores the trial data-type against the locked data-type.
ct | is the trial data-type |
lockType | is the locked data-type |
References ghidra::Datatype::getMetatype(), ghidra::Datatype::getSize(), ghidra::TYPE_ARRAY, ghidra::TYPE_CODE, ghidra::TYPE_INT, ghidra::TYPE_PTR, ghidra::TYPE_STRUCT, ghidra::TYPE_UINT, and ghidra::TYPE_UNION.
|
private |
Score trial data-type against a parameter.
Look up the call-specs for the given CALL. If the inputs are locked, find the corresponding parameter and score the trial data-type against it.
ct | is the trial data-type |
callOp | is the CALL |
paramSlot | is the input slot of the trial data-type |
References ghidra::Funcdata::getCallSpecs(), ghidra::BlockBasic::getFuncdata(), ghidra::Datatype::getMetatype(), ghidra::FuncProto::getParam(), ghidra::PcodeOp::getParent(), ghidra::ProtoParameter::getType(), ghidra::FuncProto::isInputLocked(), ghidra::FuncProto::numParams(), ghidra::TYPE_ARRAY, ghidra::TYPE_CODE, ghidra::TYPE_STRUCT, and ghidra::TYPE_UNION.
Score trial data-type against return data-type of function.
Look up the call-specs for the given CALL. If the output is locked, score the trial data-type against it.
ct | is the trial data-type |
callOp | is the CALL |
References ghidra::Funcdata::getCallSpecs(), ghidra::BlockBasic::getFuncdata(), ghidra::Datatype::getMetatype(), ghidra::FuncProto::getOutputType(), ghidra::PcodeOp::getParent(), ghidra::FuncProto::isOutputLocked(), ghidra::TYPE_ARRAY, ghidra::TYPE_CODE, ghidra::TYPE_STRUCT, and ghidra::TYPE_UNION.
|
private |
Try to fit the given trial following data-flow down.
The trial's data-type is fitted to its PcodeOp as the incoming Varnode and a score is computed and added to the score for the trial's union field. The fitting may produce a new data-type which indicates scoring for the trial recurses into the output. This method builds trials for any new data-type unless lastLevel is true Varnode of its PcodeOp.
trial | is the given trial |
lastLevel | is true if the method should skip building new trials |
References ghidra::ScoreUnionFields::Trial::array, ghidra::ResolvedUnion::baseType, ghidra::PcodeOp::code(), ghidra::TypeOpSubpiece::computeByteOffsetForComposite(), ghidra::CPUI_BOOL_AND, ghidra::CPUI_BOOL_NEGATE, ghidra::CPUI_BOOL_OR, ghidra::CPUI_BOOL_XOR, ghidra::CPUI_BRANCHIND, ghidra::CPUI_CALL, ghidra::CPUI_CALLIND, ghidra::CPUI_CALLOTHER, ghidra::CPUI_CBRANCH, ghidra::CPUI_COPY, ghidra::CPUI_FLOAT_ABS, ghidra::CPUI_FLOAT_ADD, ghidra::CPUI_FLOAT_CEIL, ghidra::CPUI_FLOAT_DIV, ghidra::CPUI_FLOAT_EQUAL, ghidra::CPUI_FLOAT_FLOAT2FLOAT, ghidra::CPUI_FLOAT_FLOOR, ghidra::CPUI_FLOAT_INT2FLOAT, ghidra::CPUI_FLOAT_LESS, ghidra::CPUI_FLOAT_LESSEQUAL, ghidra::CPUI_FLOAT_MULT, ghidra::CPUI_FLOAT_NAN, ghidra::CPUI_FLOAT_NEG, ghidra::CPUI_FLOAT_NOTEQUAL, ghidra::CPUI_FLOAT_ROUND, ghidra::CPUI_FLOAT_SQRT, ghidra::CPUI_FLOAT_SUB, ghidra::CPUI_FLOAT_TRUNC, ghidra::CPUI_INDIRECT, ghidra::CPUI_INT_2COMP, ghidra::CPUI_INT_ADD, ghidra::CPUI_INT_AND, ghidra::CPUI_INT_CARRY, ghidra::CPUI_INT_DIV, 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_REM, ghidra::CPUI_INT_RIGHT, ghidra::CPUI_INT_SBORROW, ghidra::CPUI_INT_SCARRY, ghidra::CPUI_INT_SDIV, ghidra::CPUI_INT_SEXT, ghidra::CPUI_INT_SLESS, ghidra::CPUI_INT_SLESSEQUAL, ghidra::CPUI_INT_SREM, ghidra::CPUI_INT_SRIGHT, ghidra::CPUI_INT_SUB, ghidra::CPUI_INT_XOR, ghidra::CPUI_INT_ZEXT, ghidra::CPUI_LOAD, ghidra::CPUI_LZCOUNT, ghidra::CPUI_MULTIEQUAL, ghidra::CPUI_PIECE, ghidra::CPUI_POPCOUNT, ghidra::CPUI_PTRADD, ghidra::CPUI_PTRSUB, ghidra::CPUI_RETURN, ghidra::CPUI_SEGMENTOP, ghidra::CPUI_STORE, ghidra::CPUI_SUBPIECE, ghidra::ScoreUnionFields::Trial::direction, ghidra::TypePointer::downChain(), ghidra::ScoreUnionFields::Trial::fitType, ghidra::Varnode::getDef(), ghidra::PcodeOp::getIn(), ghidra::Datatype::getMetatype(), ghidra::Varnode::getOffset(), ghidra::PcodeOp::getOut(), ghidra::TypePointer::getPtrTo(), ghidra::Datatype::getSize(), ghidra::ScoreUnionFields::Trial::inslot, ghidra::Varnode::isConstant(), ghidra::Varnode::isWritten(), ghidra::ScoreUnionFields::Trial::op, ghidra::ScoreUnionFields::Trial::scoreIndex, ghidra::TYPE_ARRAY, ghidra::TYPE_BOOL, ghidra::TYPE_CODE, ghidra::TYPE_FLOAT, ghidra::TYPE_INT, ghidra::TYPE_PTR, ghidra::TYPE_STRUCT, ghidra::TYPE_UINT, ghidra::TYPE_UNION, and ghidra::TYPE_UNKNOWN.
|
private |
Score a truncation in the data-flow.
The truncation may be an explicit CPUI_SUBPIECE, or it may be implied. A score is computed for fitting a given data-type to the truncation, and a possible data-type to recurse is also computed.
ct | is the given data-type to truncate |
vn | is the Varnode the truncation will fit into |
offset | is the number of bytes truncated off the start of the data-type |
scoreIndex | is the field being scored |
References ghidra::TypeUnion::getField(), ghidra::Datatype::getMetatype(), ghidra::Varnode::getSize(), ghidra::Datatype::getSize(), ghidra::Datatype::getSubType(), ghidra::TypeUnion::numDepend(), ghidra::TypeField::offset, ghidra::TypeField::type, ghidra::TYPE_INT, ghidra::TYPE_UINT, and ghidra::TYPE_UNION.
Referenced by ScoreUnionFields().
|
private |
Check if given PcodeOp is operating on array with union elements.
If the op is adding a constant size or a multiple of a constant size to the given input slot, where the size is at least as large as the union, return true.
op | is the given PcodeOp |
inslot | is given input slot |
References ghidra::PcodeOp::code(), ghidra::CPUI_INT_ADD, ghidra::CPUI_INT_MULT, ghidra::CPUI_PTRADD, ghidra::Varnode::getDef(), ghidra::PcodeOp::getIn(), ghidra::Varnode::getOffset(), ghidra::Varnode::isConstant(), and ghidra::Varnode::isWritten().
|
private |
Preliminary checks before doing full scoring.
Identify cases where we know the union shouldn't be resolved to a field.
op | is the PcodeOp manipulating the union variable |
inslot | is -1 if the union is the output, >=0 if the union is an input to the op |
parent | is the parent union or pointer to union |
References ghidra::PcodeOp::code(), ghidra::CPUI_COPY, ghidra::Datatype::getMetatype(), ghidra::PcodeOp::getOut(), ghidra::PcodeOp::isMarker(), ghidra::Varnode::isTypeLock(), and ghidra::TYPE_PTR.
Referenced by ScoreUnionFields().