decompiler
1.0.0
|
A high-level variable modeled as a list of low-level variables, each written once. More...
#include <variable.hh>
Public Types | |
enum | { flagsdirty = 1, namerepdirty = 2, typedirty = 4, coverdirty = 8, symboldirty = 0x10, copy_in1 = 0x20, copy_in2 = 0x40, type_finalized = 0x80, unmerged = 0x100, intersectdirty = 0x200, extendcoverdirty = 0x400 } |
Dirtiness flags for a HighVariable. More... | |
Public Member Functions | |
HighVariable (Varnode *vn) | |
Construct a HighVariable with a single member Varnode. More... | |
~HighVariable (void) | |
Destructor. | |
Datatype * | getType (void) const |
Get the data-type. | |
const Cover & | getCover (void) const |
Get cover data for this variable. More... | |
Symbol * | getSymbol (void) const |
Get the Symbol associated with this or null. | |
SymbolEntry * | getSymbolEntry (void) const |
int4 | getSymbolOffset (void) const |
Get the SymbolEntry mapping to this or null. More... | |
int4 | numInstances (void) const |
Get the number of member Varnodes this has. | |
Varnode * | getInstance (int4 i) const |
Get the i-th member Varnode. | |
void | finalizeDatatype (Datatype *tp) |
Set a final datatype for this variable. More... | |
void | groupWith (int4 off, HighVariable *hi2) |
Put this and another HighVariable in the same intersection group. More... | |
void | establishGroupSymbolOffset (void) |
Transfer symbol offset of this to the VariableGroup. More... | |
void | printCover (ostream &s) const |
Print details of the cover for this (for debug purposes) More... | |
void | printInfo (ostream &s) const |
Print information about this HighVariable to stream. More... | |
bool | hasName (void) const |
Check if this HighVariable can be named. More... | |
Varnode * | getTiedVarnode (void) const |
Find the first address tied member Varnode. More... | |
Varnode * | getInputVarnode (void) const |
Find (the) input member Varnode. More... | |
Varnode * | getTypeRepresentative (void) const |
Get a member Varnode with the strongest data-type. More... | |
Varnode * | getNameRepresentative (void) const |
Get a member Varnode that dictates the naming of this HighVariable. More... | |
int4 | getNumMergeClasses (void) const |
Get the number of speculative merges for this. | |
bool | isMapped (void) const |
Return true if this is mapped. | |
bool | isPersist (void) const |
Return true if this is a global variable. | |
bool | isAddrTied (void) const |
Return true if this is address ties. | |
bool | isInput (void) const |
Return true if this is an input variable. | |
bool | isImplied (void) const |
Return true if this is an implied variable. | |
bool | isSpacebase (void) const |
Return true if this is a spacebase. | |
bool | isConstant (void) const |
Return true if this is a constant. | |
bool | isUnaffected (void) const |
Return true if this is an unaffected register. | |
bool | isExtraOut (void) const |
Return true if this is an extra output. | |
bool | isProtoPartial (void) const |
Return true if this is a piece concatenated into a larger whole. | |
void | setMark (void) const |
Set the mark on this variable. | |
void | clearMark (void) const |
Clear the mark on this variable. | |
bool | isMark (void) const |
Return true if this is marked. | |
bool | isUnmerged (void) const |
Return true if this has merge problems. | |
bool | hasCover (void) const |
Determine if this HighVariable has an associated cover. More... | |
bool | isUnattached (void) const |
Return true if this has no member Varnode. | |
bool | isTypeLock (void) const |
Return true if this is typelocked. | |
bool | isNameLock (void) const |
Return true if this is namelocked. | |
void | encode (Encoder &encoder) const |
Encode this variable to stream as a <high> element. More... | |
Static Public Member Functions | |
static bool | compareName (Varnode *vn1, Varnode *vn2) |
Determine which given Varnode is most nameable. More... | |
static bool | compareJustLoc (const Varnode *a, const Varnode *b) |
Compare based on storage location. More... | |
static int4 | markExpression (Varnode *vn, vector< HighVariable *> &highList) |
Mark and collect variables in expression. More... | |
Private Member Functions | |
int4 | instanceIndex (const Varnode *vn) const |
Find the index of a specific Varnode member. More... | |
void | updateFlags (void) const |
(Re)derive boolean properties of this from the member Varnodes More... | |
void | updateInternalCover (void) const |
(Re)derive the internal cover of this from the member Varnodes More... | |
void | updateCover (void) const |
(Re)derive the external cover of this, as a union of internal covers More... | |
void | updateType (void) const |
(Re)derive the data-type for this from the member Varnodes More... | |
void | updateSymbol (void) const |
(Re)derive the Symbol and offset for this from member Varnodes | |
void | setCopyIn1 (void) const |
Mark the existence of one COPY into this. | |
void | setCopyIn2 (void) const |
Mark the existence of two COPYs into this. | |
void | clearCopyIns (void) const |
Clear marks indicating COPYs into this. | |
bool | hasCopyIn1 (void) const |
Is there at least one COPY into this. | |
bool | hasCopyIn2 (void) const |
Is there at least two COPYs into this. | |
void | remove (Varnode *vn) |
Remove a member Varnode from this. More... | |
void | mergeInternal (HighVariable *tv2, bool isspeculative) |
Merge another HighVariable into this. More... | |
void | merge (HighVariable *tv2, HighIntersectTest *testCache, bool isspeculative) |
Merge with another HighVariable taking into account groups. More... | |
void | setSymbol (Varnode *vn) const |
Update Symbol information for this from the given member Varnode. More... | |
void | setSymbolReference (Symbol *sym, int4 off) |
Attach a reference to a Symbol to this. More... | |
void | transferPiece (HighVariable *tv2) |
Transfer ownership of another's VariablePiece to this. | |
void | flagsDirty (void) const |
Mark the boolean properties as dirty. | |
void | coverDirty (void) const |
Mark the cover as dirty. More... | |
void | typeDirty (void) const |
Mark the data-type as dirty. | |
void | symbolDirty (void) const |
Mark the symbol as dirty. | |
void | setUnmerged (void) const |
Mark this as having merge problems. | |
bool | isCoverDirty (void) const |
Is the cover returned by getCover() up-to-date. More... | |
Private Attributes | |
vector< Varnode * > | inst |
The member Varnode objects making up this HighVariable. | |
int4 | numMergeClasses |
Number of different speculative merge classes in this. | |
uint4 | highflags |
Dirtiness flags. | |
uint4 | flags |
Boolean properties inherited from Varnode members. | |
Datatype * | type |
The data-type for this. | |
Varnode * | nameRepresentative |
The storage location used to generate a Symbol name. | |
Cover | internalCover |
The ranges of code addresses covered by this HighVariable. | |
VariablePiece * | piece |
Additional info about intersections with other pieces (if non-null) | |
Symbol * | symbol |
The Symbol this HighVariable is tied to. | |
int4 | symboloffset |
-1=perfect symbol match >=0, offset | |
Friends | |
class | Varnode |
class | Merge |
class | VariablePiece |
class | HighIntersectTest |
A high-level variable modeled as a list of low-level variables, each written once.
In the Static Single Assignment (SSA) representation of a function's data-flow, the Varnode object represents a variable node. This is a low-level variable: it is written to at most once, and there is 1 or more reads. A high-level variable, in the source language may be written to multiple times. We model this idea as a list of Varnode objects, where a different Varnode holds the value of the variable for different parts of the code. The range(s) of code for which a single Varnode holds the high-level variable's value is the cover or range of that Varnode and is modeled by the class Cover. Within a high-level variable, HighVariable, the covers of member Varnode objects should not intersect, as that represents the variable holding two or more different values at the same place in the code. The HighVariable inherits a cover which is the union of the covers of its Varnodes.
anonymous enum |
Dirtiness flags for a HighVariable.
The HighVariable inherits its Cover, its data-type, and other boolean properties from its Varnodes. The object holds these explicitly, but the values may become stale as the data-flow transforms. So we keep track of when these inherited values are dirty
Enumerator | |
---|---|
flagsdirty | Boolean properties for the HighVariable are dirty. |
namerepdirty | The name representative for the HighVariable is dirty. |
typedirty | The data-type for the HighVariable is dirty. |
coverdirty | The cover for the HighVariable is dirty. |
symboldirty | The symbol attachment is dirty. |
copy_in1 | There exists at least 1 COPY into this HighVariable from other HighVariables. |
copy_in2 | There exists at least 2 COPYs into this HighVariable from other HighVariables. |
type_finalized | Set if a final data-type is locked in and dirtying is disabled. |
unmerged | Set if part of a multi-entry Symbol but did not get merged with other SymbolEntrys. |
intersectdirty | Set if intersections with other HighVariables needs to be recomputed. |
extendcoverdirty | Set if extended cover needs to be recomputed. |
ghidra::HighVariable::HighVariable | ( | Varnode * | vn | ) |
Construct a HighVariable with a single member Varnode.
The new instance starts off with no associate Symbol and all properties marked as dirty.
vn | is the single Varnode member |
References ghidra::Varnode::getSymbolEntry(), and ghidra::Varnode::setHigh().
Compare based on storage location.
Compare two Varnode objects based just on their storage address
References ghidra::Varnode::getAddr().
Determine which given Varnode is most nameable.
Given two Varnode (members), sort them based on naming properties:
References ghidra::Varnode::getDef(), ghidra::Varnode::getSpace(), ghidra::PcodeOp::getTime(), ghidra::AddrSpace::getType(), ghidra::IPTR_INTERNAL, ghidra::Varnode::isAddrTied(), ghidra::Varnode::isInput(), ghidra::Varnode::isNameLock(), ghidra::Varnode::isPersist(), ghidra::Varnode::isProtoPartial(), ghidra::Varnode::isUnaffected(), and ghidra::Varnode::isWritten().
|
inlineprivate |
Mark the cover as dirty.
The internal cover is marked as dirty. If this is a piece of a VariableGroup, it and all the other HighVariables it intersects with are marked as having a dirty extended cover.
Referenced by ghidra::Merge::inflate().
void ghidra::HighVariable::encode | ( | Encoder & | encoder | ) | const |
Encode this variable to stream as a <high> element.
encoder | is the stream encoder |
References ghidra::Encoder::closeElement(), ghidra::Symbol::function_parameter, ghidra::Varnode::getCreateIndex(), ghidra::Encoder::openElement(), ghidra::Encoder::writeBool(), ghidra::Encoder::writeSignedInteger(), ghidra::Encoder::writeString(), and ghidra::Encoder::writeUnsignedInteger().
Referenced by ghidra::Funcdata::encodeHigh().
void ghidra::HighVariable::establishGroupSymbolOffset | ( | void | ) |
Transfer symbol offset of this to the VariableGroup.
If this is part of a larger group and has had its symboloffset set, it can be used to calculate the symboloffset of other HighVariables in the same group, by writing it to the common VariableGroup object.
References ghidra::VariableGroup::setSymbolOffset().
Referenced by ghidra::Funcdata::linkProtoPartial().
void ghidra::HighVariable::finalizeDatatype | ( | Datatype * | tp | ) |
Set a final datatype for this variable.
The data-type its dirtying mechanism is disabled. The data-type will not change, unless this method is called again.
tp | is the data-type to set |
References ghidra::Datatype::getMetatype(), ghidra::TYPE_PARTIALUNION, ghidra::TYPE_STRUCT, and ghidra::TYPE_UNION.
Referenced by ghidra::Funcdata::syncVarnodesWithSymbol().
|
inline |
Get cover data for this variable.
The returns the internal cover unless this is part of a VariableGroup, in which case the extended cover is returned.
Referenced by ghidra::HighIntersectTest::blockIntersection(), ghidra::Merge::compareHighByBlock(), and ghidra::HighIntersectTest::intersection().
Varnode * ghidra::HighVariable::getInputVarnode | ( | void | ) | const |
Find (the) input member Varnode.
This should only be called if isInput() returns true. If there is no input member, this will throw an exception.
Referenced by ghidra::Merge::mergeTestAdjacent().
Varnode * ghidra::HighVariable::getNameRepresentative | ( | void | ) | const |
Get a member Varnode that dictates the naming of this HighVariable.
Members are scored based the properties that are most dominating in choosing a name.
Referenced by ghidra::Funcdata::linkProtoPartial(), ghidra::ActionNameVars::linkSymbols(), and ghidra::PrintLanguage::pushSymbolDetail().
SymbolEntry * ghidra::HighVariable::getSymbolEntry | ( | void | ) | const |
Assuming there is a Symbol attached to this, run through the Varnode members until we find one with a SymbolEntry corresponding to the Symbol and return it.
References ghidra::SymbolEntry::getSymbol().
Referenced by ghidra::PrintC::pushSymbol().
|
inline |
Get the SymbolEntry mapping to this or null.
Get the Symbol offset associated with this
Referenced by ghidra::ActionNameVars::linkSymbols(), ghidra::Merge::mergeTestRequired(), ghidra::PrintC::opPtrsub(), ghidra::PrintC::opSubpiece(), and ghidra::PrintLanguage::pushSymbolDetail().
Varnode * ghidra::HighVariable::getTiedVarnode | ( | void | ) | const |
Find the first address tied member Varnode.
This should only be called if isAddrTied() returns true. If there is no address tied member, this will throw an exception.
Referenced by ghidra::MapState::gatherHighs(), and ghidra::Merge::mergeTestRequired().
Varnode * ghidra::HighVariable::getTypeRepresentative | ( | void | ) | const |
Get a member Varnode with the strongest data-type.
Find the member Varnode with the most specialized data-type, handling bool specially. Boolean data-types are specialized in the data-type lattice, but not all byte values are boolean values. Within the Varnode/PcodeOp tree, the bool data-type can only propagate to a Varnode if it is verified to only take the boolean values 0 and 1. Since the data-type representative represents the type of all instances, if any instance is not boolean, then the HighVariable cannot be boolean, even though bool is more specialized. This method uses Datatype::typeOrderBool() to implement the special handling.
References ghidra::Varnode::getType(), ghidra::Varnode::isTypeLock(), and ghidra::Datatype::typeOrderBool().
void ghidra::HighVariable::groupWith | ( | int4 | off, |
HighVariable * | hi2 | ||
) |
Put this and another HighVariable in the same intersection group.
If one of the HighVariables is already in a group, the other HighVariable is added to this group.
off | is the relative byte offset of this with the other HighVariable |
hi2 | is the other HighVariable |
References ghidra::VariableGroup::combineGroups(), ghidra::VariablePiece::getGroup(), ghidra::VariablePiece::getOffset(), highflags, ghidra::VariablePiece::markIntersectionDirty(), and piece.
Referenced by ghidra::Merge::groupPartialRoot(), and ghidra::Merge::mergeAddrTied().
|
inline |
Determine if this HighVariable has an associated cover.
Constant and annotation variables do not have a cover
References ghidra::Varnode::annotation, ghidra::Varnode::constant, and ghidra::Varnode::insert.
Referenced by ghidra::Merge::mergeTest().
bool ghidra::HighVariable::hasName | ( | void | ) | const |
Check if this HighVariable can be named.
All Varnode objects are assigned a HighVariable, including those that don't get names like indirect variables, constants, and annotations. Determine if this, as inherited from its member Varnodes, can have a name.
References ghidra::Varnode::hasCover(), ghidra::Varnode::isIllegalInput(), ghidra::Varnode::isImplied(), ghidra::Varnode::isIndirectOnly(), and ghidra::Varnode::isSpacebase().
Referenced by ghidra::ActionNameVars::linkSymbols().
|
private |
Find the index of a specific Varnode member.
Find the index, for use with getInstance(), that will retrieve the given Varnode member
vn | is the given Varnode member |
|
inlineprivate |
Is the cover returned by getCover() up-to-date.
The cover could either by the internal one or the extended one if this is part of a Variable Group.
Referenced by ghidra::HighIntersectTest::updateHigh().
|
static |
Mark and collect variables in expression.
Given a Varnode at the root of an expression, we collect all the explicit HighVariables involved in the expression. This should only be run after explicit and implicit properties have been computed on Varnodes. The expression is traced back from the root until explicit Varnodes are encountered; then their HighVariable is marked and added to the list. The routine returns a value based on PcodeOps encountered in the expression:
vn | is the given root Varnode of the expression |
highList | will hold the collected HighVariables |
References ghidra::PcodeOp::code(), ghidra::Varnode::copyShadow(), ghidra::CPUI_LOAD, ghidra::Varnode::getCover(), ghidra::Varnode::getDef(), ghidra::Varnode::getHigh(), ghidra::Cover::intersect(), ghidra::Varnode::isAnnotation(), ghidra::PcodeOp::isCall(), ghidra::Varnode::isExplicit(), isMark(), ghidra::Varnode::isWritten(), ghidra::Cover::merge(), and setMark().
Referenced by ghidra::Funcdata::moveRespectingCover().
|
private |
Merge with another HighVariable taking into account groups.
The HighVariables are merged internally as with mergeInternal. If this is part of a VariableGroup, extended covers of the group may be affected. If both HighVariables are part of separate groups, the groups are combined into one, which may induce additional HighVariable pairs within the group to be merged. In all cases, the other HighVariable is deleted.
tv2 | is the other HighVariable to merge into this |
testCache | if non-null is a cache of intersection tests that must be updated to reflect the merge |
isspeculative | is true to keep the new members in separate merge classes |
References mergeInternal(), ghidra::HighIntersectTest::moveIntersectTests(), and piece.
Referenced by ghidra::Merge::buildDominantCopy(), and ghidra::Merge::merge().
|
private |
Merge another HighVariable into this.
The lists of members are merged and the other HighVariable is deleted.
tv2 | is the other HighVariable to merge into this |
isspeculative | is true to keep the new members in separate merge classes |
References ghidra::Varnode::getMergeGroup(), highflags, inst, internalCover, numMergeClasses, ghidra::Varnode::setHigh(), symbol, and symboloffset.
Referenced by merge().
|
inline |
Print details of the cover for this (for debug purposes)
s | is the output stream |
References coverdirty, and ghidra::Cover::print().
Referenced by ghidra::IfcPrintCover::execute(), and ghidra::IfcVarnodehighCover::execute().
void ghidra::HighVariable::printInfo | ( | ostream & | s | ) | const |
Print information about this HighVariable to stream.
This is generally used for debug purposes.
s | is the output stream |
References ghidra::Varnode::getMergeGroup(), and ghidra::Varnode::printInfo().
Referenced by ghidra::IfcPrintHigh::execute(), and ghidra::IfcPrintVarnode::execute().
|
private |
Remove a member Varnode from this.
Search for the given Varnode and cut it out of the list, marking all properties as dirty.
vn | is the given Varnode member to remove |
References ghidra::Varnode::getSymbolEntry().
Referenced by ghidra::Merge::buildDominantCopy(), and ghidra::Varnode::~Varnode().
|
private |
Update Symbol information for this from the given member Varnode.
The given Varnode must be a member and must have a non-null SymbolEntry.
References ghidra::Symbol::equate, ghidra::SymbolEntry::getAddr(), ghidra::Varnode::getAddr(), ghidra::Symbol::getName(), ghidra::SymbolEntry::getOffset(), ghidra::Varnode::getSize(), ghidra::SymbolEntry::getSymbol(), ghidra::Varnode::getSymbolEntry(), ghidra::SymbolEntry::isDynamic(), ghidra::SymbolEntry::isPiece(), ghidra::Varnode::isProtoPartial(), ghidra::Address::overlapJoin(), and ghidra::TYPE_PARTIALUNION.
|
private |
Attach a reference to a Symbol to this.
Link information to this from a Symbol that is not attached to a member Varnode. This only works for a HighVariable with a constant member Varnode. This used when there is a constant address reference to the Symbol and the Varnode holds the reference, not the actual value of the Symbol.
|
private |
(Re)derive the external cover of this, as a union of internal covers
This is only called by the Merge class which knows when to call it properly.
Referenced by ghidra::Merge::merge(), and ghidra::HighIntersectTest::updateHigh().
|
private |
(Re)derive boolean properties of this from the member Varnodes
Only update if flags are marked as dirty. Generally if any member Varnode possesses the property, this HighVariable should inherit it. The Varnode::typelock field is not set here, but in updateType().
References ghidra::Varnode::directwrite, ghidra::Varnode::mark, and ghidra::Varnode::typelock.
|
private |
(Re)derive the internal cover of this from the member Varnodes
Only update if the cover is marked as dirty. Merge the covers of all Varnode instances.
Referenced by ghidra::VariablePiece::updateCover().
|
private |
(Re)derive the data-type for this from the member Varnodes
Only update if the data-type is marked as dirty. Get the most locked, most specific data-type from member Varnode objects.
References ghidra::Datatype::getMetatype(), ghidra::Varnode::getType(), ghidra::Varnode::isTypeLock(), ghidra::TYPE_PARTIALUNION, ghidra::TYPE_STRUCT, ghidra::TYPE_UNION, and ghidra::Varnode::typelock.