Ghidra 11.3.2
Ghidra internal decompiler documentation.
|
Class for tracing changes of precision in floating point variables. More...
#include <subflow.hh>
Classes | |
class | State |
Internal state for walking floating-point data-flow and computing precision. More... | |
Public Member Functions | |
SubfloatFlow (Funcdata *f, Varnode *root, int4 prec) | |
virtual bool | preserveAddress (Varnode *vn, int4 bitSize, int4 lsbOffset) const |
Should the address of the given Varnode be preserved when constructing a piece. | |
bool | doTrace (void) |
Trace logical value as far as possible. | |
![]() | |
TransformManager (Funcdata *f) | |
Constructor. | |
virtual | ~TransformManager (void) |
Destructor. | |
Funcdata * | getFunction (void) const |
Get function being transformed. | |
void | clearVarnodeMarks (void) |
Clear mark for all Varnodes in the map. | |
TransformVar * | newPreexistingVarnode (Varnode *vn) |
Make placeholder for preexisting Varnode. | |
TransformVar * | newUnique (int4 size) |
Make placeholder for new unique space Varnode. | |
TransformVar * | newConstant (int4 size, int4 lsbOffset, uintb val) |
Make placeholder for constant Varnode. | |
TransformVar * | newIop (Varnode *vn) |
Make placeholder for special iop constant. | |
TransformVar * | newPiece (Varnode *vn, int4 bitSize, int4 lsbOffset) |
Make placeholder for piece of a Varnode. | |
TransformVar * | newSplit (Varnode *vn, const LaneDescription &description) |
Create placeholder nodes splitting a Varnode into its lanes. | |
TransformVar * | newSplit (Varnode *vn, const LaneDescription &description, int4 numLanes, int4 startLane) |
Create placeholder nodes splitting a Varnode into a subset of lanes in the given description. | |
TransformOp * | newOpReplace (int4 numParams, OpCode opc, PcodeOp *replace) |
Create a new placeholder op intended to replace an existing op. | |
TransformOp * | newOp (int4 numParams, OpCode opc, TransformOp *follow) |
Create a new placeholder op that will not replace an existing op. | |
TransformOp * | newPreexistingOp (int4 numParams, OpCode opc, PcodeOp *originalOp) |
Create a new placeholder op for an existing PcodeOp. | |
TransformVar * | getPreexistingVarnode (Varnode *vn) |
Get (or create) placeholder for preexisting Varnode. | |
TransformVar * | getPiece (Varnode *vn, int4 bitSize, int4 lsbOffset) |
Get (or create) placeholder piece. | |
TransformVar * | getSplit (Varnode *vn, const LaneDescription &description) |
Find (or create) placeholder nodes splitting a Varnode into its lanes. | |
TransformVar * | getSplit (Varnode *vn, const LaneDescription &description, int4 numLanes, int4 startLane) |
Find (or create) placeholder nodes splitting a Varnode into a subset of lanes from a description. | |
void | opSetInput (TransformOp *rop, TransformVar *rvn, int4 slot) |
Mark given variable as input to given op. | |
void | opSetOutput (TransformOp *rop, TransformVar *rvn) |
Mark given variable as output of given op. | |
void | apply (void) |
Apply the full transform to the function. | |
Private Member Functions | |
int4 | maxPrecision (Varnode *vn) |
Calculate maximum floating-point precision reaching a given Varnode. | |
bool | exceedsPrecision (PcodeOp *op) |
Determine if the given op exceeds our precision. | |
TransformVar * | setReplacement (Varnode *vn) |
Create and return a placeholder associated with the given Varnode. | |
bool | traceForward (TransformVar *rvn) |
Try to trace logical variable through descendant Varnodes. | |
bool | traceBackward (TransformVar *rvn) |
Trace a logical value backward through defining op one level. | |
bool | processNextWork (void) |
Push the trace one hop from the placeholder at the top of the worklist. | |
Private Attributes | |
int4 | precision |
Number of bytes of precision in the logical flow. | |
int4 | terminatorCount |
Number of terminating nodes reachable via the root. | |
const FloatFormat * | format |
The floating-point format of the logical value. | |
vector< TransformVar * > | worklist |
Current list of placeholders that still need to be traced. | |
map< PcodeOp *, int4 > | maxPrecisionMap |
Maximum precision flowing into a particular floating-point op. | |
Additional Inherited Members | |
![]() | |
static bool | preexistingGuard (int4 slot, TransformVar *rvn) |
Should newPreexistingOp be called. | |
Class for tracing changes of precision in floating point variables.
It follows the flow of a logical lower precision value stored in higher precision locations and then rewrites the data-flow in terms of the lower precision, eliminating the precision conversions.
f | is the function being transformed |
root | is the start Varnode containing the logical value |
prec | is the precision to assume for the logical value |
References format, ghidra::Funcdata::getArch(), ghidra::Translate::getFloatFormat(), precision, setReplacement(), and ghidra::Architecture::translate.
bool ghidra::SubfloatFlow::doTrace | ( | void | ) |
Trace logical value as far as possible.
The interpretation that the root Varnode contains a logical value with smaller precision is pushed through the data-flow. If the interpretation is inconsistent, false is returned. Otherwise a transform is constructed that makes the smaller precision the explicit size of Varnodes within the data-flow.
References ghidra::TransformManager::clearVarnodeMarks(), format, processNextWork(), terminatorCount, and worklist.
Referenced by ghidra::RuleSubfloatConvert::applyOp().
|
private |
Determine if the given op exceeds our precision.
This is called only for binary floating-point ops: FLOAT_ADD, FLOAT_MULT, FLOAT_LESS, etc. If the maximum precision reaching both input operands exceeds the precision established for this Rule, true is returned, indicating the op cannot be truncated without losing precision. We count on the fact that this test is applied to all binary operations encountered during Rule application. This method will correctly return true for the earliest operations whose inputs both exceed the precision, but, because of the way maxPrecision() is calculated, it may incorrectly return false for later operations.
op | is the given binary floating-point PcodeOp |
References ghidra::PcodeOp::getIn(), maxPrecision(), and precision.
Referenced by traceBackward(), and traceForward().
|
private |
Calculate maximum floating-point precision reaching a given Varnode.
This method distinguishes between a floating-point variable with full precision, where all the storage can vary (or is unknown), versus a value that is extended from a floating-point variable with smaller storage. Within the data-flow above the given Varnode, we search for the maximum precision coming through MULTIEQUAL, COPY, and unary floating-point operations. Binary operations like FLOAT_ADD and FLOAT_MULT are not traversed and are assumed to produce a smaller precision. If the method indicates full precision for the given Varnode, or if the data-flow does not involve binary floating-point operations, it is accurate, otherwise it may under report the precision.
vn | is the given Varnode |
References ghidra::PcodeOp::clearMark(), ghidra::PcodeOp::code(), ghidra::CPUI_COPY, ghidra::CPUI_FLOAT_ABS, ghidra::CPUI_FLOAT_ADD, ghidra::CPUI_FLOAT_CEIL, ghidra::CPUI_FLOAT_DIV, ghidra::CPUI_FLOAT_FLOAT2FLOAT, ghidra::CPUI_FLOAT_FLOOR, ghidra::CPUI_FLOAT_INT2FLOAT, ghidra::CPUI_FLOAT_MULT, ghidra::CPUI_FLOAT_NEG, ghidra::CPUI_FLOAT_ROUND, ghidra::CPUI_FLOAT_SQRT, ghidra::CPUI_FLOAT_SUB, ghidra::CPUI_MULTIEQUAL, ghidra::Varnode::getDef(), ghidra::PcodeOp::getIn(), ghidra::Varnode::getSize(), ghidra::SubfloatFlow::State::incorporateInputSize(), ghidra::PcodeOp::isMark(), ghidra::Varnode::isWritten(), ghidra::SubfloatFlow::State::maxPrecision, maxPrecisionMap, ghidra::PcodeOp::numInput(), ghidra::SubfloatFlow::State::op, ghidra::PcodeOp::setMark(), and ghidra::SubfloatFlow::State::slot.
Referenced by exceedsPrecision().
|
virtual |
Should the address of the given Varnode be preserved when constructing a piece.
A new Varnode will be created that represents a logical piece of the given Varnode. This routine determines whether the new Varnode should be constructed using storage which overlaps the given Varnode. It returns true if overlapping storage should be used, false if the new Varnode should be constructed as a unique temporary.
vn | is the given Varnode |
bitSize | is the logical size of the Varnode piece being constructed |
lsbOffset | is the least significant bit position of the logical value within the given Varnode |
Reimplemented from ghidra::TransformManager.
References ghidra::Varnode::isInput().
|
private |
Push the trace one hop from the placeholder at the top of the worklist.
The logical value for the value on top of the worklist stack is pushed back to the input Varnodes of the operation defining it. Then the value is pushed forward through all operations that read it.
References traceBackward(), traceForward(), and worklist.
Referenced by doTrace().
|
private |
Create and return a placeholder associated with the given Varnode.
Add the placeholder to the worklist if it hasn't been visited before
vn | is the given Varnode |
References ghidra::FloatFormat::convertEncoding(), format, ghidra::Funcdata::getArch(), ghidra::Translate::getFloatFormat(), ghidra::TransformManager::getFunction(), ghidra::Datatype::getMetatype(), ghidra::Varnode::getOffset(), ghidra::TransformManager::getPiece(), ghidra::Datatype::getSize(), ghidra::Varnode::getSize(), ghidra::Varnode::getType(), ghidra::Varnode::isAddrForce(), ghidra::Varnode::isConstant(), ghidra::Varnode::isFree(), ghidra::Varnode::isInput(), ghidra::Varnode::isMark(), ghidra::Varnode::isTypeLock(), ghidra::TransformManager::newConstant(), ghidra::TransformManager::newPiece(), ghidra::TransformManager::newPreexistingVarnode(), precision, ghidra::Varnode::setMark(), ghidra::Architecture::translate, ghidra::TYPE_PARTIALSTRUCT, and worklist.
Referenced by SubfloatFlow(), traceBackward(), and traceForward().
|
private |
Trace a logical value backward through defining op one level.
Given an existing variable placeholder look at the op defining it and define placeholder variables for all its inputs. Put the new placeholders onto the worklist if appropriate.
rvn | is the given variable placeholder |
References ghidra::PcodeOp::code(), ghidra::CPUI_COPY, ghidra::CPUI_FLOAT_ABS, ghidra::CPUI_FLOAT_ADD, ghidra::CPUI_FLOAT_CEIL, ghidra::CPUI_FLOAT_DIV, ghidra::CPUI_FLOAT_FLOAT2FLOAT, ghidra::CPUI_FLOAT_FLOOR, ghidra::CPUI_FLOAT_INT2FLOAT, ghidra::CPUI_FLOAT_MULT, ghidra::CPUI_FLOAT_NEG, ghidra::CPUI_FLOAT_ROUND, ghidra::CPUI_FLOAT_SQRT, ghidra::CPUI_FLOAT_SUB, ghidra::CPUI_MULTIEQUAL, exceedsPrecision(), ghidra::Varnode::getDef(), ghidra::TransformVar::getDef(), ghidra::TransformOp::getIn(), ghidra::PcodeOp::getIn(), ghidra::Varnode::getOffset(), ghidra::TransformVar::getOriginal(), ghidra::TransformManager::getPreexistingVarnode(), ghidra::Varnode::getSize(), ghidra::Varnode::isConstant(), ghidra::Varnode::isFree(), ghidra::TransformManager::newConstant(), ghidra::TransformManager::newOpReplace(), ghidra::PcodeOp::numInput(), ghidra::TransformManager::opSetInput(), ghidra::TransformManager::opSetOutput(), precision, and setReplacement().
Referenced by processNextWork().
|
private |
Try to trace logical variable through descendant Varnodes.
Given a Varnode placeholder, look at all descendant PcodeOps and create placeholders for the op and its output Varnode. If appropriate add the output placeholder to the worklist.
rvn | is the given Varnode placeholder |
References ghidra::Varnode::beginDescend(), ghidra::PcodeOp::code(), 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_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_MULTIEQUAL, ghidra::Varnode::endDescend(), exceedsPrecision(), ghidra::PcodeOp::getIn(), ghidra::TransformVar::getOriginal(), ghidra::PcodeOp::getOut(), ghidra::PcodeOp::getRepeatSlot(), ghidra::Varnode::getSize(), ghidra::PcodeOp::getSlot(), ghidra::Varnode::isMark(), ghidra::TransformManager::newOpReplace(), ghidra::TransformManager::newPreexistingOp(), ghidra::PcodeOp::numInput(), ghidra::TransformManager::opSetInput(), ghidra::TransformManager::opSetOutput(), precision, ghidra::TransformManager::preexistingGuard(), setReplacement(), and terminatorCount.
Referenced by processNextWork().