mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-06-02 13:57:40 +08:00
GP-5922 Integer formatting for switch cases
This commit is contained in:
@@ -140,7 +140,7 @@ public class SwitchOverride extends GhidraScript {
|
||||
}
|
||||
|
||||
// Allocate an override jumptable
|
||||
JumpTable jumpTab = new JumpTable(branchind, destlist, true);
|
||||
JumpTable jumpTab = new JumpTable(branchind, destlist, true, 0);
|
||||
jumpTab.writeOverride(function);
|
||||
|
||||
// fixup the body now that there are jump references
|
||||
|
||||
@@ -790,6 +790,7 @@ public:
|
||||
uint4 getGotoType(int4 i) const { return caseblocks[i].gototype; } ///< Get the edge type for the i-th \e case block
|
||||
bool isExit(int4 i) const { return caseblocks[i].isexit; } ///< Does the i-th \e case block exit the switch?
|
||||
const Datatype *getSwitchType(void) const; ///< Get the data-type of the switch variable
|
||||
uint4 getDisplayFormat(void) const { return jump->getDisplayFormat(); } ///< Get any integer display format for cases
|
||||
virtual block_type getType(void) const { return t_switch; }
|
||||
virtual void markUnstructured(void);
|
||||
virtual void scopeBreak(int4 curexit,int4 curloopexit);
|
||||
|
||||
@@ -1059,7 +1059,7 @@ void FlowInfo::xrefInlinedBranch(PcodeOp *op)
|
||||
setupCallindSpecs(op,(FuncCallSpecs *)0);
|
||||
else if (op->code() == CPUI_BRANCHIND) {
|
||||
JumpTable *jt = data.linkJumpTable(op);
|
||||
if (jt == (JumpTable *)0)
|
||||
if (jt == (JumpTable *)0 || jt->numEntries() == 0)
|
||||
tablelist.push_back(op); // Didn't recover a jumptable
|
||||
}
|
||||
}
|
||||
|
||||
@@ -615,7 +615,7 @@ void Funcdata::decodeJumpTable(Decoder &decoder)
|
||||
{
|
||||
uint4 elemId = decoder.openElement(ELEM_JUMPTABLELIST);
|
||||
while(decoder.peekElement() != 0) {
|
||||
JumpTable *jt = new JumpTable(glb);
|
||||
JumpTable *jt = new JumpTable();
|
||||
jt->decode(decoder);
|
||||
jumpvec.push_back(jt);
|
||||
}
|
||||
|
||||
@@ -470,7 +470,7 @@ JumpTable *Funcdata::installJumpTable(const Address &addr)
|
||||
if (jt->getOpAddress() == addr)
|
||||
throw LowlevelError("Trying to install over existing jumptable");
|
||||
}
|
||||
JumpTable *newjt = new JumpTable(glb,addr);
|
||||
JumpTable *newjt = new JumpTable(addr);
|
||||
jumpvec.push_back(newjt);
|
||||
return newjt;
|
||||
}
|
||||
@@ -645,10 +645,10 @@ JumpTable *Funcdata::recoverJumpTable(Funcdata &partial,PcodeOp *op,FlowInfo *fl
|
||||
jt = linkJumpTable(op); // Search for pre-existing jumptable
|
||||
if (jt != (JumpTable *)0) {
|
||||
if (!jt->isOverride()) {
|
||||
if (!jt->isPartial())
|
||||
if (!jt->isPartial() && jt->numEntries() != 0)
|
||||
return jt; // Previously calculated jumptable (NOT an override and NOT incomplete)
|
||||
}
|
||||
mode = stageJumpTable(partial,jt,op,flow); // Recover based on override information
|
||||
mode = stageJumpTable(partial,jt,op,flow); // Recover empty jumptable or based on override information
|
||||
if (mode != JumpTable::success)
|
||||
return (JumpTable *)0;
|
||||
jt->setIndirectOp(op); // Relink table back to original op
|
||||
@@ -660,7 +660,7 @@ JumpTable *Funcdata::recoverJumpTable(Funcdata &partial,PcodeOp *op,FlowInfo *fl
|
||||
mode = earlyJumpTableFail(op);
|
||||
if (mode != JumpTable::success)
|
||||
return (JumpTable *)0;
|
||||
JumpTable trialjt(glb);
|
||||
JumpTable trialjt;
|
||||
mode = stageJumpTable(partial,&trialjt,op,flow);
|
||||
if (mode != JumpTable::success)
|
||||
return (JumpTable *)0;
|
||||
|
||||
@@ -2271,9 +2271,10 @@ void JumpTable::clearSavedModel(void)
|
||||
void JumpTable::recoverModel(Funcdata *fd)
|
||||
|
||||
{
|
||||
uint4 maxTableSize = fd->getArch()->max_jumptable_size;
|
||||
if (jmodel != (JumpModel *)0) {
|
||||
if (jmodel->isOverride()) { // If preexisting model is override
|
||||
jmodel->recoverModel(fd,indirect,0,glb->max_jumptable_size);
|
||||
jmodel->recoverModel(fd,indirect,0,maxTableSize);
|
||||
return;
|
||||
}
|
||||
delete jmodel; // Otherwise this is an old attempt we should remove
|
||||
@@ -2284,18 +2285,18 @@ void JumpTable::recoverModel(Funcdata *fd)
|
||||
if (op->code() == CPUI_CALLOTHER) {
|
||||
JumpAssisted *jassisted = new JumpAssisted(this);
|
||||
jmodel = jassisted;
|
||||
if (jmodel->recoverModel(fd,indirect,addresstable.size(),glb->max_jumptable_size))
|
||||
if (jmodel->recoverModel(fd,indirect,addresstable.size(),maxTableSize))
|
||||
return;
|
||||
}
|
||||
}
|
||||
JumpBasic *jbasic = new JumpBasic(this);
|
||||
jmodel = jbasic;
|
||||
if (jmodel->recoverModel(fd,indirect,addresstable.size(),glb->max_jumptable_size))
|
||||
if (jmodel->recoverModel(fd,indirect,addresstable.size(),maxTableSize))
|
||||
return;
|
||||
jmodel = new JumpBasic2(this);
|
||||
((JumpBasic2 *)jmodel)->initializeStart(jbasic->getPathMeld());
|
||||
delete jbasic;
|
||||
if (jmodel->recoverModel(fd,indirect,addresstable.size(),glb->max_jumptable_size))
|
||||
if (jmodel->recoverModel(fd,indirect,addresstable.size(),maxTableSize))
|
||||
return;
|
||||
delete jmodel;
|
||||
jmodel = (JumpModel *)0;
|
||||
@@ -2392,12 +2393,10 @@ bool JumpTable::isReachable(PcodeOp *op)
|
||||
return true;
|
||||
}
|
||||
|
||||
/// \param g is the Architecture the table exists within
|
||||
/// \param ad is the Address of the BRANCHIND \b this models
|
||||
JumpTable::JumpTable(Architecture *g,Address ad)
|
||||
JumpTable::JumpTable(Address ad)
|
||||
: opaddress(ad)
|
||||
{
|
||||
glb = g;
|
||||
jmodel = (JumpModel *)0;
|
||||
origmodel = (JumpModel *)0;
|
||||
indirect = (PcodeOp *)0;
|
||||
@@ -2407,6 +2406,7 @@ JumpTable::JumpTable(Architecture *g,Address ad)
|
||||
maxaddsub = 1;
|
||||
maxleftright = 1;
|
||||
maxext = 1;
|
||||
displayFormat = 0;
|
||||
partialTable = false;
|
||||
collectloads = false;
|
||||
defaultIsFolded = false;
|
||||
@@ -2418,7 +2418,6 @@ JumpTable::JumpTable(Architecture *g,Address ad)
|
||||
JumpTable::JumpTable(const JumpTable *op2)
|
||||
|
||||
{
|
||||
glb = op2->glb;
|
||||
jmodel = (JumpModel *)0;
|
||||
origmodel = (JumpModel *)0;
|
||||
indirect = (PcodeOp *)0;
|
||||
@@ -2428,6 +2427,7 @@ JumpTable::JumpTable(const JumpTable *op2)
|
||||
maxaddsub = op2->maxaddsub;
|
||||
maxleftright = op2->maxleftright;
|
||||
maxext = op2->maxext;
|
||||
displayFormat = op2->displayFormat;
|
||||
partialTable = op2->partialTable;
|
||||
collectloads = op2->collectloads;
|
||||
defaultIsFolded = false;
|
||||
@@ -2743,7 +2743,7 @@ void JumpTable::recoverLabels(Funcdata *fd)
|
||||
}
|
||||
else {
|
||||
jmodel = new JumpModelTrivial(this);
|
||||
jmodel->recoverModel(fd,indirect,addresstable.size(),glb->max_jumptable_size);
|
||||
jmodel->recoverModel(fd,indirect,addresstable.size(),fd->getArch()->max_jumptable_size);
|
||||
jmodel->buildAddresses(fd,indirect,addresstable,(vector<LoadTable> *)0,(vector<int4> *)0);
|
||||
trivialSwitchOver();
|
||||
jmodel->buildLabels(fd,addresstable,label,origmodel);
|
||||
@@ -2785,6 +2785,8 @@ void JumpTable::encode(Encoder &encoder) const
|
||||
throw LowlevelError("Trying to save unrecovered jumptable");
|
||||
|
||||
encoder.openElement(ELEM_JUMPTABLE);
|
||||
if (displayFormat != 0)
|
||||
encoder.writeUnsignedInteger(ATTRIB_FORMAT, displayFormat);
|
||||
opaddress.encode(encoder);
|
||||
for(int4 i=0;i<addresstable.size();++i) {
|
||||
encoder.openElement(ELEM_DEST);
|
||||
@@ -2814,6 +2816,8 @@ void JumpTable::decode(Decoder &decoder)
|
||||
|
||||
{
|
||||
uint4 elemId = decoder.openElement(ELEM_JUMPTABLE);
|
||||
if (decoder.getNextAttributeId() == ATTRIB_FORMAT)
|
||||
displayFormat = decoder.readUnsignedInteger();
|
||||
opaddress = Address::decode( decoder );
|
||||
bool missedlabel = false;
|
||||
for(;;) {
|
||||
|
||||
@@ -557,7 +557,6 @@ private:
|
||||
bool operator<(const IndexPair &op2) const; ///< Compare by position then by index
|
||||
static bool compareByPosition(const IndexPair &op1,const IndexPair &op2); ///< Compare just by position
|
||||
};
|
||||
Architecture *glb; ///< Architecture under which this jump-table operates
|
||||
JumpModel *jmodel; ///< Current model of how the jump table is implemented in code
|
||||
JumpModel *origmodel; ///< Initial jump table model, which may be incomplete
|
||||
vector<Address> addresstable; ///< Raw addresses in the jump-table
|
||||
@@ -572,6 +571,7 @@ private:
|
||||
uint4 maxaddsub; ///< Maximum ADDs or SUBs to normalize
|
||||
uint4 maxleftright; ///< Maximum shifts to normalize
|
||||
uint4 maxext; ///< Maximum extensions to normalize
|
||||
uint4 displayFormat; ///< Display format for integer \e case values
|
||||
bool partialTable; ///< Set to \b true if \b this table is incomplete and needs additional recovery steps
|
||||
bool collectloads; ///< Set to \b true if information about in-memory model data is/should be collected
|
||||
bool defaultIsFolded; ///< The \e default block is the target of a folded CBRANCH (and cannot have a label)
|
||||
@@ -584,7 +584,7 @@ private:
|
||||
int4 block2Position(const FlowBlock *bl) const; ///< Convert a basic-block to an out-edge index from the switch.
|
||||
static bool isReachable(PcodeOp *op); ///< Check if the given PcodeOp still seems reachable in its function
|
||||
public:
|
||||
JumpTable(Architecture *g,Address ad=Address()); ///< Constructor
|
||||
JumpTable(Address ad=Address()); ///< Constructor
|
||||
JumpTable(const JumpTable *op2); ///< Copy constructor
|
||||
~JumpTable(void); ///< Destructor
|
||||
bool isRecovered(void) const { return !addresstable.empty(); } ///< Return \b true if a model has been recovered
|
||||
@@ -600,6 +600,8 @@ public:
|
||||
void setIndirectOp(PcodeOp *ind) { opaddress = ind->getAddr(); indirect = ind; } ///< Set the BRANCHIND PcodeOp
|
||||
void setNormMax(uint4 maddsub,uint4 mleftright,uint4 mext) {
|
||||
maxaddsub = maddsub; maxleftright = mleftright; maxext = mext; } ///< Set the switch variable normalization model restrictions
|
||||
uint4 getDisplayFormat(void) const { return displayFormat; } ///< Get the display format for integer cases
|
||||
void setDisplayFormat(uint4 format) { displayFormat = format; } ///< Set the display format to use for integer case values
|
||||
void setOverride(const vector<Address> &addrtable,const Address &naddr,uintb h,uintb sv);
|
||||
int4 numIndicesByBlock(const FlowBlock *bl) const;
|
||||
int4 getIndexByBlock(const FlowBlock *bl,int4 i) const;
|
||||
|
||||
@@ -325,7 +325,7 @@ void PrintC::pushTypeEnd(const Datatype *ct)
|
||||
const TypeArray *ctarray = (const TypeArray *)ct;
|
||||
ct = ctarray->getBase();
|
||||
push_integer(ctarray->numElements(),4,false,syntax,
|
||||
(const Varnode *)0,(const PcodeOp *)0);
|
||||
(const Varnode *)0,(const PcodeOp *)0,0);
|
||||
}
|
||||
else if (ct->getMetatype()==TYPE_CODE) {
|
||||
const TypeCode *ctcode = (const TypeCode *)ct;
|
||||
@@ -1051,7 +1051,7 @@ void PrintC::opPtrsub(const PcodeOp *op)
|
||||
pushAtom(Atom(fieldname,fieldtoken,EmitMarkup::no_color,ct,fieldid,op));
|
||||
}
|
||||
if (arrayvalue)
|
||||
push_integer(0,4,false,syntax,(Varnode *)0,op);
|
||||
push_integer(0,4,false,syntax,(Varnode *)0,op,0);
|
||||
}
|
||||
}
|
||||
else if (ct->getMetatype() == TYPE_SPACEBASE) {
|
||||
@@ -1093,7 +1093,7 @@ void PrintC::opPtrsub(const PcodeOp *op)
|
||||
}
|
||||
}
|
||||
if (arrayvalue)
|
||||
push_integer(0,4,false,syntax,(Varnode *)0,op);
|
||||
push_integer(0,4,false,syntax,(Varnode *)0,op,0);
|
||||
}
|
||||
else if (ct->getMetatype() == TYPE_ARRAY) {
|
||||
if (in1const != 0) {
|
||||
@@ -1124,7 +1124,7 @@ void PrintC::opPtrsub(const PcodeOp *op)
|
||||
if (ptrel != (TypePointerRel *)0)
|
||||
pushTypePointerRel(op);
|
||||
pushVn(in0,op,m | print_load_value); // Absorb one dereference into in0's defining op
|
||||
push_integer(0,4,false,syntax,(Varnode *)0,op);
|
||||
push_integer(0,4,false,syntax,(Varnode *)0,op,0);
|
||||
}
|
||||
else { // EMIT (* )[0]
|
||||
pushOp(&subscript,op);
|
||||
@@ -1132,7 +1132,7 @@ void PrintC::opPtrsub(const PcodeOp *op)
|
||||
if (ptrel != (TypePointerRel *)0)
|
||||
pushTypePointerRel(op);
|
||||
pushVn(in0,op,m);
|
||||
push_integer(0,4,false,syntax,(Varnode *)0,op);
|
||||
push_integer(0,4,false,syntax,(Varnode *)0,op,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1285,13 +1285,13 @@ void PrintC::opExtractOp(const PcodeOp *op)
|
||||
/// \param tag is the type of token to associate with the integer
|
||||
/// \param vn is the Varnode holding the value
|
||||
/// \param op is the PcodeOp using the value
|
||||
/// \param displayFormat is the default display format (which can be 0 and may be overridden)
|
||||
void PrintC::push_integer(uintb val,int4 sz,bool sign,tagtype tag,
|
||||
const Varnode *vn,const PcodeOp *op)
|
||||
const Varnode *vn,const PcodeOp *op,uint4 displayFormat)
|
||||
{
|
||||
bool print_negsign;
|
||||
bool force_unsigned_token;
|
||||
bool force_sized_token;
|
||||
uint4 displayFormat = 0;
|
||||
|
||||
force_unsigned_token = false;
|
||||
force_sized_token = false;
|
||||
@@ -1307,8 +1307,6 @@ void PrintC::push_integer(uintb val,int4 sz,bool sign,tagtype tag,
|
||||
}
|
||||
force_unsigned_token = vn->isUnsignedPrint();
|
||||
force_sized_token = vn->isLongPrint();
|
||||
if (displayFormat == 0) // The symbol's formatting overrides any formatting on the data-type
|
||||
displayFormat = high->getType()->getDisplayFormat();
|
||||
}
|
||||
if (sign && displayFormat != Symbol::force_char) { // Print the constant as signed
|
||||
uintb mask = calc_mask(sz);
|
||||
@@ -1324,7 +1322,7 @@ void PrintC::push_integer(uintb val,int4 sz,bool sign,tagtype tag,
|
||||
|
||||
// Figure whether to print as hex or decimal
|
||||
if (displayFormat != 0) {
|
||||
// Format is forced by the Symbol
|
||||
// Format is forced by the Symbol or data-type
|
||||
}
|
||||
else if ((mods & force_hex)!=0) {
|
||||
displayFormat = Symbol::force_hex;
|
||||
@@ -1623,7 +1621,7 @@ void PrintC::pushCharConstant(uintb val,const Datatype *ct,tagtype tag,const Var
|
||||
}
|
||||
if (displayFormat != 0 && displayFormat != Symbol::force_char) {
|
||||
if (!castStrategy->caresAboutCharRepresentation(vn, op)) {
|
||||
push_integer(val, ct->getSize(), isSigned, tag, vn, op);
|
||||
push_integer(val, ct->getSize(), isSigned, tag, vn, op, displayFormat);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1633,7 +1631,7 @@ void PrintC::pushCharConstant(uintb val,const Datatype *ct,tagtype tag,const Var
|
||||
// unicode code-point. Its either part of a multi-byte UTF-8 encoding or an unknown
|
||||
// code-page value. In either case, we print as an integer or an escape sequence.
|
||||
if (displayFormat != Symbol::force_hex && displayFormat != Symbol::force_char) {
|
||||
push_integer(val, 1, isSigned, tag, vn, op);
|
||||
push_integer(val, 1, isSigned, tag, vn, op, displayFormat);
|
||||
return;
|
||||
}
|
||||
displayFormat = Symbol::force_hex; // Fallthru but force a hex representation
|
||||
@@ -1679,10 +1677,10 @@ void PrintC::pushEnumConstant(uintb val,const TypeEnum *ct,tagtype tag,
|
||||
for(int4 i=0;i<rep.matchname.size();++i)
|
||||
pushAtom(Atom(rep.matchname[i],tag,EmitMarkup::const_color,op,vn,val));
|
||||
if (rep.shiftAmount != 0)
|
||||
push_integer(rep.shiftAmount,4,false,tag,vn,op);
|
||||
push_integer(rep.shiftAmount,4,false,tag,vn,op,0);
|
||||
}
|
||||
else {
|
||||
push_integer(val,ct->getSize(),false,tag,vn,op);
|
||||
push_integer(val,ct->getSize(),false,tag,vn,op,ct->getDisplayFormat());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1742,8 +1740,7 @@ bool PrintC::pushPtrCodeConstant(uintb val,const TypePointer *ct,
|
||||
}
|
||||
|
||||
void PrintC::pushConstant(uintb val,const Datatype *ct,tagtype tag,
|
||||
const Varnode *vn,
|
||||
const PcodeOp *op)
|
||||
const Varnode *vn,const PcodeOp *op,uint4 displayFormat)
|
||||
{
|
||||
Datatype *subtype;
|
||||
switch(ct->getMetatype()) {
|
||||
@@ -1753,7 +1750,7 @@ void PrintC::pushConstant(uintb val,const Datatype *ct,tagtype tag,
|
||||
else if (ct->isEnumType())
|
||||
pushEnumConstant(val,(TypeEnum *)ct,tag,vn,op);
|
||||
else
|
||||
push_integer(val,ct->getSize(),false,tag,vn,op);
|
||||
push_integer(val,ct->getSize(),false,tag,vn,op,displayFormat);
|
||||
return;
|
||||
case TYPE_INT:
|
||||
if (ct->isCharPrint())
|
||||
@@ -1761,10 +1758,10 @@ void PrintC::pushConstant(uintb val,const Datatype *ct,tagtype tag,
|
||||
else if (ct->isEnumType())
|
||||
pushEnumConstant(val,(TypeEnum *)ct,tag,vn,op);
|
||||
else
|
||||
push_integer(val,ct->getSize(),true,tag,vn,op);
|
||||
push_integer(val,ct->getSize(),true,tag,vn,op,displayFormat);
|
||||
return;
|
||||
case TYPE_UNKNOWN:
|
||||
push_integer(val,ct->getSize(),false,tag,vn,op);
|
||||
push_integer(val,ct->getSize(),false,tag,vn,op,displayFormat);
|
||||
return;
|
||||
case TYPE_BOOL:
|
||||
pushBoolConstant(val,(const TypeBase *)ct,tag,vn,op);
|
||||
@@ -1811,7 +1808,7 @@ void PrintC::pushConstant(uintb val,const Datatype *ct,tagtype tag,
|
||||
pushMod();
|
||||
if (!isSet(force_dec))
|
||||
setMod(force_hex);
|
||||
push_integer(val,ct->getSize(),false,tag,vn,op);
|
||||
push_integer(val,ct->getSize(),false,tag,vn,op,displayFormat);
|
||||
popMod();
|
||||
}
|
||||
|
||||
@@ -1845,14 +1842,14 @@ bool PrintC::pushEquate(uintb val,int4 sz,const EquateSymbol *sym,const Varnode
|
||||
if (modval == val) {
|
||||
pushOp(&binary_plus,(const PcodeOp *)0);
|
||||
pushSymbol(sym,vn,op);
|
||||
push_integer(1, sz, false, syntax, (const Varnode *)0, (const PcodeOp *)0);
|
||||
push_integer(1, sz, false, syntax, (const Varnode *)0, (const PcodeOp *)0, 0);
|
||||
return true;
|
||||
}
|
||||
modval = (baseval - 1) & mask;
|
||||
if (modval == val) {
|
||||
pushOp(&binary_minus,(const PcodeOp *)0);
|
||||
pushSymbol(sym,vn,op);
|
||||
push_integer(1, sz, false, syntax, (const Varnode *)0, (const PcodeOp *)0);
|
||||
push_integer(1, sz, false, syntax, (const Varnode *)0, (const PcodeOp *)0, 0);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -2053,7 +2050,7 @@ void PrintC::pushPartialSymbol(const Symbol *sym,int4 off,int4 sz,
|
||||
PartialSymbolEntry &entry (stack[i]);
|
||||
if (entry.field == (const TypeField *)0) {
|
||||
if (entry.size <= 0)
|
||||
push_integer(entry.offset, entry.size, (entry.offset < 0), syntax, (Varnode *)0, op);
|
||||
push_integer(entry.offset, entry.size, (entry.offset < 0), syntax, (Varnode *)0, op, 0);
|
||||
else {
|
||||
string field = unnamedField(entry.offset,entry.size);
|
||||
pushAtom(Atom(field,syntax,entry.hilite,op));
|
||||
@@ -2172,7 +2169,7 @@ void PrintC::emitEnumDefinition(const TypeEnum *ct)
|
||||
emit->spaces(1);
|
||||
emit->print(EQUALSIGN,EmitMarkup::no_color);
|
||||
emit->spaces(1);
|
||||
push_integer((*iter).first,ct->getSize(),sign,syntax,(Varnode *)0,(PcodeOp *)0);
|
||||
push_integer((*iter).first,ct->getSize(),sign,syntax,(Varnode *)0,(PcodeOp *)0,0);
|
||||
recurse();
|
||||
emit->print(SEMICOLON);
|
||||
++iter;
|
||||
@@ -3145,12 +3142,15 @@ void PrintC::emitSwitchCase(int4 casenum,const BlockSwitch *switchbl)
|
||||
}
|
||||
else {
|
||||
num = switchbl->getNumLabels(casenum);
|
||||
uint4 displayFormat = switchbl->getDisplayFormat();
|
||||
if (displayFormat == 0)
|
||||
displayFormat = ct->getDisplayFormat();
|
||||
for(i=0;i<num;++i) {
|
||||
val = switchbl->getLabel(casenum,i);
|
||||
emit->tagLine();
|
||||
emit->print(KEYWORD_CASE,EmitMarkup::keyword_color);
|
||||
emit->spaces(1);
|
||||
pushConstant(val,ct,casetoken,(Varnode *)0,op);
|
||||
pushConstant(val,ct,casetoken,(Varnode *)0,op,displayFormat);
|
||||
recurse();
|
||||
emit->print(COLON);
|
||||
}
|
||||
|
||||
@@ -203,7 +203,7 @@ protected:
|
||||
int4 getHiddenThisSlot(const PcodeOp *op,FuncProto *fc); ///< Get position of "this" pointer needing to be hidden
|
||||
void resetDefaultsPrintC(void); ///< Set default values for options specific to PrintC
|
||||
virtual void pushConstant(uintb val,const Datatype *ct,tagtype tag,
|
||||
const Varnode *vn,const PcodeOp *op);
|
||||
const Varnode *vn,const PcodeOp *op,uint4 displayFormat);
|
||||
virtual bool pushEquate(uintb val,int4 sz,const EquateSymbol *sym,
|
||||
const Varnode *vn,const PcodeOp *op);
|
||||
virtual void pushAnnotation(const Varnode *vn,const PcodeOp *op);
|
||||
@@ -216,8 +216,7 @@ protected:
|
||||
const Varnode *vn,const PcodeOp *op);
|
||||
virtual void pushImpliedField(const Varnode *vn,const PcodeOp *op);
|
||||
virtual void push_integer(uintb val,int4 sz,bool sign,tagtype tag,
|
||||
const Varnode *vn,
|
||||
const PcodeOp *op);
|
||||
const Varnode *vn,const PcodeOp *op,uint4 displayFormat);
|
||||
virtual void push_float(uintb val,int4 sz,tagtype tag,const Varnode *vn,
|
||||
const PcodeOp *op);
|
||||
virtual void printUnicode(ostream &s,int4 onechar) const;
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -234,7 +234,7 @@ void PrintJava::opLoad(const PcodeOp *op)
|
||||
pushOp(&subscript,op);
|
||||
pushVn(op->getIn(1),op,m);
|
||||
if (printArrayRef)
|
||||
push_integer(0,4,false,syntax,(Varnode *)0,op);
|
||||
push_integer(0,4,false,syntax,(Varnode *)0,op,0);
|
||||
}
|
||||
|
||||
void PrintJava::opStore(const PcodeOp *op)
|
||||
@@ -245,7 +245,7 @@ void PrintJava::opStore(const PcodeOp *op)
|
||||
if (needZeroArray(op->getIn(1))) {
|
||||
pushOp(&subscript,op);
|
||||
pushVn(op->getIn(1),op,m);
|
||||
push_integer(0,4,false,syntax,(Varnode *)0,op);
|
||||
push_integer(0,4,false,syntax,(Varnode *)0,op,0);
|
||||
pushVn(op->getIn(2),op,mods);
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -223,7 +223,8 @@ void PrintLanguage::pushVnExplicit(const Varnode *vn,const PcodeOp *op)
|
||||
return;
|
||||
}
|
||||
if (vn->isConstant()) {
|
||||
pushConstant(vn->getOffset(),vn->getHighTypeReadFacing(op),vartoken,vn,op);
|
||||
Datatype *ct = vn->getHighTypeReadFacing(op);
|
||||
pushConstant(vn->getOffset(),ct,vartoken,vn,op,ct->getDisplayFormat());
|
||||
return;
|
||||
}
|
||||
pushSymbolDetail(vn,op,true);
|
||||
|
||||
@@ -324,10 +324,11 @@ protected:
|
||||
/// \param val is the value of the constant
|
||||
/// \param ct is the data-type of the constant
|
||||
/// \param tag is the type of token associated with the constant
|
||||
/// \param vn is the Varnode holding the constant (optional)
|
||||
/// \param op is the PcodeOp using the constant (optional)
|
||||
/// \param vn is the Varnode holding the constant (may be null)
|
||||
/// \param op is the PcodeOp using the constant (may be null)
|
||||
/// \param displayFormat is the default display format to use (may be 0)
|
||||
virtual void pushConstant(uintb val,const Datatype *ct,tagtype tag,
|
||||
const Varnode *vn,const PcodeOp *op)=0;
|
||||
const Varnode *vn,const PcodeOp *op,uint4 displayFormat)=0;
|
||||
|
||||
/// \brief Push a constant marked up by and EquateSymbol onto the RPN stack
|
||||
///
|
||||
@@ -335,8 +336,8 @@ protected:
|
||||
/// \param val is the value of the constant
|
||||
/// \param sz is the number of bytes to use for the encoding
|
||||
/// \param sym is the EquateSymbol that marks up the constant
|
||||
/// \param vn is the Varnode holding the constant (optional)
|
||||
/// \param op is the PcodeOp using the constant (optional)
|
||||
/// \param vn is the Varnode holding the constant (may be null)
|
||||
/// \param op is the PcodeOp using the constant (may be null)
|
||||
virtual bool pushEquate(uintb val,int4 sz,const EquateSymbol *sym,const Varnode *vn,const PcodeOp *op)=0;
|
||||
|
||||
/// \brief Push an address which is not in the normal data-flow.
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -36,6 +36,13 @@ public class ClangCaseToken extends ClangToken {
|
||||
value = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the constant value associated with this label
|
||||
*/
|
||||
public long getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVariableRef() {
|
||||
return true;
|
||||
|
||||
+7
-8
@@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -41,11 +41,10 @@ public class ConvertBinaryAction extends ConvertConstantAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMenuDisplay(long value, int size, boolean isSigned, Program program) {
|
||||
Scalar scalar = new Scalar(size * 8, value);
|
||||
public String getMenuDisplay(Scalar scalar, Program program) {
|
||||
long v;
|
||||
String prefix = "0b";
|
||||
if (isSigned) {
|
||||
if (scalar.isSigned()) {
|
||||
v = scalar.getSignedValue();
|
||||
if (v < 0) {
|
||||
v = -v;
|
||||
@@ -74,9 +73,9 @@ public class ConvertBinaryAction extends ConvertConstantAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEquateName(long value, int size, boolean isSigned, Program program) {
|
||||
String valueStr = Long.toBinaryString(value);
|
||||
valueStr = StringUtilities.pad(valueStr, '0', size * 8);
|
||||
public String getEquateName(Scalar scalar, Program program) {
|
||||
String valueStr = Long.toBinaryString(scalar.getValue());
|
||||
valueStr = StringUtilities.pad(valueStr, '0', scalar.bitLength());
|
||||
return valueStr + "b";
|
||||
}
|
||||
}
|
||||
|
||||
+13
-11
@@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -22,6 +22,7 @@ import ghidra.program.model.data.ByteDataType;
|
||||
import ghidra.program.model.data.StringDataInstance;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.pcode.EquateSymbol;
|
||||
import ghidra.program.model.scalar.Scalar;
|
||||
import ghidra.util.BigEndianDataConverter;
|
||||
import ghidra.util.HelpLocation;
|
||||
|
||||
@@ -63,9 +64,9 @@ public class ConvertCharAction extends ConvertConstantAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEquateName(long value, int size, boolean isSigned, Program program) {
|
||||
byte[] bytes = new byte[size];
|
||||
BigEndianDataConverter.INSTANCE.putValue(value, size, bytes, 0);
|
||||
public String getEquateName(Scalar scalar, Program program) {
|
||||
byte[] bytes = new byte[scalar.bitLength() / 8];
|
||||
BigEndianDataConverter.INSTANCE.putValue(scalar.getValue(), bytes.length, bytes, 0);
|
||||
return StringDataInstance.getCharRepresentation(ByteDataType.dataType, bytes, null);
|
||||
}
|
||||
|
||||
@@ -98,13 +99,14 @@ public class ConvertCharAction extends ConvertConstantAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMenuDisplay(long value, int size, boolean isSigned, Program program) {
|
||||
public String getMenuDisplay(Scalar scalar, Program program) {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
if (size > 1) {
|
||||
if (scalar.bitLength() > 8) {
|
||||
buffer.append('L');
|
||||
}
|
||||
if ((size == 1 && value >= 0x7f) || codePointNeedsEscape((int) value)) {
|
||||
switch ((int) value) {
|
||||
if ((scalar.bitLength() == 8 && scalar.getUnsignedValue() >= 0x7f) ||
|
||||
codePointNeedsEscape((int) scalar.getUnsignedValue())) {
|
||||
switch ((int) scalar.getValue()) {
|
||||
case 0:
|
||||
buffer.append("'\\0'");
|
||||
break;
|
||||
@@ -140,12 +142,12 @@ public class ConvertCharAction extends ConvertConstantAction {
|
||||
break;
|
||||
default:
|
||||
// Generic unicode escape
|
||||
generateHexEscape(buffer, (int) value);
|
||||
generateHexEscape(buffer, (int) scalar.getUnsignedValue());
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
buffer.append('\'').append((char) value).append('\'');
|
||||
buffer.append('\'').append((char) scalar.getUnsignedValue()).append('\'');
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
+107
-263
@@ -17,27 +17,21 @@ package ghidra.app.plugin.core.decompile.actions;
|
||||
|
||||
import java.awt.Font;
|
||||
import java.awt.FontMetrics;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.JMenuItem;
|
||||
|
||||
import ghidra.app.decompiler.ClangCaseToken;
|
||||
import ghidra.app.decompiler.ClangToken;
|
||||
import ghidra.app.decompiler.ClangVariableToken;
|
||||
import ghidra.app.plugin.core.decompile.DecompilePlugin;
|
||||
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.block.CodeBlock;
|
||||
import ghidra.program.model.block.SimpleBlockModel;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.Enum;
|
||||
import ghidra.program.model.listing.Instruction;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.pcode.*;
|
||||
import ghidra.program.model.scalar.Scalar;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
|
||||
/**
|
||||
* Abstract pop-up menu convert action for the decompiler. If triggered, it lays down
|
||||
@@ -46,29 +40,45 @@ import ghidra.util.task.TaskMonitor;
|
||||
*/
|
||||
public abstract class ConvertConstantAction extends AbstractDecompilerAction {
|
||||
|
||||
/**
|
||||
* Max instructions to search through, when looking for a scalar match in the listing
|
||||
* that corresponds with the selected constant in the decompiler window.
|
||||
*/
|
||||
private final static int MAX_INSTRUCTION_WINDOW = 20;
|
||||
|
||||
private static final int MAX_SCALAR_SIZE = 8;
|
||||
protected DecompilePlugin plugin;
|
||||
private FontMetrics metrics = null;
|
||||
private int convertType; // The EquateSymbol conversion type performed by the action
|
||||
protected int convertType; // The conversion type performed by the action
|
||||
|
||||
/**
|
||||
* A helper class describing a (matching) scalar operand
|
||||
* Helper class for identifying integer values that are "near" a given value.
|
||||
* "Near" can mean off by 1, negated, or inverted.
|
||||
*/
|
||||
private static class ScalarMatch {
|
||||
Address refAddr; // Address of instruction
|
||||
Scalar scalar;
|
||||
int opIndex;
|
||||
public static class NearMatchValues {
|
||||
private long[] values;
|
||||
private long mask;
|
||||
|
||||
public ScalarMatch(Address addr, Scalar value, int index) {
|
||||
refAddr = addr;
|
||||
scalar = value;
|
||||
opIndex = index;
|
||||
public NearMatchValues(long value, int size) {
|
||||
mask = -1;
|
||||
if (size < 8) {
|
||||
mask = mask >>> (8 - size) * 8;
|
||||
}
|
||||
values = new long[4];
|
||||
values[0] = value & mask;
|
||||
values[1] = (value - 1) & mask;
|
||||
values[2] = (value + 1) & mask;
|
||||
values[3] = (-value) & mask;
|
||||
}
|
||||
|
||||
public NearMatchValues(Scalar scalar) {
|
||||
this(scalar.getValue(), scalar.bitLength() / 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value is the value to match
|
||||
* @return true if the value matches
|
||||
*/
|
||||
public boolean isMatch(long value) {
|
||||
value = value & mask;
|
||||
for (long match : values) {
|
||||
if (match == value)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,238 +116,17 @@ public abstract class ConvertConstantAction extends AbstractDecompilerAction {
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a scalar in the instruction matching one of the given values.
|
||||
* Return an object describing the match or null if there is no match.
|
||||
* @param instr is the instruction
|
||||
* @param values is an array of the given values
|
||||
* @return the Scalar and
|
||||
*/
|
||||
private ScalarMatch findScalarInInstruction(Instruction instr, long values[]) {
|
||||
int numOperands = instr.getNumOperands();
|
||||
ScalarMatch scalarMatch = null;
|
||||
for (int i = 0; i < numOperands; i++) {
|
||||
for (Object obj : instr.getOpObjects(i)) {
|
||||
if (obj instanceof Scalar) {
|
||||
Scalar scalar = (Scalar) obj;
|
||||
for (long value : values) {
|
||||
if (scalar.getUnsignedValue() != value) {
|
||||
continue;
|
||||
}
|
||||
if (scalarMatch != null) {
|
||||
scalarMatch.opIndex = -1; // non-unique scalar operand value - can't identify operand
|
||||
return scalarMatch;
|
||||
}
|
||||
scalarMatch = new ScalarMatch(instr.getAddress(), scalar, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return scalarMatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a scalar (instruction operand) that matches the given constant Varnode.
|
||||
* We walk backward from the starting address inspecting operands until a match is found.
|
||||
* The search is terminated if either a match is found, the beginning of the basic block
|
||||
* is reached, or if 20 instructions are traversed. The scalar can be a "near" match, meaning
|
||||
* off by 1 or the negated value.
|
||||
* @param program is the Program
|
||||
* @param startAddress is the starting address to search backward from
|
||||
* @param constVn is the given constant Varnode
|
||||
* @return a description of the scalar match, or null if there is no match
|
||||
*/
|
||||
private ScalarMatch findScalarMatch(Program program, Address startAddress, Varnode constVn) {
|
||||
long value = constVn.getOffset();
|
||||
long mask = -1;
|
||||
if (constVn.getSize() < 8) {
|
||||
mask = mask >>> (8 - constVn.getSize()) * 8;
|
||||
}
|
||||
long values[] = new long[4];
|
||||
values[0] = value;
|
||||
values[1] = (value - 1) & mask;
|
||||
values[2] = (value + 1) & mask;
|
||||
values[3] = (-value) & mask;
|
||||
int count = 0;
|
||||
ScalarMatch scalarMatch = null;
|
||||
Instruction curInst = program.getListing().getInstructionAt(startAddress);
|
||||
if (curInst == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
SimpleBlockModel model = new SimpleBlockModel(program);
|
||||
CodeBlock basicBlock = null;
|
||||
try {
|
||||
basicBlock = model.getFirstCodeBlockContaining(startAddress, TaskMonitor.DUMMY);
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
// can't happen; dummy monitor
|
||||
}
|
||||
if (basicBlock == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
while (count < MAX_INSTRUCTION_WINDOW) {
|
||||
count += 1;
|
||||
ScalarMatch newMatch = findScalarInInstruction(curInst, values);
|
||||
if (newMatch != null) {
|
||||
if (scalarMatch != null) {
|
||||
return null; // Matches at more than one address
|
||||
}
|
||||
if (newMatch.opIndex < 0) {
|
||||
return null; // Matches at more than one operand
|
||||
}
|
||||
scalarMatch = newMatch;
|
||||
}
|
||||
curInst = curInst.getPrevious();
|
||||
if (curInst == null) {
|
||||
break;
|
||||
}
|
||||
if (!basicBlock.contains(curInst.getAddress())) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return scalarMatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the context, set up the task object that will execute the conversion.
|
||||
* If setupFinal toggle is false, only enough of the task is set up to complete
|
||||
* the isEnabled test for the action. Otherwise the whole task is set up, ready for runTask().
|
||||
* If the context is not suitable for a conversion, null is returned.
|
||||
* @param context is the given context for the action
|
||||
* @param setupFinal is true if a full task setup is needed
|
||||
* @return the task object or null
|
||||
*/
|
||||
protected ConvertConstantTask establishTask(DecompilerActionContext context,
|
||||
boolean setupFinal) {
|
||||
|
||||
ClangToken tokenAtCursor = context.getTokenAtCursor();
|
||||
if (!(tokenAtCursor instanceof ClangVariableToken)) {
|
||||
return null;
|
||||
}
|
||||
Varnode convertVn = tokenAtCursor.getVarnode();
|
||||
if (convertVn == null || !convertVn.isConstant() || convertVn.getSize() > MAX_SCALAR_SIZE) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HighSymbol symbol = convertVn.getHigh().getSymbol();
|
||||
EquateSymbol convertSymbol = null;
|
||||
if (symbol != null) {
|
||||
if (symbol instanceof EquateSymbol) {
|
||||
convertSymbol = (EquateSymbol) symbol;
|
||||
int type = convertSymbol.getConvert();
|
||||
if (type == convertType || type == EquateSymbol.FORMAT_DEFAULT) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return null; // Something already attached to constant
|
||||
}
|
||||
}
|
||||
|
||||
DataType convertDataType = convertVn.getHigh().getDataType();
|
||||
boolean convertIsSigned = false;
|
||||
if (convertDataType instanceof AbstractIntegerDataType) {
|
||||
if (convertDataType instanceof BooleanDataType) {
|
||||
return null;
|
||||
}
|
||||
convertIsSigned = ((AbstractIntegerDataType) convertDataType).isSigned();
|
||||
}
|
||||
else if (convertDataType instanceof Enum) {
|
||||
return null;
|
||||
}
|
||||
if (!setupFinal) {
|
||||
return new ConvertConstantTask(convertVn, convertIsSigned);
|
||||
}
|
||||
|
||||
if (convertSymbol != null) {
|
||||
return convertExistingSymbol(context, convertSymbol, convertVn, convertIsSigned);
|
||||
}
|
||||
|
||||
PcodeOp op = convertVn.getLoneDescend();
|
||||
Address convertAddr = op.getSeqnum().getTarget();
|
||||
DynamicHash dynamicHash = new DynamicHash(convertVn, 0);
|
||||
long convertHash = dynamicHash.getHash();
|
||||
Program program = context.getProgram();
|
||||
ScalarMatch scalarMatch = findScalarMatch(program, convertAddr, convertVn);
|
||||
if (scalarMatch == null) {
|
||||
String equateName = getEquateName(convertVn.getOffset(), convertVn.getSize(),
|
||||
convertIsSigned, program);
|
||||
if (equateName == null) {
|
||||
return null; // A null is a user cancel
|
||||
}
|
||||
return new ConvertConstantTask(context, equateName, convertAddr, convertVn,
|
||||
convertIsSigned, convertHash, -1);
|
||||
}
|
||||
|
||||
long value = scalarMatch.scalar.getUnsignedValue();
|
||||
int size = scalarMatch.scalar.bitLength() / 8;
|
||||
if (size == 0) {
|
||||
size = 1;
|
||||
}
|
||||
value = ConvertConstantTask.signExtendValue(convertIsSigned, value, size);
|
||||
String equateName = getEquateName(value, size, convertIsSigned, program);
|
||||
if (equateName == null) {
|
||||
return null; // user cancelled
|
||||
}
|
||||
|
||||
ConvertConstantTask task =
|
||||
new ConvertConstantTask(context, equateName, convertAddr, convertVn,
|
||||
convertIsSigned, convertHash, -1);
|
||||
|
||||
// Don't create a named equate if the varnode and the instruction operand differ
|
||||
// as the name was selected specifically for the varnode
|
||||
if (convertType != EquateSymbol.FORMAT_DEFAULT || value == task.getValue()) {
|
||||
task.setAlternate(equateName, scalarMatch.refAddr, scalarMatch.opIndex, value);
|
||||
}
|
||||
return task;
|
||||
}
|
||||
|
||||
private ConvertConstantTask convertExistingSymbol(DecompilerActionContext context,
|
||||
EquateSymbol convertSymbol, Varnode convertVn, boolean convertIsSigned) {
|
||||
|
||||
Address convertAddr = convertSymbol.getPCAddress();
|
||||
long convertHash = 0;
|
||||
int convertIndex = -1;
|
||||
boolean foundEquate = false;
|
||||
Program program = context.getProgram();
|
||||
EquateTable equateTable = program.getEquateTable();
|
||||
List<Equate> equates = equateTable.getEquates(convertAddr);
|
||||
for (Equate equate : equates) {
|
||||
if (equate.getValue() != convertVn.getOffset()) {
|
||||
continue;
|
||||
}
|
||||
for (EquateReference equateRef : equate.getReferences(convertAddr)) {
|
||||
convertHash = equateRef.getDynamicHashValue();
|
||||
convertIndex = equateRef.getOpIndex();
|
||||
foundEquate = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!foundEquate) {
|
||||
Msg.error(this, "Symbol does not have matching entry in equate table");
|
||||
return null;
|
||||
}
|
||||
|
||||
String equateName = getEquateName(convertVn.getOffset(), convertVn.getSize(),
|
||||
convertIsSigned, context.getProgram());
|
||||
if (equateName == null) { // A null is a user cancel
|
||||
return null;
|
||||
}
|
||||
return new ConvertConstantTask(context, equateName, convertAddr, convertVn,
|
||||
convertIsSigned, convertHash, convertIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEnabledForDecompilerContext(DecompilerActionContext context) {
|
||||
ConvertConstantTask task = establishTask(context, false);
|
||||
if (task == null) {
|
||||
Scalar scalar;
|
||||
scalar = getCaseConstant(context, convertType);
|
||||
if (scalar == null) {
|
||||
scalar = ConvertConstantEquateTask.getConvertibleConstant(context, convertType);
|
||||
}
|
||||
if (scalar == null) {
|
||||
return false;
|
||||
}
|
||||
String convDisplay =
|
||||
getMenuDisplay(task.getValue(), task.getSize(), task.isSigned(), context.getProgram());
|
||||
String convDisplay = getMenuDisplay(scalar, context.getProgram());
|
||||
if (convDisplay == null) {
|
||||
return false;
|
||||
}
|
||||
@@ -352,13 +141,72 @@ public abstract class ConvertConstantAction extends AbstractDecompilerAction {
|
||||
|
||||
@Override
|
||||
protected void decompilerActionPerformed(DecompilerActionContext context) {
|
||||
ConvertConstantTask task = establishTask(context, true);
|
||||
if (context.getTokenAtCursor() instanceof ClangCaseToken) {
|
||||
writeSwitchFormat(context);
|
||||
return;
|
||||
}
|
||||
ConvertConstantEquateTask task = ConvertConstantEquateTask.establishTask(context, this);
|
||||
if (task == null) {
|
||||
return;
|
||||
}
|
||||
task.runTask();
|
||||
}
|
||||
|
||||
/**
|
||||
* If the mouse context is a constant from a switch case that is suitable for conversion
|
||||
* return a description of the constant. Otherwise return null.
|
||||
* @param context is the mouse context
|
||||
* @param convertType is the type of conversion being selected (FORMAT_DEC FORMAT_HEX etc.)
|
||||
* @return the constant description or null
|
||||
*/
|
||||
static protected Scalar getCaseConstant(DecompilerActionContext context,
|
||||
int convertType) {
|
||||
ClangToken tokenAtCursor = context.getTokenAtCursor();
|
||||
if (!(tokenAtCursor instanceof ClangCaseToken)) {
|
||||
return null;
|
||||
}
|
||||
if (convertType == EquateSymbol.FORMAT_DEFAULT ||
|
||||
convertType == EquateSymbol.FORMAT_DOUBLE || convertType == EquateSymbol.FORMAT_FLOAT) {
|
||||
return null;
|
||||
}
|
||||
ClangCaseToken caseToken = (ClangCaseToken) tokenAtCursor;
|
||||
HighVariable high = caseToken.getHighVariable();
|
||||
if (high == null) {
|
||||
return null;
|
||||
}
|
||||
DataType convertDataType = high.getDataType();
|
||||
boolean convertIsSigned = false;
|
||||
if (convertDataType instanceof AbstractIntegerDataType) {
|
||||
if (convertDataType instanceof BooleanDataType) {
|
||||
return null;
|
||||
}
|
||||
convertIsSigned = ((AbstractIntegerDataType) convertDataType).isSigned();
|
||||
}
|
||||
else if (convertDataType instanceof Enum) {
|
||||
return null;
|
||||
}
|
||||
return new Scalar(high.getSize() * 8, caseToken.getValue(), convertIsSigned);
|
||||
}
|
||||
|
||||
private void writeSwitchFormat(DecompilerActionContext context) {
|
||||
ClangCaseToken caseToken = (ClangCaseToken) context.getTokenAtCursor();
|
||||
PcodeOp switchOp = caseToken.getSwitchOp();
|
||||
Function func = context.getFunction();
|
||||
Program program = context.getProgram();
|
||||
int transaction = program.startTransaction("Convert case constants");
|
||||
boolean commit = false;
|
||||
try {
|
||||
JumpTable.writeFormat(func, switchOp.getSeqnum().getTarget(), convertType);
|
||||
commit = true;
|
||||
}
|
||||
catch (InvalidInputException ex) {
|
||||
Msg.error(this, ex);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transaction, commit);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The menu option for this kind of action is intended to look like:
|
||||
* {@literal Hexadecimal: 0x2408}
|
||||
@@ -372,22 +220,18 @@ public abstract class ConvertConstantAction extends AbstractDecompilerAction {
|
||||
* {@literal Hexadecimal: 0x2408}
|
||||
* This method constructs the final part of this string, after the colon by
|
||||
* formatting the actual value that is to be converted.
|
||||
* @param value is the actual value
|
||||
* @param size is the number of bytes used for the constant Varnode
|
||||
* @param isSigned is true if the constant represents a signed data-type
|
||||
* @param scalar is the constant being converted
|
||||
* @param program the program
|
||||
* @return the formatted String
|
||||
*/
|
||||
public abstract String getMenuDisplay(long value, int size, boolean isSigned, Program program);
|
||||
public abstract String getMenuDisplay(Scalar scalar, Program program);
|
||||
|
||||
/**
|
||||
* Construct the name of the Equate, either absolutely for a conversion or
|
||||
* by preventing the user with a dialog to select a name.
|
||||
* @param value is the value being converted
|
||||
* @param size is the number of bytes used for the constant Varnode
|
||||
* @param isSigned is true if the constant represents a signed data-type
|
||||
* @param scalar is the constant being converted
|
||||
* @param program is the current Program
|
||||
* @return the equate name
|
||||
*/
|
||||
public abstract String getEquateName(long value, int size, boolean isSigned, Program program);
|
||||
public abstract String getEquateName(Scalar scalar, Program program);
|
||||
}
|
||||
|
||||
+548
File diff suppressed because it is too large
Load Diff
-342
@@ -1,342 +0,0 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.plugin.core.decompile.actions;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.pcode.*;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
import utility.function.Callback;
|
||||
|
||||
/**
|
||||
* Create an equate in the table for the specific Address and hash value.
|
||||
* The equate is not assumed to be attached to a particular instruction operand and
|
||||
* uses the dynamic hash value to identify the particular constant (within p-code) to label.
|
||||
*
|
||||
* If altAddress is non-null and the other alt* fields are filled in, the task attempts
|
||||
* to set the equation on the altAddress first to get the representation of the p-code
|
||||
* constant at convertAddress to change. After the decompilation finishes, the representation
|
||||
* is checked, and if it did not change, the alt* equate is removed and an equate is created
|
||||
* directly for the convertAddress;
|
||||
*/
|
||||
public class ConvertConstantTask implements Callback {
|
||||
private DecompilerActionContext context;
|
||||
private Program program;
|
||||
private long equateValue; // Primary value of the equate
|
||||
private int equateSize; // The number of bytes in the Varnode constant being equated
|
||||
private Address convertAddress; // The primary address of the Equate
|
||||
private String convertName; // The primary name to use in the Equate table
|
||||
private long convertHash; // A dynamic hash locating the constant Varnode in data-flow
|
||||
private int convertIndex; // The scalar index associated with the primary Equate (or -1)
|
||||
private boolean convertSigned;
|
||||
|
||||
private Address altAddress = null; // Alternate location of constant
|
||||
private int altIndex; // Index of alternate scalar
|
||||
private String altName = null; // Alternate equate name
|
||||
private long altValue; // Alternate value
|
||||
|
||||
public ConvertConstantTask(Varnode vn, boolean isSigned) {
|
||||
equateValue = signExtendValue(isSigned, vn.getOffset(), vn.getSize());
|
||||
equateSize = vn.getSize();
|
||||
convertSigned = isSigned;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a primary Equate task
|
||||
* @param context is the action context for the task
|
||||
* @param name is the primary Equate name
|
||||
* @param addr is the primary address of the Equate
|
||||
* @param vn is the constant Varnode being equated
|
||||
* @param isSigned is true if the equate value is considered signed
|
||||
* @param hash is the dynamic hash
|
||||
* @param index is the operand index if the Equate is known to label an instruction operand
|
||||
*/
|
||||
public ConvertConstantTask(DecompilerActionContext context, String name, Address addr,
|
||||
Varnode vn, boolean isSigned, long hash, int index) {
|
||||
this.context = context;
|
||||
program = context.getProgram();
|
||||
convertName = name;
|
||||
convertAddress = addr;
|
||||
equateValue = signExtendValue(isSigned, vn.getOffset(), vn.getSize());
|
||||
equateSize = vn.getSize();
|
||||
convertSigned = isSigned;
|
||||
convertHash = hash;
|
||||
convertIndex = index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Negative equates must be sign extended to 64-bits to be properly stored in the table.
|
||||
* Compute the proper 64-bit value of a constant given its signedness and the number
|
||||
* of bytes used to store the constant.
|
||||
* @param isSigned is true if the equate is considered signed
|
||||
* @param value is the (unsigned) form of the constant
|
||||
* @param size is the number of bytes used to store the constant
|
||||
* @return the 64-bit extended value
|
||||
*/
|
||||
public static long signExtendValue(boolean isSigned, long value, int size) {
|
||||
if (isSigned && size < 8) {
|
||||
int sa = (8 /* sizeof(long) */ - size) * 8 /* bits per byte */;
|
||||
value <<= sa;
|
||||
value >>= sa;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Establish an alternate Equate to try before falling back on the primary Equate
|
||||
* @param name is the alternate name of the Equate
|
||||
* @param addr is the alternate address
|
||||
* @param index is the operand index
|
||||
* @param value is the alternate constant value to equate
|
||||
*/
|
||||
public void setAlternate(String name, Address addr, int index, long value) {
|
||||
altName = name;
|
||||
altAddress = addr;
|
||||
altValue = value;
|
||||
altIndex = index;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the primary value being equated
|
||||
*/
|
||||
public long getValue() {
|
||||
return equateValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the size of constant (Varnode) being equated
|
||||
*/
|
||||
public int getSize() {
|
||||
return equateSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the constant value is treated as a signed integer
|
||||
*/
|
||||
public boolean isSigned() {
|
||||
return convertSigned;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove any pre-existing equate reference with the same address and hash as the
|
||||
* primate equate.
|
||||
*/
|
||||
private void removePrimaryReference() {
|
||||
EquateTable equateTable = program.getEquateTable();
|
||||
List<Equate> equates = equateTable.getEquates(convertAddress);
|
||||
for (Equate equate : equates) {
|
||||
List<EquateReference> references = equate.getReferences(convertAddress);
|
||||
for (EquateReference ref : references) {
|
||||
if (ref.getDynamicHashValue() == convertHash) {
|
||||
if (equate.getReferenceCount() <= 1) {
|
||||
equateTable.removeEquate(equate.getName());
|
||||
}
|
||||
else {
|
||||
equate.removeReference(convertHash, convertAddress);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove and pre-existing equate reference with the same address and hash as the
|
||||
* alternate equate.
|
||||
*/
|
||||
private void removeAlternateReference() {
|
||||
EquateTable equateTable = program.getEquateTable();
|
||||
List<Equate> equates = equateTable.getEquates(altAddress);
|
||||
for (Equate equate : equates) {
|
||||
List<EquateReference> references = equate.getReferences(altAddress);
|
||||
for (EquateReference ref : references) {
|
||||
if (ref.getOpIndex() == altIndex) {
|
||||
if (equate.getReferenceCount() <= 1) {
|
||||
equateTable.removeEquate(equate.getName());
|
||||
}
|
||||
else {
|
||||
equate.removeReference(altAddress, altIndex);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add equate based on the alternate constant information: altAddress, altName, altIndex
|
||||
* @throws DuplicateNameException if there is already an equate with same name but different value
|
||||
* @throws InvalidInputException if the equate name is illegal
|
||||
*/
|
||||
private void addPrimaryEquate() throws DuplicateNameException, InvalidInputException {
|
||||
EquateTable equateTable = program.getEquateTable();
|
||||
Equate equate = equateTable.getEquate(convertName);
|
||||
|
||||
if (equate != null && equate.getValue() != equateValue) {
|
||||
String msg = "Equate named " + convertName + " already exists with value of " +
|
||||
equate.getValue() + ".";
|
||||
throw new DuplicateNameException(msg);
|
||||
}
|
||||
|
||||
if (equate == null) {
|
||||
equate = equateTable.createEquate(convertName, equateValue);
|
||||
}
|
||||
|
||||
// Add reference to existing equate
|
||||
if (convertHash != 0) {
|
||||
equate.addReference(convertHash, convertAddress);
|
||||
}
|
||||
else {
|
||||
equate.addReference(convertAddress, convertIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add equate based on the direct constant information: convertAddress, convertName, convertHash
|
||||
* @throws DuplicateNameException if there is already an equate with same name but different value
|
||||
* @throws InvalidInputException if the equate name is illegal
|
||||
*/
|
||||
private void addAlternateEquate() throws InvalidInputException, DuplicateNameException {
|
||||
EquateTable equateTable = program.getEquateTable();
|
||||
Equate equate = equateTable.getEquate(altName);
|
||||
|
||||
if (equate != null && equate.getValue() != altValue) {
|
||||
String msg = "Equate named " + altName + " already exists with value of " +
|
||||
equate.getValue() + ".";
|
||||
throw new DuplicateNameException(msg);
|
||||
}
|
||||
|
||||
if (equate == null) {
|
||||
equate = equateTable.createEquate(altName, altValue);
|
||||
}
|
||||
|
||||
equate.addReference(altAddress, altIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a reference to primary equate, removing any previous reference.
|
||||
* If an alternate equate is given, remove any existing reference to it as well.
|
||||
*/
|
||||
private void applyPrimaryEquate() {
|
||||
|
||||
int transaction = program.startTransaction("Convert constant");
|
||||
boolean commit = false;
|
||||
try {
|
||||
if (altAddress != null) {
|
||||
removeAlternateReference();
|
||||
}
|
||||
removePrimaryReference();
|
||||
addPrimaryEquate();
|
||||
commit = true;
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
Msg.showError(this, null, "Convert Failed", e.getMessage());
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
Msg.showError(this, null, "Convert Failed", e.getMessage());
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transaction, commit);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a reference to the alternate equate.
|
||||
*/
|
||||
private void applyAlternateEquate() {
|
||||
int transaction = program.startTransaction("Convert constant");
|
||||
boolean commit = false;
|
||||
try {
|
||||
addAlternateEquate();
|
||||
commit = true;
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
Msg.showError(this, null, "Convert Failed", e.getMessage());
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
Msg.showError(this, null, "Convert Failed", e.getMessage());
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transaction, commit);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for the EquateSymbol pointing to the altAddress, attached to the constant
|
||||
* @return true if we find the EquateSymbol, false otherwise
|
||||
*/
|
||||
private boolean isAlternatePlaced() {
|
||||
HighFunction highFunction = context.getHighFunction(); // Get the updated HighFunction
|
||||
if (highFunction == null) {
|
||||
return false;
|
||||
}
|
||||
// Varnode itself should be unchanged
|
||||
Varnode vn = DynamicHash.findVarnode(highFunction, convertAddress, convertHash);
|
||||
if (vn == null) {
|
||||
return false;
|
||||
}
|
||||
HighSymbol symbol = vn.getHigh().getSymbol(); // But now it should have an equate on it
|
||||
if (!(symbol instanceof EquateSymbol)) {
|
||||
return false;
|
||||
}
|
||||
EquateSymbol eqSymbol = (EquateSymbol) symbol;
|
||||
if (!eqSymbol.getPCAddress().equals(altAddress)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback executed after the alternative equate is placed and the DecompilerProvider has updated its window.
|
||||
* We check to see if the equate reached the desired constant in the decompiler.
|
||||
* If not, we remove the alternate equate and place a direct equate
|
||||
*/
|
||||
@Override
|
||||
public void call() {
|
||||
if (isAlternatePlaced()) {
|
||||
return;
|
||||
}
|
||||
applyPrimaryEquate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the convert task. If the task is given an alternate equate, this is placed, otherwise
|
||||
* the primary equate is placed. If an alternate is placed, a thread is scheduled to check if
|
||||
* the alternate equate reached the constant Varnode. If not the alternate equate reference is
|
||||
* removed, and the task falls back and places the primary equate.
|
||||
*/
|
||||
public void runTask() {
|
||||
if (altAddress != null) {
|
||||
applyAlternateEquate();
|
||||
try {
|
||||
Thread.sleep(50); // Let the decompiler get going
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
return;
|
||||
}
|
||||
context.getComponentProvider().doWhenNotBusy(this);
|
||||
}
|
||||
else {
|
||||
applyPrimaryEquate();
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-7
@@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -39,14 +39,13 @@ public class ConvertDecAction extends ConvertConstantAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMenuDisplay(long value, int size, boolean isSigned, Program program) {
|
||||
return getEquateName(value, size, isSigned, program);
|
||||
public String getMenuDisplay(Scalar scalar, Program program) {
|
||||
return getEquateName(scalar, program);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEquateName(long value, int size, boolean isSigned, Program program) {
|
||||
Scalar scalar = new Scalar(size * 8, value);
|
||||
if (isSigned) {
|
||||
public String getEquateName(Scalar scalar, Program program) {
|
||||
if (scalar.isSigned()) {
|
||||
return Long.toString(scalar.getSignedValue());
|
||||
}
|
||||
return Long.toString(scalar.getUnsignedValue());
|
||||
|
||||
+7
-8
@@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -41,19 +41,18 @@ public class ConvertDoubleAction extends ConvertConstantAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMenuDisplay(long value, int size, boolean isSigned, Program program) {
|
||||
return getText(value, size, isSigned, program);
|
||||
public String getMenuDisplay(Scalar scalar, Program program) {
|
||||
return getText(scalar, program);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEquateName(long value, int size, boolean isSigned, Program program) {
|
||||
return getText(value, size, isSigned, program);
|
||||
public String getEquateName(Scalar scalar, Program program) {
|
||||
return getText(scalar, program);
|
||||
}
|
||||
|
||||
private String getText(long value, int size, boolean isSigned, Program program) {
|
||||
private String getText(Scalar scalar, Program program) {
|
||||
DataOrganization organization = program.getDataTypeManager().getDataOrganization();
|
||||
int doubleSize = organization.getDoubleSize();
|
||||
Scalar scalar = new Scalar(size * 8, value);
|
||||
BigDecimal bd = value(doubleSize, scalar);
|
||||
if (bd != null) {
|
||||
return bd.toString();
|
||||
|
||||
+7
-8
@@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -41,19 +41,18 @@ public class ConvertFloatAction extends ConvertConstantAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMenuDisplay(long value, int size, boolean isSigned, Program program) {
|
||||
return getText(value, size, isSigned, program);
|
||||
public String getMenuDisplay(Scalar scalar, Program program) {
|
||||
return getText(scalar, program);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEquateName(long value, int size, boolean isSigned, Program program) {
|
||||
return getText(value, size, isSigned, program);
|
||||
public String getEquateName(Scalar scalar, Program program) {
|
||||
return getText(scalar, program);
|
||||
}
|
||||
|
||||
private String getText(long value, int size, boolean isSigned, Program program) {
|
||||
private String getText(Scalar scalar, Program program) {
|
||||
DataOrganization organization = program.getDataTypeManager().getDataOrganization();
|
||||
int floatSize = organization.getFloatSize();
|
||||
Scalar scalar = new Scalar(size * 8, value);
|
||||
BigDecimal bd = value(floatSize, scalar);
|
||||
if (bd != null) {
|
||||
return bd.toString();
|
||||
|
||||
+6
-8
@@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -40,9 +40,8 @@ public class ConvertHexAction extends ConvertConstantAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMenuDisplay(long value, int size, boolean isSigned, Program program) {
|
||||
Scalar scalar = new Scalar(size * 8, value);
|
||||
if (isSigned) {
|
||||
public String getMenuDisplay(Scalar scalar, Program program) {
|
||||
if (scalar.isSigned()) {
|
||||
long v = scalar.getSignedValue();
|
||||
String valueStr = Long.toString(v, 16);
|
||||
if (v < 0) {
|
||||
@@ -56,9 +55,8 @@ public class ConvertHexAction extends ConvertConstantAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEquateName(long value, int size, boolean isSigned, Program program) {
|
||||
Scalar scalar = new Scalar(size * 8, value);
|
||||
if (isSigned) {
|
||||
public String getEquateName(Scalar scalar, Program program) {
|
||||
if (scalar.isSigned()) {
|
||||
long v = scalar.getSignedValue();
|
||||
String valueStr = Long.toString(v, 16).toUpperCase();
|
||||
if (v < 0) {
|
||||
|
||||
+5
-7
@@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -40,9 +40,8 @@ public class ConvertOctAction extends ConvertConstantAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMenuDisplay(long value, int size, boolean isSigned, Program program) {
|
||||
Scalar scalar = new Scalar(size * 8, value);
|
||||
if (isSigned) {
|
||||
public String getMenuDisplay(Scalar scalar, Program program) {
|
||||
if (scalar.isSigned()) {
|
||||
long v = scalar.getSignedValue();
|
||||
String valueStr = Long.toString(v, 8);
|
||||
if (v < 0) {
|
||||
@@ -56,8 +55,7 @@ public class ConvertOctAction extends ConvertConstantAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEquateName(long value, int size, boolean isSigned, Program program) {
|
||||
Scalar scalar = new Scalar(size * 8, value);
|
||||
public String getEquateName(Scalar scalar, Program program) {
|
||||
return Long.toOctalString(scalar.getUnsignedValue()) + "o";
|
||||
}
|
||||
}
|
||||
|
||||
+58
-8
@@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -18,9 +18,9 @@ package ghidra.app.plugin.core.decompile.actions;
|
||||
import java.util.List;
|
||||
|
||||
import docking.action.MenuData;
|
||||
import ghidra.app.decompiler.ClangToken;
|
||||
import ghidra.app.decompiler.ClangVariableToken;
|
||||
import ghidra.app.decompiler.*;
|
||||
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
|
||||
import ghidra.app.plugin.core.decompile.actions.ConvertConstantAction.NearMatchValues;
|
||||
import ghidra.app.util.HelpTopics;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Program;
|
||||
@@ -28,7 +28,12 @@ import ghidra.program.model.pcode.*;
|
||||
import ghidra.program.model.symbol.Equate;
|
||||
import ghidra.program.model.symbol.EquateTable;
|
||||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
|
||||
/**
|
||||
* Remove a selected conversion or other equate set on a constant
|
||||
*/
|
||||
public class RemoveEquateAction extends AbstractDecompilerAction {
|
||||
|
||||
public RemoveEquateAction() {
|
||||
@@ -40,6 +45,17 @@ public class RemoveEquateAction extends AbstractDecompilerAction {
|
||||
@Override
|
||||
protected boolean isEnabledForDecompilerContext(DecompilerActionContext context) {
|
||||
ClangToken tokenAtCursor = context.getTokenAtCursor();
|
||||
if (tokenAtCursor instanceof ClangCaseToken) {
|
||||
// Check for a conversion applied to case labels on a specific jumptable/switch
|
||||
PcodeOp switchOp = ((ClangCaseToken) tokenAtCursor).getSwitchOp();
|
||||
if (switchOp != null) {
|
||||
int format = JumpTable.getFormatOverride(context.getFunction(),
|
||||
switchOp.getSeqnum().getTarget());
|
||||
return (EquateSymbol.FORMAT_DEFAULT != format);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Check for any Equate on a constant token
|
||||
if (!(tokenAtCursor instanceof ClangVariableToken)) {
|
||||
return false;
|
||||
}
|
||||
@@ -51,6 +67,13 @@ public class RemoveEquateAction extends AbstractDecompilerAction {
|
||||
return (symbol instanceof EquateSymbol);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a specific Equate reference on a constant
|
||||
* @param program is the Program
|
||||
* @param equate is the Equate being referenced
|
||||
* @param refAddr is the address of the reference
|
||||
* @param convertHash is a dynamic hash of the Varnode (or -1 if the equate is on an instruction)
|
||||
*/
|
||||
private void removeReference(Program program, Equate equate, Address refAddr,
|
||||
long convertHash) {
|
||||
int transaction = program.startTransaction("Remove Equate Reference");
|
||||
@@ -70,9 +93,35 @@ public class RemoveEquateAction extends AbstractDecompilerAction {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the integer format override for a specific JumpTable
|
||||
* @param context is the selected context
|
||||
* @param opAddress is the address of the JumpTable branch site
|
||||
*/
|
||||
private void removeCaseOverride(DecompilerActionContext context, Address opAddress) {
|
||||
Program program = context.getProgram();
|
||||
int transaction = program.startTransaction("Remove Case Label Override");
|
||||
boolean commit = false;
|
||||
try {
|
||||
JumpTable.writeFormat(context.getFunction(), opAddress, transaction);
|
||||
commit = true;
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
Msg.error(this, e);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transaction, commit);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decompilerActionPerformed(DecompilerActionContext context) {
|
||||
ClangToken tokenAtCursor = context.getTokenAtCursor();
|
||||
if (tokenAtCursor instanceof ClangCaseToken) {
|
||||
PcodeOp switchOp = ((ClangCaseToken) tokenAtCursor).getSwitchOp();
|
||||
removeCaseOverride(context, switchOp.getSeqnum().getTarget());
|
||||
return;
|
||||
}
|
||||
if (!(tokenAtCursor instanceof ClangVariableToken)) {
|
||||
return;
|
||||
}
|
||||
@@ -91,12 +140,13 @@ public class RemoveEquateAction extends AbstractDecompilerAction {
|
||||
Program program = context.getProgram();
|
||||
EquateTable equateTable = program.getEquateTable();
|
||||
List<Equate> equates = equateTable.getEquates(convertAddr);
|
||||
NearMatchValues values =
|
||||
new NearMatchValues(convertVn.getOffset(), convertVn.getSize());
|
||||
for (Equate equate : equates) {
|
||||
if (equate.getValue() != convertVn.getOffset()) {
|
||||
continue;
|
||||
if (values.isMatch(equate.getValue())) {
|
||||
removeReference(program, equate, convertAddr, convertHash);
|
||||
break;
|
||||
}
|
||||
removeReference(program, equate, convertAddr, convertHash);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-7
@@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -43,16 +43,15 @@ public class SetEquateAction extends ConvertConstantAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMenuDisplay(long value, int size, boolean isSigned, Program program) {
|
||||
public String getMenuDisplay(Scalar scalar, Program program) {
|
||||
return null; // Menu isn't tailored for this action
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEquateName(long value, int size, boolean isSigned, Program program) {
|
||||
public String getEquateName(Scalar scalar, Program program) {
|
||||
if (program == null) {
|
||||
return null;
|
||||
}
|
||||
Scalar scalar = new Scalar(size * 8, value, isSigned);
|
||||
SetEquateDialog dialog = new SetEquateDialog(plugin.getTool(), program, scalar);
|
||||
dialog.disableHasSelection();
|
||||
int res = dialog.showSetDialog();
|
||||
@@ -66,7 +65,7 @@ public class SetEquateAction extends ConvertConstantAction {
|
||||
|
||||
@Override
|
||||
protected boolean isEnabledForDecompilerContext(DecompilerActionContext context) {
|
||||
ConvertConstantTask task = establishTask(context, false);
|
||||
return (task != null);
|
||||
Scalar scalar = ConvertConstantEquateTask.getConvertibleConstant(context, convertType);
|
||||
return (scalar != null);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -27,6 +27,7 @@ import ghidra.app.decompiler.component.ClangTextField;
|
||||
import ghidra.app.plugin.core.decompile.actions.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.pcode.*;
|
||||
import ghidra.program.model.scalar.Scalar;
|
||||
import ghidra.program.model.symbol.*;
|
||||
|
||||
public class DecompilerEquateTest extends AbstractDecompilerTest {
|
||||
@@ -41,7 +42,7 @@ public class DecompilerEquateTest extends AbstractDecompilerTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEquateName(long value, int size, boolean isSigned, Program program) {
|
||||
public String getEquateName(Scalar scalar, Program program) {
|
||||
if (program == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
+56
-25
@@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -115,34 +115,65 @@ public class EquateSymbol extends HighSymbol {
|
||||
decoder.closeElement(symel);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param convert is an integer conversion type
|
||||
* @return the name of the corresponding conversion
|
||||
*/
|
||||
public static String getIntegerFormatString(int convert) {
|
||||
if (convert == FORMAT_HEX) {
|
||||
return "hex";
|
||||
}
|
||||
else if (convert == FORMAT_DEC) {
|
||||
return "dec";
|
||||
}
|
||||
else if (convert == FORMAT_OCT) {
|
||||
return "oct";
|
||||
}
|
||||
else if (convert == FORMAT_BIN) {
|
||||
return "bin";
|
||||
}
|
||||
else if (convert == FORMAT_CHAR) {
|
||||
return "char";
|
||||
}
|
||||
else if (convert == FORMAT_FLOAT) {
|
||||
return "float";
|
||||
}
|
||||
else if (convert == FORMAT_DOUBLE) {
|
||||
return "double";
|
||||
}
|
||||
return "_";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param format is the name of a conversion format
|
||||
* @return return the matching conversion type or FORMAT_DEFAULT if there is no matching conversion
|
||||
*/
|
||||
public static int getFormatStringValue(String format) {
|
||||
switch (format) {
|
||||
case "hex":
|
||||
return FORMAT_HEX;
|
||||
case "dec":
|
||||
return FORMAT_DEC;
|
||||
case "oct":
|
||||
return FORMAT_OCT;
|
||||
case "bin":
|
||||
return FORMAT_BIN;
|
||||
case "char":
|
||||
return FORMAT_CHAR;
|
||||
case "float":
|
||||
return FORMAT_FLOAT;
|
||||
case "double":
|
||||
return FORMAT_DOUBLE;
|
||||
}
|
||||
return FORMAT_DEFAULT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(Encoder encoder) throws IOException {
|
||||
encoder.openElement(ELEM_EQUATESYMBOL);
|
||||
encodeHeader(encoder);
|
||||
if (convert != 0) {
|
||||
String formString = "hex";
|
||||
if (convert == FORMAT_HEX) {
|
||||
// Most common case
|
||||
}
|
||||
else if (convert == FORMAT_DEC) {
|
||||
formString = "dec";
|
||||
}
|
||||
else if (convert == FORMAT_OCT) {
|
||||
formString = "oct";
|
||||
}
|
||||
else if (convert == FORMAT_BIN) {
|
||||
formString = "bin";
|
||||
}
|
||||
else if (convert == FORMAT_CHAR) {
|
||||
formString = "char";
|
||||
}
|
||||
else if (convert == FORMAT_FLOAT) {
|
||||
formString = "float";
|
||||
}
|
||||
else if (convert == FORMAT_DOUBLE) {
|
||||
formString = "double";
|
||||
}
|
||||
|
||||
String formString = getIntegerFormatString(convert);
|
||||
encoder.writeString(ATTRIB_FORMAT, formString);
|
||||
}
|
||||
encoder.openElement(ELEM_VALUE);
|
||||
|
||||
+1
-1
@@ -302,7 +302,7 @@ public class HighFunction extends PcodeSyntaxTree {
|
||||
private void decodeJumpTableList(Decoder decoder) throws DecoderException {
|
||||
int el = decoder.openElement(ELEM_JUMPTABLELIST);
|
||||
while (decoder.peekElement() != 0) {
|
||||
JumpTable table = new JumpTable(entryPoint.getAddressSpace());
|
||||
JumpTable table = new JumpTable();
|
||||
table.decode(decoder);
|
||||
if (!table.isEmpty()) {
|
||||
if (jumpTables == null) {
|
||||
|
||||
+103
-20
@@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -23,7 +23,6 @@ import java.util.ArrayList;
|
||||
|
||||
import ghidra.program.database.symbol.CodeSymbol;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.symbol.*;
|
||||
@@ -101,7 +100,6 @@ public class JumpTable {
|
||||
}
|
||||
}
|
||||
|
||||
private AddressSpace preferredSpace;
|
||||
private Address opAddress;
|
||||
|
||||
// Address corresponds to label entries. If DEFAULT_VALUE, then entry is the default guard case, not a jump target.
|
||||
@@ -109,21 +107,22 @@ public class JumpTable {
|
||||
private Integer labelTable[];
|
||||
private LoadTable loadTable[];
|
||||
private BasicOverride override;
|
||||
private int displayFormat; // Default format for displaying integer case values
|
||||
|
||||
public JumpTable(AddressSpace preferredSpace) {
|
||||
this.preferredSpace = preferredSpace;
|
||||
public JumpTable() {
|
||||
opAddress = null;
|
||||
addressTable = null;
|
||||
labelTable = null;
|
||||
loadTable = null;
|
||||
override = null;
|
||||
displayFormat = 0;
|
||||
}
|
||||
|
||||
public JumpTable(Address addr, ArrayList<Address> destlist, boolean override) {
|
||||
public JumpTable(Address addr, ArrayList<Address> destlist, boolean override, int format) {
|
||||
opAddress = addr;
|
||||
preferredSpace = opAddress.getAddressSpace();
|
||||
labelTable = null;
|
||||
loadTable = null;
|
||||
displayFormat = format;
|
||||
if (override) {
|
||||
addressTable = null;
|
||||
this.override = new BasicOverride(destlist);
|
||||
@@ -152,6 +151,9 @@ public class JumpTable {
|
||||
*/
|
||||
public void decode(Decoder decoder) throws DecoderException {
|
||||
int el = decoder.openElement(ELEM_JUMPTABLE);
|
||||
if (decoder.getNextAttributeId() == ATTRIB_FORMAT.id()) {
|
||||
displayFormat = (int) decoder.readUnsignedInteger();
|
||||
}
|
||||
if (decoder.peekElement() == 0) { // Empty jumptable
|
||||
decoder.closeElement(el);
|
||||
return;
|
||||
@@ -206,6 +208,9 @@ public class JumpTable {
|
||||
|
||||
public void encode(Encoder encoder) throws IOException {
|
||||
encoder.openElement(ELEM_JUMPTABLE);
|
||||
if (displayFormat != 0) {
|
||||
encoder.writeUnsignedInteger(ATTRIB_FORMAT, displayFormat);
|
||||
}
|
||||
AddressXML.encode(encoder, opAddress);
|
||||
if (addressTable != null) {
|
||||
for (Address element : addressTable) {
|
||||
@@ -236,6 +241,82 @@ public class JumpTable {
|
||||
return loadTable.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find or create a namespace for a specific jumptable
|
||||
* @param func is the function with the jumptable
|
||||
* @param opAddress is the address of the call point using the table
|
||||
* @param symtab is the symbol table
|
||||
* @return the jumptable namespace
|
||||
* @throws InvalidInputException for any problems creating the namespace
|
||||
*/
|
||||
private static Namespace getSwitchNamespace(Function func, Address opAddress,
|
||||
SymbolTable symtab)
|
||||
throws InvalidInputException {
|
||||
if (!func.getBody().contains(opAddress)) {
|
||||
throw new InvalidInputException("Switch is not in function body");
|
||||
}
|
||||
Namespace space = HighFunction.findCreateOverrideSpace(func);
|
||||
if (space == null) {
|
||||
throw new InvalidInputException("Could not create \"override\" namespace");
|
||||
}
|
||||
return HighFunction.findCreateNamespace(symtab, space, "jmp_" + opAddress.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get any case format override for this jumptable.
|
||||
* @param func is the function with the jumptable
|
||||
* @param opAddress is the address of the call point using the table
|
||||
* @return the overriding format if it exists or EquateSymbol.FORMAT_DEFAULT otherwise
|
||||
*/
|
||||
public static int getFormatOverride(Function func, Address opAddress) {
|
||||
Namespace space = HighFunction.findOverrideSpace(func);
|
||||
if (space == null)
|
||||
return EquateSymbol.FORMAT_DEFAULT;
|
||||
SymbolTable symtab = func.getProgram().getSymbolTable();
|
||||
space = HighFunction.findNamespace(symtab, space, "jmp_" + opAddress.toString());
|
||||
if (space == null)
|
||||
return EquateSymbol.FORMAT_DEFAULT;
|
||||
SymbolIterator iter = symtab.getSymbols(space);
|
||||
while (iter.hasNext()) {
|
||||
Symbol sym = iter.next();
|
||||
if (sym.getName().startsWith("format")) {
|
||||
String format = sym.getName().substring(7);
|
||||
return EquateSymbol.getFormatStringValue(format);
|
||||
}
|
||||
}
|
||||
return EquateSymbol.FORMAT_DEFAULT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write/update the current display format for a JumpTable.
|
||||
* The format is stored as a symbol with a name like "format_dec" or "format_char"
|
||||
* Any previous existing symbol is removed.
|
||||
* @param func is the function containing the switch
|
||||
* @param opAddress is the address of the CALLIND
|
||||
* @param displayFormat is the new desired format
|
||||
* @throws InvalidInputException for problems writing to the database
|
||||
*/
|
||||
public static void writeFormat(Function func, Address opAddress, int displayFormat)
|
||||
throws InvalidInputException {
|
||||
Program program = func.getProgram();
|
||||
SymbolTable symtab = program.getSymbolTable();
|
||||
|
||||
Namespace space = getSwitchNamespace(func, opAddress, symtab);
|
||||
SymbolIterator iter = symtab.getSymbols(space);
|
||||
while (iter.hasNext()) {
|
||||
Symbol sym = iter.next();
|
||||
if (sym.getName().startsWith("format")) {
|
||||
HighFunction.deleteSymbol(symtab, sym.getAddress(), sym.getName(), space);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (displayFormat != EquateSymbol.FORMAT_DEFAULT) {
|
||||
String nm = "format_" + EquateSymbol.getIntegerFormatString(displayFormat);
|
||||
HighFunction.createLabelSymbol(symtab, opAddress, nm, space, SourceType.USER_DEFINED,
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
public void writeOverride(Function func) throws InvalidInputException {
|
||||
if (override == null) {
|
||||
throw new InvalidInputException("Jumptable is not an override");
|
||||
@@ -244,23 +325,14 @@ public class JumpTable {
|
||||
if (destlist.length == 0) {
|
||||
throw new InvalidInputException("Jumptable has no destinations");
|
||||
}
|
||||
if (!func.getBody().contains(opAddress)) {
|
||||
throw new InvalidInputException("Switch is not in function body");
|
||||
}
|
||||
Program program = func.getProgram();
|
||||
SymbolTable symtab = program.getSymbolTable();
|
||||
|
||||
Namespace space = HighFunction.findCreateOverrideSpace(func);
|
||||
if (space == null) {
|
||||
throw new InvalidInputException("Could not create \"override\" namespace");
|
||||
}
|
||||
space = HighFunction.findCreateNamespace(symtab, space, "jmp_" + opAddress.toString());
|
||||
|
||||
Namespace space = getSwitchNamespace(func, opAddress, symtab);
|
||||
if (!HighFunction.clearNamespace(symtab, space)) {
|
||||
throw new InvalidInputException(
|
||||
"Jumptable override namespace contains non-label symbols.");
|
||||
}
|
||||
|
||||
HighFunction.createLabelSymbol(symtab, opAddress, "switch", space, SourceType.USER_DEFINED,
|
||||
false);
|
||||
for (int i = 0; i < destlist.length; ++i) {
|
||||
@@ -268,12 +340,18 @@ public class JumpTable {
|
||||
HighFunction.createLabelSymbol(symtab, destlist[i], nm, space, SourceType.USER_DEFINED,
|
||||
false);
|
||||
}
|
||||
if (displayFormat != EquateSymbol.FORMAT_DEFAULT) {
|
||||
String nm = "format_" + EquateSymbol.getIntegerFormatString(displayFormat);
|
||||
HighFunction.createLabelSymbol(symtab, opAddress, nm, space, SourceType.USER_DEFINED,
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
public static JumpTable readOverride(Namespace space, SymbolTable symtab) {
|
||||
Address branchind = null;
|
||||
ArrayList<Address> destlist = new ArrayList<>();
|
||||
SymbolIterator iter = symtab.getSymbols(space);
|
||||
int displayFormat = 0;
|
||||
while (iter.hasNext()) {
|
||||
Symbol sym = iter.next();
|
||||
if (!(sym instanceof CodeSymbol)) {
|
||||
@@ -286,9 +364,14 @@ public class JumpTable {
|
||||
else if (sym.getName().startsWith("case")) {
|
||||
destlist.add(addr);
|
||||
}
|
||||
else if (sym.getName().startsWith("format")) {
|
||||
branchind = addr;
|
||||
displayFormat = EquateSymbol.getFormatStringValue(sym.getName().substring(7));
|
||||
}
|
||||
}
|
||||
if ((branchind != null) && (destlist.size() > 0)) {
|
||||
return new JumpTable(branchind, destlist, true);
|
||||
if ((branchind != null) && (destlist.size() > 0 || displayFormat != 0)) {
|
||||
boolean override = destlist.size() > 0;
|
||||
return new JumpTable(branchind, destlist, override, displayFormat);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user