mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
Renaming adjustments
This commit is contained in:
parent
6c6d5f2f1b
commit
ced3760c09
13 changed files with 163 additions and 50 deletions
|
@ -2457,6 +2457,14 @@ void ActionNameVars::linkSpacebaseSymbol(Varnode *vn,Funcdata &data,vector<Varno
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Link formal Symbols to their HighVariable representative in the given Function
|
||||||
|
///
|
||||||
|
/// Run through all HighVariables for the given function and set up the explicit mapping with
|
||||||
|
/// existing Symbol objects. If there is no matching Symbol for a given HighVariable, a new
|
||||||
|
/// Symbol is created. Any Symbol that does not have a name is added to a list for further
|
||||||
|
/// name resolution.
|
||||||
|
/// \param data is the given function
|
||||||
|
/// \param namerec is the container for collecting Symbols with a name
|
||||||
void ActionNameVars::linkSymbols(Funcdata &data,vector<Varnode *> &namerec)
|
void ActionNameVars::linkSymbols(Funcdata &data,vector<Varnode *> &namerec)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -3870,8 +3878,6 @@ int4 ActionDynamicSymbols::apply(Funcdata &data)
|
||||||
while(iter != enditer) {
|
while(iter != enditer) {
|
||||||
SymbolEntry *entry = &(*iter);
|
SymbolEntry *entry = &(*iter);
|
||||||
++iter;
|
++iter;
|
||||||
// FIXME: Setting the symbol here (for the first time) gives the type no time to propagate properly
|
|
||||||
// Currently the casts aren't set properly
|
|
||||||
if (data.attemptDynamicMappingLate(entry, dhash))
|
if (data.attemptDynamicMappingLate(entry, dhash))
|
||||||
count += 1;
|
count += 1;
|
||||||
}
|
}
|
||||||
|
@ -4857,6 +4863,7 @@ void universal_action(Architecture *conf)
|
||||||
act->addAction( new ActionMergeMultiEntry("merge") );
|
act->addAction( new ActionMergeMultiEntry("merge") );
|
||||||
act->addAction( new ActionMergeCopy("merge") );
|
act->addAction( new ActionMergeCopy("merge") );
|
||||||
act->addAction( new ActionDominantCopy("merge") );
|
act->addAction( new ActionDominantCopy("merge") );
|
||||||
|
act->addAction( new ActionDynamicSymbols("dynamic") );
|
||||||
act->addAction( new ActionMarkIndirectOnly("merge") ); // Must come after required merges but before speculative
|
act->addAction( new ActionMarkIndirectOnly("merge") ); // Must come after required merges but before speculative
|
||||||
act->addAction( new ActionMergeAdjacent("merge") );
|
act->addAction( new ActionMergeAdjacent("merge") );
|
||||||
act->addAction( new ActionMergeType("merge") );
|
act->addAction( new ActionMergeType("merge") );
|
||||||
|
|
|
@ -362,7 +362,6 @@ public:
|
||||||
bool ancestorOpUse(int4 maxlevel,const Varnode *invn,const PcodeOp *op,ParamTrial &trial) const;
|
bool ancestorOpUse(int4 maxlevel,const Varnode *invn,const PcodeOp *op,ParamTrial &trial) const;
|
||||||
bool syncVarnodesWithSymbols(const ScopeLocal *lm,bool typesyes);
|
bool syncVarnodesWithSymbols(const ScopeLocal *lm,bool typesyes);
|
||||||
void transferVarnodeProperties(Varnode *vn,Varnode *newVn,int4 lsbOffset);
|
void transferVarnodeProperties(Varnode *vn,Varnode *newVn,int4 lsbOffset);
|
||||||
void splitVarnode(Varnode *vn,int4 lowsize,Varnode *&vnlo,Varnode *& vnhi);
|
|
||||||
bool fillinReadOnly(Varnode *vn); ///< Replace the given Varnode with its (constant) value in the load image
|
bool fillinReadOnly(Varnode *vn); ///< Replace the given Varnode with its (constant) value in the load image
|
||||||
bool replaceVolatile(Varnode *vn); ///< Replace accesses of the given Varnode with \e volatile operations
|
bool replaceVolatile(Varnode *vn); ///< Replace accesses of the given Varnode with \e volatile operations
|
||||||
void markIndirectOnly(void); ///< Mark \e illegal \e input Varnodes used only in INDIRECTs
|
void markIndirectOnly(void); ///< Mark \e illegal \e input Varnodes used only in INDIRECTs
|
||||||
|
|
|
@ -525,6 +525,7 @@ Varnode *Funcdata::opStackLoad(AddrSpace *spc,uintb off,uint4 sz,PcodeOp *op,Var
|
||||||
/// CPUI_INT_MULT PcodeOp. If finalization is requested and a new PcodeOp is needed, the output
|
/// CPUI_INT_MULT PcodeOp. If finalization is requested and a new PcodeOp is needed, the output
|
||||||
/// Varnode is marked as \e implicit and has its data-type set
|
/// Varnode is marked as \e implicit and has its data-type set
|
||||||
/// \param op is the given PTRADD
|
/// \param op is the given PTRADD
|
||||||
|
/// \param finalize is \b true if finalization is needed for any new PcodeOp
|
||||||
void Funcdata::opUndoPtradd(PcodeOp *op,bool finalize)
|
void Funcdata::opUndoPtradd(PcodeOp *op,bool finalize)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -282,7 +282,7 @@ void Merge::mergeOpcode(OpCode opc)
|
||||||
vn2 = op->getIn(j);
|
vn2 = op->getIn(j);
|
||||||
if (!mergeTestBasic(vn2)) continue;
|
if (!mergeTestBasic(vn2)) continue;
|
||||||
if (mergeTestRequired(vn1->getHigh(),vn2->getHigh()))
|
if (mergeTestRequired(vn1->getHigh(),vn2->getHigh()))
|
||||||
merge(vn1->getHigh(),vn2->getHigh(),true); // Treat as speculative
|
merge(vn1->getHigh(),vn2->getHigh(),false); // This is a required merge
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,7 +97,7 @@ public:
|
||||||
InjectPayload(const string &nm,int4 tp) { name=nm; type=tp; paramshift=0; dynamic = false; incidentalCopy = false; } ///< Construct for use with restoreXml
|
InjectPayload(const string &nm,int4 tp) { name=nm; type=tp; paramshift=0; dynamic = false; incidentalCopy = false; } ///< Construct for use with restoreXml
|
||||||
int4 getParamShift(void) const { return paramshift; } ///< Get the number of parameters shifted
|
int4 getParamShift(void) const { return paramshift; } ///< Get the number of parameters shifted
|
||||||
bool isDynamic(void) const { return dynamic; } ///< Return \b true if p-code in the injection is generated dynamically
|
bool isDynamic(void) const { return dynamic; } ///< Return \b true if p-code in the injection is generated dynamically
|
||||||
bool isIncidentalCopy(void) const { return incidentalCopy; }
|
bool isIncidentalCopy(void) const { return incidentalCopy; } ///< Return \b true if any injected COPY is considered \e incidental
|
||||||
int4 sizeInput(void) const { return inputlist.size(); } ///< Return the number of input parameters
|
int4 sizeInput(void) const { return inputlist.size(); } ///< Return the number of input parameters
|
||||||
int4 sizeOutput(void) const { return output.size(); } ///< Return the number of output parameters
|
int4 sizeOutput(void) const { return output.size(); } ///< Return the number of output parameters
|
||||||
InjectParameter &getInput(int4 i) { return inputlist[i]; } ///< Get the i-th input parameter
|
InjectParameter &getInput(int4 i) { return inputlist[i]; } ///< Get the i-th input parameter
|
||||||
|
|
|
@ -1884,9 +1884,9 @@ int4 RuleDoubleShift::applyOp(PcodeOp *op,Funcdata &data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \class RuleDoubleArithShift
|
/// \class RuleDoubleArithShift
|
||||||
/// \brief Simply two sequential INT_SRIGHT: `(x s>> #c) s>> #d => x s>> saturate(#c + #d)`
|
/// \brief Simplify two sequential INT_SRIGHT: `(x s>> #c) s>> #d => x s>> saturate(#c + #d)`
|
||||||
///
|
///
|
||||||
/// Optimized division optimization in particular can produce a sequence of signed right shifts.
|
/// Division optimization in particular can produce a sequence of signed right shifts.
|
||||||
/// The shift amounts add up to the point where the sign bit has saturated the entire result.
|
/// The shift amounts add up to the point where the sign bit has saturated the entire result.
|
||||||
void RuleDoubleArithShift::getOpList(vector<uint4> &oplist) const
|
void RuleDoubleArithShift::getOpList(vector<uint4> &oplist) const
|
||||||
|
|
||||||
|
|
|
@ -97,12 +97,12 @@ public:
|
||||||
LanedIterator(const LanedRegister *lanedR) { size = 0; mask = lanedR->sizeBitMask; normalize(); } ///< Constructor
|
LanedIterator(const LanedRegister *lanedR) { size = 0; mask = lanedR->sizeBitMask; normalize(); } ///< Constructor
|
||||||
LanedIterator(void) { size = -1; mask = 0; } ///< Constructor for ending iterator
|
LanedIterator(void) { size = -1; mask = 0; } ///< Constructor for ending iterator
|
||||||
LanedIterator &operator++(void) { size += 1; normalize(); return *this; } ///< Preincrement operator
|
LanedIterator &operator++(void) { size += 1; normalize(); return *this; } ///< Preincrement operator
|
||||||
int4 operator*(void) const { return size; } /// Dereference operator
|
int4 operator*(void) const { return size; } ///< Dereference operator
|
||||||
LanedIterator &operator=(const LanedIterator &op2) { size = op2.size; mask = op2.mask; return *this; } ///< Assignment
|
LanedIterator &operator=(const LanedIterator &op2) { size = op2.size; mask = op2.mask; return *this; } ///< Assignment
|
||||||
bool operator==(const LanedIterator &op2) const { return (size == op2.size); } ///< Equal operator
|
bool operator==(const LanedIterator &op2) const { return (size == op2.size); } ///< Equal operator
|
||||||
bool operator!=(const LanedIterator &op2) const { return (size != op2.size); } ///< Not-equal operator
|
bool operator!=(const LanedIterator &op2) const { return (size != op2.size); } ///< Not-equal operator
|
||||||
};
|
};
|
||||||
typedef LanedIterator const_iterator;
|
typedef LanedIterator const_iterator; ///< Iterator over possible lane sizes for this register
|
||||||
private:
|
private:
|
||||||
int4 wholeSize; ///< Size of the whole register
|
int4 wholeSize; ///< Size of the whole register
|
||||||
uint4 sizeBitMask; ///< A 1-bit for every permissible lane size
|
uint4 sizeBitMask; ///< A 1-bit for every permissible lane size
|
||||||
|
|
|
@ -23,10 +23,11 @@ HighVariable::HighVariable(Varnode *vn)
|
||||||
|
|
||||||
{
|
{
|
||||||
numMergeClasses = 1;
|
numMergeClasses = 1;
|
||||||
highflags = flagsdirty | typedirty | coverdirty;
|
highflags = flagsdirty | namerepdirty | typedirty | coverdirty;
|
||||||
flags = 0;
|
flags = 0;
|
||||||
type = (Datatype *)0;
|
type = (Datatype *)0;
|
||||||
symbol = (Symbol *)0;
|
symbol = (Symbol *)0;
|
||||||
|
nameRepresentative = (Varnode *)0;
|
||||||
symboloffset = -1;
|
symboloffset = -1;
|
||||||
inst.push_back(vn);
|
inst.push_back(vn);
|
||||||
vn->setHigh( this, numMergeClasses-1 );
|
vn->setHigh( this, numMergeClasses-1 );
|
||||||
|
@ -66,7 +67,7 @@ void HighVariable::setSymbol(Varnode *vn) const
|
||||||
/// is a constant address reference to the Symbol and the Varnode holds the reference, not
|
/// is a constant address reference to the Symbol and the Varnode holds the reference, not
|
||||||
/// the actual value of the Symbol.
|
/// the actual value of the Symbol.
|
||||||
/// \param sym is the given Symbol to attach
|
/// \param sym is the given Symbol to attach
|
||||||
/// \off is the byte offset into the Symbol of the reference
|
/// \param off is the byte offset into the Symbol of the reference
|
||||||
void HighVariable::setSymbolReference(Symbol *sym,int4 off)
|
void HighVariable::setSymbolReference(Symbol *sym,int4 off)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -229,18 +230,22 @@ bool HighVariable::compareName(Varnode *vn1,Varnode *vn2)
|
||||||
Varnode *HighVariable::getNameRepresentative(void) const
|
Varnode *HighVariable::getNameRepresentative(void) const
|
||||||
|
|
||||||
{
|
{
|
||||||
|
if ((highflags & namerepdirty)==0)
|
||||||
|
return nameRepresentative; // Name representative is up to date
|
||||||
|
highflags &= ~namerepdirty;
|
||||||
|
|
||||||
vector<Varnode *>::const_iterator iter;
|
vector<Varnode *>::const_iterator iter;
|
||||||
Varnode *rep,*vn;
|
Varnode *vn;
|
||||||
|
|
||||||
iter = inst.begin();
|
iter = inst.begin();
|
||||||
rep = *iter;
|
nameRepresentative = *iter;
|
||||||
++iter;
|
++iter;
|
||||||
for(;iter!=inst.end();++iter) {
|
for(;iter!=inst.end();++iter) {
|
||||||
vn = *iter;
|
vn = *iter;
|
||||||
if (compareName(rep,vn))
|
if (compareName(nameRepresentative,vn))
|
||||||
rep = vn;
|
nameRepresentative = vn;
|
||||||
}
|
}
|
||||||
return rep;
|
return nameRepresentative;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Search for the given Varnode and cut it out of the list, marking all properties as \e dirty.
|
/// Search for the given Varnode and cut it out of the list, marking all properties as \e dirty.
|
||||||
|
@ -254,7 +259,7 @@ void HighVariable::remove(Varnode *vn)
|
||||||
for(;iter!=inst.end();++iter) {
|
for(;iter!=inst.end();++iter) {
|
||||||
if (*iter == vn) {
|
if (*iter == vn) {
|
||||||
inst.erase(iter);
|
inst.erase(iter);
|
||||||
highflags |= (flagsdirty|coverdirty|typedirty);
|
highflags |= (flagsdirty|namerepdirty|coverdirty|typedirty);
|
||||||
if (vn->getSymbolEntry() != (SymbolEntry *)0)
|
if (vn->getSymbolEntry() != (SymbolEntry *)0)
|
||||||
highflags |= symboldirty;
|
highflags |= symboldirty;
|
||||||
return;
|
return;
|
||||||
|
@ -296,7 +301,7 @@ void HighVariable::merge(HighVariable *tv2,bool isspeculative)
|
||||||
|
|
||||||
if (tv2 == this) return;
|
if (tv2 == this) return;
|
||||||
|
|
||||||
highflags |= (flagsdirty|typedirty);
|
highflags |= (flagsdirty|namerepdirty|typedirty);
|
||||||
if (tv2->symbol != (Symbol *)0) { // Check if we inherit a Symbol
|
if (tv2->symbol != (Symbol *)0) { // Check if we inherit a Symbol
|
||||||
if ((tv2->highflags & symboldirty)==0) {
|
if ((tv2->highflags & symboldirty)==0) {
|
||||||
symbol = tv2->symbol; // Overwrite our Symbol (assume it is the same)
|
symbol = tv2->symbol; // Overwrite our Symbol (assume it is the same)
|
||||||
|
|
|
@ -44,13 +44,14 @@ public:
|
||||||
/// So we keep track of when these inherited values are \e dirty
|
/// So we keep track of when these inherited values are \e dirty
|
||||||
enum {
|
enum {
|
||||||
flagsdirty = 1, ///< Boolean properties for the HighVariable are dirty
|
flagsdirty = 1, ///< Boolean properties for the HighVariable are dirty
|
||||||
typedirty = 2, ///< The data-type for the HighVariable is dirty
|
namerepdirty = 2, ///< The name representative for the HighVariable is dirty
|
||||||
coverdirty = 4, ///< The cover for the HighVariable is dirty
|
typedirty = 4, ///< The data-type for the HighVariable is dirty
|
||||||
symboldirty = 8, ///< The symbol attachment is dirty
|
coverdirty = 8, ///< The cover for the HighVariable is dirty
|
||||||
copy_in1 = 8, ///< There exists at least 1 COPY into \b this HighVariable from other HighVariables
|
symboldirty = 0x10, ///< The symbol attachment is dirty
|
||||||
copy_in2 = 16, ///< There exists at least 2 COPYs into \b this HighVariable from other HighVariables
|
copy_in1 = 0x20, ///< There exists at least 1 COPY into \b this HighVariable from other HighVariables
|
||||||
type_finalized = 32, ///< Set if a final data-type is locked in and dirtying is disabled
|
copy_in2 = 0x40, ///< There exists at least 2 COPYs into \b this HighVariable from other HighVariables
|
||||||
unmerged = 64 ///< Set if part of a multi-entry Symbol but did not get merged with other SymbolEntrys
|
type_finalized = 0x80, ///< Set if a final data-type is locked in and dirtying is disabled
|
||||||
|
unmerged = 0x100 ///< Set if part of a multi-entry Symbol but did not get merged with other SymbolEntrys
|
||||||
};
|
};
|
||||||
private:
|
private:
|
||||||
friend class Varnode;
|
friend class Varnode;
|
||||||
|
@ -59,7 +60,8 @@ private:
|
||||||
int4 numMergeClasses; ///< Number of different speculative merge classes in \b this
|
int4 numMergeClasses; ///< Number of different speculative merge classes in \b this
|
||||||
mutable uint4 highflags; ///< Dirtiness flags
|
mutable uint4 highflags; ///< Dirtiness flags
|
||||||
mutable uint4 flags; ///< Boolean properties inherited from Varnode members
|
mutable uint4 flags; ///< Boolean properties inherited from Varnode members
|
||||||
mutable Datatype *type; ///< The data-type for this
|
mutable Datatype *type; ///< The data-type for \b this
|
||||||
|
mutable Varnode *nameRepresentative; ///< The storage location used to generate a Symbol name
|
||||||
mutable Cover wholecover; ///< The ranges of code addresses covered by this HighVariable
|
mutable Cover wholecover; ///< The ranges of code addresses covered by this HighVariable
|
||||||
mutable Symbol *symbol; ///< The Symbol \b this HighVariable is tied to
|
mutable Symbol *symbol; ///< The Symbol \b this HighVariable is tied to
|
||||||
mutable int4 symboloffset; ///< -1=perfect symbol match >=0, offset
|
mutable int4 symboloffset; ///< -1=perfect symbol match >=0, offset
|
||||||
|
@ -77,9 +79,9 @@ private:
|
||||||
void merge(HighVariable *tv2,bool isspeculative); ///< Merge another HighVariable into \b this
|
void merge(HighVariable *tv2,bool isspeculative); ///< Merge another HighVariable into \b this
|
||||||
void setSymbol(Varnode *vn) const; ///< Update Symbol information for \b this from the given member Varnode
|
void setSymbol(Varnode *vn) const; ///< Update Symbol information for \b this from the given member Varnode
|
||||||
void setSymbolReference(Symbol *sym,int4 off); ///< Attach a reference to a Symbol to \b this
|
void setSymbolReference(Symbol *sym,int4 off); ///< Attach a reference to a Symbol to \b this
|
||||||
void flagsDirty(void) const { highflags |= HighVariable::flagsdirty; } ///< Mark the boolean properties as \e dirty
|
void flagsDirty(void) const { highflags |= flagsdirty | namerepdirty; } ///< Mark the boolean properties as \e dirty
|
||||||
void coverDirty(void) const { highflags |= HighVariable::coverdirty; } ///< Mark the cover as \e dirty
|
void coverDirty(void) const { highflags |= coverdirty; } ///< Mark the cover as \e dirty
|
||||||
void typeDirty(void) const { highflags |= HighVariable::typedirty; } ///< Mark the data-type as \e dirty
|
void typeDirty(void) const { highflags |= typedirty; } ///< Mark the data-type as \e dirty
|
||||||
void setUnmerged(void) const { highflags |= unmerged; } ///< Mark \b this as having merge problems
|
void setUnmerged(void) const { highflags |= unmerged; } ///< Mark \b this as having merge problems
|
||||||
public:
|
public:
|
||||||
HighVariable(Varnode *vn); ///< Construct a HighVariable with a single member Varnode
|
HighVariable(Varnode *vn); ///< Construct a HighVariable with a single member Varnode
|
||||||
|
|
|
@ -21,6 +21,11 @@
|
||||||
|
|
||||||
#include "database.hh"
|
#include "database.hh"
|
||||||
|
|
||||||
|
/// \brief A symbol name recommendation with its associated storage location
|
||||||
|
///
|
||||||
|
/// The name is associated with a static Address and use point in the code. Symbols
|
||||||
|
/// present at the end of function decompilation without a name can acquire \b this name
|
||||||
|
/// if their storage matches.
|
||||||
class NameRecommend {
|
class NameRecommend {
|
||||||
Address addr; ///< The starting address of the storage location
|
Address addr; ///< The starting address of the storage location
|
||||||
Address useaddr; ///< The code address at the point of use
|
Address useaddr; ///< The code address at the point of use
|
||||||
|
@ -37,7 +42,7 @@ public:
|
||||||
uint8 getSymbolId(void) const { return symbolId; } ///< Get the original Symbol id
|
uint8 getSymbolId(void) const { return symbolId; } ///< Get the original Symbol id
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief A name recommendation for a particular dynamic location
|
/// \brief A name recommendation for a particular dynamic storage location
|
||||||
///
|
///
|
||||||
/// A recommendation for a symbol name whose storage is dynamic. The storage
|
/// A recommendation for a symbol name whose storage is dynamic. The storage
|
||||||
/// is identified using the DynamicHash mechanism and may or may not exist.
|
/// is identified using the DynamicHash mechanism and may or may not exist.
|
||||||
|
|
|
@ -23,15 +23,19 @@ import org.junit.Test;
|
||||||
|
|
||||||
import docking.widgets.fieldpanel.field.Field;
|
import docking.widgets.fieldpanel.field.Field;
|
||||||
import docking.widgets.fieldpanel.support.FieldLocation;
|
import docking.widgets.fieldpanel.support.FieldLocation;
|
||||||
|
import ghidra.app.cmd.function.CreateFunctionCmd;
|
||||||
|
import ghidra.app.cmd.function.DeleteFunctionCmd;
|
||||||
import ghidra.app.decompiler.ClangToken;
|
import ghidra.app.decompiler.ClangToken;
|
||||||
import ghidra.app.decompiler.ClangVariableToken;
|
import ghidra.app.decompiler.ClangVariableToken;
|
||||||
import ghidra.app.decompiler.component.ClangTextField;
|
import ghidra.app.decompiler.component.ClangTextField;
|
||||||
import ghidra.app.decompiler.component.DecompilerPanel;
|
import ghidra.app.decompiler.component.DecompilerPanel;
|
||||||
import ghidra.app.plugin.core.decompile.actions.RenameGlobalVariableTask;
|
import ghidra.app.plugin.core.decompile.actions.*;
|
||||||
import ghidra.app.plugin.core.decompile.actions.RenameVariableTask;
|
import ghidra.framework.options.Options;
|
||||||
import ghidra.program.database.symbol.CodeSymbol;
|
import ghidra.program.database.symbol.CodeSymbol;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.listing.Data;
|
import ghidra.program.model.data.DataType;
|
||||||
|
import ghidra.program.model.data.Undefined;
|
||||||
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.pcode.*;
|
import ghidra.program.model.pcode.*;
|
||||||
import ghidra.program.model.symbol.SourceType;
|
import ghidra.program.model.symbol.SourceType;
|
||||||
import ghidra.program.model.symbol.Symbol;
|
import ghidra.program.model.symbol.Symbol;
|
||||||
|
@ -85,6 +89,29 @@ public class HighSymbolTest extends AbstractDecompilerTest {
|
||||||
waitForDecompiler();
|
waitForDecompiler();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void deleteFunction(String address) {
|
||||||
|
modifyProgram(p -> {
|
||||||
|
Address addr = p.getAddressFactory().getAddress(address);
|
||||||
|
DeleteFunctionCmd deleteCmd = new DeleteFunctionCmd(addr);
|
||||||
|
deleteCmd.applyTo(p);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createFunction(String address) {
|
||||||
|
modifyProgram(p -> {
|
||||||
|
Address addr = p.getAddressFactory().getAddress(address);
|
||||||
|
CreateFunctionCmd createCmd = new CreateFunctionCmd(addr);
|
||||||
|
createCmd.applyTo(p);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void turnOffAnalysis() {
|
||||||
|
modifyProgram(p -> {
|
||||||
|
Options options = p.getOptions(Program.ANALYSIS_PROPERTIES);
|
||||||
|
options.setBoolean("Decompiler Parameter ID", false);
|
||||||
|
options.setBoolean("Stack", false);
|
||||||
|
});
|
||||||
|
}
|
||||||
private void renameVariable(HighSymbol highSymbol, ClangToken tokenAtCursor, String newName) {
|
private void renameVariable(HighSymbol highSymbol, ClangToken tokenAtCursor, String newName) {
|
||||||
RenameVariableTask rename =
|
RenameVariableTask rename =
|
||||||
new RenameVariableTask(provider.getTool(), highSymbol.getProgram(),
|
new RenameVariableTask(provider.getTool(), highSymbol.getProgram(),
|
||||||
|
@ -96,6 +123,16 @@ public class HighSymbolTest extends AbstractDecompilerTest {
|
||||||
waitForDecompiler();
|
waitForDecompiler();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void isolateVariable(HighSymbol highSymbol, ClangToken tokenAtCursor, String newName) {
|
||||||
|
IsolateVariableTask isolate = new IsolateVariableTask(provider.getTool(), program,
|
||||||
|
provider.getDecompilerPanel(), tokenAtCursor, highSymbol, SourceType.USER_DEFINED);
|
||||||
|
assertTrue(isolate.isValid(newName));
|
||||||
|
modifyProgram(p -> {
|
||||||
|
isolate.commit();
|
||||||
|
});
|
||||||
|
waitForDecompiler();
|
||||||
|
}
|
||||||
|
|
||||||
private void renameExisting(HighSymbol highSymbol, ClangToken tokenAtCursor, String newName) {
|
private void renameExisting(HighSymbol highSymbol, ClangToken tokenAtCursor, String newName) {
|
||||||
SymbolEntry oldEntry = highSymbol.getFirstWholeMap();
|
SymbolEntry oldEntry = highSymbol.getFirstWholeMap();
|
||||||
long oldId = highSymbol.getId();
|
long oldId = highSymbol.getId();
|
||||||
|
@ -303,4 +340,64 @@ public class HighSymbolTest extends AbstractDecompilerTest {
|
||||||
entry = highSymbol.getFirstWholeMap();
|
entry = highSymbol.getFirstWholeMap();
|
||||||
assertEquals(usepoint, entry.getPCAdress()); // Make sure the same usepoint comes back
|
assertEquals(usepoint, entry.getPCAdress()); // Make sure the same usepoint comes back
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHighSymbol_freeParameter() {
|
||||||
|
deleteFunction("10015a6");
|
||||||
|
turnOffAnalysis();
|
||||||
|
createFunction("10015a6");
|
||||||
|
decompile("10015a6");
|
||||||
|
ClangTextField line = getLineContaining("param_4 +");
|
||||||
|
FieldLocation loc = loc(line.getLineNumber(), 23);
|
||||||
|
ClangToken token = line.getToken(loc);
|
||||||
|
assertTrue(token instanceof ClangVariableToken);
|
||||||
|
HighSymbol highSymbol = token.getHighVariable().getSymbol();
|
||||||
|
renameVariable(highSymbol, token, "newParam");
|
||||||
|
line = getLineContaining("newParam +");
|
||||||
|
token = line.getToken(loc);
|
||||||
|
assertTrue(token instanceof ClangVariableToken);
|
||||||
|
HighVariable variable = token.getHighVariable();
|
||||||
|
assertTrue(variable instanceof HighParam);
|
||||||
|
assertEquals(((HighParam) variable).getSlot(), 3);
|
||||||
|
highSymbol = variable.getSymbol();
|
||||||
|
assertTrue(highSymbol.isNameLocked());
|
||||||
|
assertFalse(highSymbol.isTypeLocked());
|
||||||
|
Function function = highSymbol.getHighFunction().getFunction();
|
||||||
|
Parameter[] parameters = function.getParameters();
|
||||||
|
assertEquals(parameters.length, 4);
|
||||||
|
for (int i = 0; i < 4; ++i) {
|
||||||
|
DataType dt = parameters[i].getDataType();
|
||||||
|
assertTrue(Undefined.isUndefined(dt));
|
||||||
|
assertEquals(dt.getLength(), 4);
|
||||||
|
}
|
||||||
|
assertEquals(parameters[3].getName(), "newParam");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHighSymbol_isolate() {
|
||||||
|
decompile("1002a22");
|
||||||
|
ClangTextField line = getLineContaining(" >> 1");
|
||||||
|
FieldLocation loc = loc(line.getLineNumber(), 2);
|
||||||
|
ClangToken token = line.getToken(loc);
|
||||||
|
assertTrue(token instanceof ClangVariableToken);
|
||||||
|
HighVariable variable = token.getHighVariable();
|
||||||
|
Varnode[] instances = variable.getInstances();
|
||||||
|
short maxMerge = 0;
|
||||||
|
for (Varnode vn : instances) {
|
||||||
|
if (vn.getMergeGroup() > maxMerge) {
|
||||||
|
maxMerge = vn.getMergeGroup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertEquals(maxMerge, 1); // Make sure there are 2 merge groups
|
||||||
|
String name = token.getText();
|
||||||
|
isolateVariable(variable.getSymbol(), token, name);
|
||||||
|
line = getLineContaining(" >> 1");
|
||||||
|
token = line.getToken(loc);
|
||||||
|
variable = token.getHighVariable();
|
||||||
|
assertEquals(variable.getInstances().length, 1);
|
||||||
|
HighSymbol highSymbol = variable.getSymbol();
|
||||||
|
assertEquals(highSymbol.getName(), name);
|
||||||
|
assertTrue(highSymbol.isNameLocked());
|
||||||
|
assertTrue(highSymbol.isTypeLocked());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,24 +89,20 @@ public class DynamicEntry extends SymbolEntry {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build the dynamic storage object for a new DynamicEntry, given the underlying temporary
|
* Build a new DynamicEntry, given the underlying temporary
|
||||||
* Varnode and its function model. The hash is created from local information in the
|
* Varnode attached to a symbol. The hash is created from local information in the
|
||||||
* syntax tree near the Varnode.
|
* syntax tree near the Varnode.
|
||||||
* @param vn is the underlying Varnode
|
* @param vn is the underlying Varnode
|
||||||
* @param high is the function model
|
* @return the new DynamicEntry
|
||||||
* @return the dynamic storage object
|
|
||||||
*/
|
*/
|
||||||
public static VariableStorage buildDynamicStorage(Varnode vn, HighFunction high) {
|
public static DynamicEntry build(Varnode vn) {
|
||||||
DynamicHash dynamicHash = new DynamicHash(vn, high);
|
HighVariable highVariable = vn.getHigh();
|
||||||
Program program = high.getFunction().getProgram();
|
HighSymbol highSymbol = highVariable.getSymbol();
|
||||||
long ourHash = dynamicHash.getHash();
|
HighFunction highFunction = highSymbol.getHighFunction();
|
||||||
try {
|
DynamicHash dynamicHash = new DynamicHash(vn, highFunction);
|
||||||
return new VariableStorage(program, AddressSpace.HASH_SPACE.getAddress(ourHash),
|
DynamicEntry entry =
|
||||||
vn.getSize());
|
new DynamicEntry(highSymbol, dynamicHash.getAddress(), dynamicHash.getHash());
|
||||||
}
|
return entry;
|
||||||
catch (InvalidInputException e) {
|
|
||||||
throw new AssertException("Unexpected exception", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -510,8 +510,9 @@ public class HighFunctionDBUtil {
|
||||||
HighVariable tmpHigh = highSymbol.getHighVariable();
|
HighVariable tmpHigh = highSymbol.getHighVariable();
|
||||||
if (!storage.isHashStorage() && tmpHigh != null &&
|
if (!storage.isHashStorage() && tmpHigh != null &&
|
||||||
tmpHigh.requiresDynamicStorage()) {
|
tmpHigh.requiresDynamicStorage()) {
|
||||||
storage =
|
DynamicEntry entry = DynamicEntry.build(tmpHigh.getRepresentative());
|
||||||
DynamicEntry.buildDynamicStorage(tmpHigh.getRepresentative(), highFunction);
|
storage = entry.getStorage();
|
||||||
|
pcAddr = entry.getPCAdress(); // The address may change from original Varnode
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Variable var = clearConflictingLocalVariables(function, storage, pcAddr);
|
Variable var = clearConflictingLocalVariables(function, storage, pcAddr);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue