mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-31 05:40:05 +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
|
// Allocate an override jumptable
|
||||||
JumpTable jumpTab = new JumpTable(branchind, destlist, true);
|
JumpTable jumpTab = new JumpTable(branchind, destlist, true, 0);
|
||||||
jumpTab.writeOverride(function);
|
jumpTab.writeOverride(function);
|
||||||
|
|
||||||
// fixup the body now that there are jump references
|
// 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
|
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?
|
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
|
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 block_type getType(void) const { return t_switch; }
|
||||||
virtual void markUnstructured(void);
|
virtual void markUnstructured(void);
|
||||||
virtual void scopeBreak(int4 curexit,int4 curloopexit);
|
virtual void scopeBreak(int4 curexit,int4 curloopexit);
|
||||||
|
|||||||
@@ -1059,7 +1059,7 @@ void FlowInfo::xrefInlinedBranch(PcodeOp *op)
|
|||||||
setupCallindSpecs(op,(FuncCallSpecs *)0);
|
setupCallindSpecs(op,(FuncCallSpecs *)0);
|
||||||
else if (op->code() == CPUI_BRANCHIND) {
|
else if (op->code() == CPUI_BRANCHIND) {
|
||||||
JumpTable *jt = data.linkJumpTable(op);
|
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
|
tablelist.push_back(op); // Didn't recover a jumptable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -615,7 +615,7 @@ void Funcdata::decodeJumpTable(Decoder &decoder)
|
|||||||
{
|
{
|
||||||
uint4 elemId = decoder.openElement(ELEM_JUMPTABLELIST);
|
uint4 elemId = decoder.openElement(ELEM_JUMPTABLELIST);
|
||||||
while(decoder.peekElement() != 0) {
|
while(decoder.peekElement() != 0) {
|
||||||
JumpTable *jt = new JumpTable(glb);
|
JumpTable *jt = new JumpTable();
|
||||||
jt->decode(decoder);
|
jt->decode(decoder);
|
||||||
jumpvec.push_back(jt);
|
jumpvec.push_back(jt);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -470,7 +470,7 @@ JumpTable *Funcdata::installJumpTable(const Address &addr)
|
|||||||
if (jt->getOpAddress() == addr)
|
if (jt->getOpAddress() == addr)
|
||||||
throw LowlevelError("Trying to install over existing jumptable");
|
throw LowlevelError("Trying to install over existing jumptable");
|
||||||
}
|
}
|
||||||
JumpTable *newjt = new JumpTable(glb,addr);
|
JumpTable *newjt = new JumpTable(addr);
|
||||||
jumpvec.push_back(newjt);
|
jumpvec.push_back(newjt);
|
||||||
return newjt;
|
return newjt;
|
||||||
}
|
}
|
||||||
@@ -645,10 +645,10 @@ JumpTable *Funcdata::recoverJumpTable(Funcdata &partial,PcodeOp *op,FlowInfo *fl
|
|||||||
jt = linkJumpTable(op); // Search for pre-existing jumptable
|
jt = linkJumpTable(op); // Search for pre-existing jumptable
|
||||||
if (jt != (JumpTable *)0) {
|
if (jt != (JumpTable *)0) {
|
||||||
if (!jt->isOverride()) {
|
if (!jt->isOverride()) {
|
||||||
if (!jt->isPartial())
|
if (!jt->isPartial() && jt->numEntries() != 0)
|
||||||
return jt; // Previously calculated jumptable (NOT an override and NOT incomplete)
|
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)
|
if (mode != JumpTable::success)
|
||||||
return (JumpTable *)0;
|
return (JumpTable *)0;
|
||||||
jt->setIndirectOp(op); // Relink table back to original op
|
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);
|
mode = earlyJumpTableFail(op);
|
||||||
if (mode != JumpTable::success)
|
if (mode != JumpTable::success)
|
||||||
return (JumpTable *)0;
|
return (JumpTable *)0;
|
||||||
JumpTable trialjt(glb);
|
JumpTable trialjt;
|
||||||
mode = stageJumpTable(partial,&trialjt,op,flow);
|
mode = stageJumpTable(partial,&trialjt,op,flow);
|
||||||
if (mode != JumpTable::success)
|
if (mode != JumpTable::success)
|
||||||
return (JumpTable *)0;
|
return (JumpTable *)0;
|
||||||
|
|||||||
@@ -2271,9 +2271,10 @@ void JumpTable::clearSavedModel(void)
|
|||||||
void JumpTable::recoverModel(Funcdata *fd)
|
void JumpTable::recoverModel(Funcdata *fd)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
uint4 maxTableSize = fd->getArch()->max_jumptable_size;
|
||||||
if (jmodel != (JumpModel *)0) {
|
if (jmodel != (JumpModel *)0) {
|
||||||
if (jmodel->isOverride()) { // If preexisting model is override
|
if (jmodel->isOverride()) { // If preexisting model is override
|
||||||
jmodel->recoverModel(fd,indirect,0,glb->max_jumptable_size);
|
jmodel->recoverModel(fd,indirect,0,maxTableSize);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
delete jmodel; // Otherwise this is an old attempt we should remove
|
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) {
|
if (op->code() == CPUI_CALLOTHER) {
|
||||||
JumpAssisted *jassisted = new JumpAssisted(this);
|
JumpAssisted *jassisted = new JumpAssisted(this);
|
||||||
jmodel = jassisted;
|
jmodel = jassisted;
|
||||||
if (jmodel->recoverModel(fd,indirect,addresstable.size(),glb->max_jumptable_size))
|
if (jmodel->recoverModel(fd,indirect,addresstable.size(),maxTableSize))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
JumpBasic *jbasic = new JumpBasic(this);
|
JumpBasic *jbasic = new JumpBasic(this);
|
||||||
jmodel = jbasic;
|
jmodel = jbasic;
|
||||||
if (jmodel->recoverModel(fd,indirect,addresstable.size(),glb->max_jumptable_size))
|
if (jmodel->recoverModel(fd,indirect,addresstable.size(),maxTableSize))
|
||||||
return;
|
return;
|
||||||
jmodel = new JumpBasic2(this);
|
jmodel = new JumpBasic2(this);
|
||||||
((JumpBasic2 *)jmodel)->initializeStart(jbasic->getPathMeld());
|
((JumpBasic2 *)jmodel)->initializeStart(jbasic->getPathMeld());
|
||||||
delete jbasic;
|
delete jbasic;
|
||||||
if (jmodel->recoverModel(fd,indirect,addresstable.size(),glb->max_jumptable_size))
|
if (jmodel->recoverModel(fd,indirect,addresstable.size(),maxTableSize))
|
||||||
return;
|
return;
|
||||||
delete jmodel;
|
delete jmodel;
|
||||||
jmodel = (JumpModel *)0;
|
jmodel = (JumpModel *)0;
|
||||||
@@ -2392,12 +2393,10 @@ bool JumpTable::isReachable(PcodeOp *op)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \param g is the Architecture the table exists within
|
|
||||||
/// \param ad is the Address of the BRANCHIND \b this models
|
/// \param ad is the Address of the BRANCHIND \b this models
|
||||||
JumpTable::JumpTable(Architecture *g,Address ad)
|
JumpTable::JumpTable(Address ad)
|
||||||
: opaddress(ad)
|
: opaddress(ad)
|
||||||
{
|
{
|
||||||
glb = g;
|
|
||||||
jmodel = (JumpModel *)0;
|
jmodel = (JumpModel *)0;
|
||||||
origmodel = (JumpModel *)0;
|
origmodel = (JumpModel *)0;
|
||||||
indirect = (PcodeOp *)0;
|
indirect = (PcodeOp *)0;
|
||||||
@@ -2407,6 +2406,7 @@ JumpTable::JumpTable(Architecture *g,Address ad)
|
|||||||
maxaddsub = 1;
|
maxaddsub = 1;
|
||||||
maxleftright = 1;
|
maxleftright = 1;
|
||||||
maxext = 1;
|
maxext = 1;
|
||||||
|
displayFormat = 0;
|
||||||
partialTable = false;
|
partialTable = false;
|
||||||
collectloads = false;
|
collectloads = false;
|
||||||
defaultIsFolded = false;
|
defaultIsFolded = false;
|
||||||
@@ -2418,7 +2418,6 @@ JumpTable::JumpTable(Architecture *g,Address ad)
|
|||||||
JumpTable::JumpTable(const JumpTable *op2)
|
JumpTable::JumpTable(const JumpTable *op2)
|
||||||
|
|
||||||
{
|
{
|
||||||
glb = op2->glb;
|
|
||||||
jmodel = (JumpModel *)0;
|
jmodel = (JumpModel *)0;
|
||||||
origmodel = (JumpModel *)0;
|
origmodel = (JumpModel *)0;
|
||||||
indirect = (PcodeOp *)0;
|
indirect = (PcodeOp *)0;
|
||||||
@@ -2428,6 +2427,7 @@ JumpTable::JumpTable(const JumpTable *op2)
|
|||||||
maxaddsub = op2->maxaddsub;
|
maxaddsub = op2->maxaddsub;
|
||||||
maxleftright = op2->maxleftright;
|
maxleftright = op2->maxleftright;
|
||||||
maxext = op2->maxext;
|
maxext = op2->maxext;
|
||||||
|
displayFormat = op2->displayFormat;
|
||||||
partialTable = op2->partialTable;
|
partialTable = op2->partialTable;
|
||||||
collectloads = op2->collectloads;
|
collectloads = op2->collectloads;
|
||||||
defaultIsFolded = false;
|
defaultIsFolded = false;
|
||||||
@@ -2743,7 +2743,7 @@ void JumpTable::recoverLabels(Funcdata *fd)
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
jmodel = new JumpModelTrivial(this);
|
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);
|
jmodel->buildAddresses(fd,indirect,addresstable,(vector<LoadTable> *)0,(vector<int4> *)0);
|
||||||
trivialSwitchOver();
|
trivialSwitchOver();
|
||||||
jmodel->buildLabels(fd,addresstable,label,origmodel);
|
jmodel->buildLabels(fd,addresstable,label,origmodel);
|
||||||
@@ -2785,6 +2785,8 @@ void JumpTable::encode(Encoder &encoder) const
|
|||||||
throw LowlevelError("Trying to save unrecovered jumptable");
|
throw LowlevelError("Trying to save unrecovered jumptable");
|
||||||
|
|
||||||
encoder.openElement(ELEM_JUMPTABLE);
|
encoder.openElement(ELEM_JUMPTABLE);
|
||||||
|
if (displayFormat != 0)
|
||||||
|
encoder.writeUnsignedInteger(ATTRIB_FORMAT, displayFormat);
|
||||||
opaddress.encode(encoder);
|
opaddress.encode(encoder);
|
||||||
for(int4 i=0;i<addresstable.size();++i) {
|
for(int4 i=0;i<addresstable.size();++i) {
|
||||||
encoder.openElement(ELEM_DEST);
|
encoder.openElement(ELEM_DEST);
|
||||||
@@ -2814,6 +2816,8 @@ void JumpTable::decode(Decoder &decoder)
|
|||||||
|
|
||||||
{
|
{
|
||||||
uint4 elemId = decoder.openElement(ELEM_JUMPTABLE);
|
uint4 elemId = decoder.openElement(ELEM_JUMPTABLE);
|
||||||
|
if (decoder.getNextAttributeId() == ATTRIB_FORMAT)
|
||||||
|
displayFormat = decoder.readUnsignedInteger();
|
||||||
opaddress = Address::decode( decoder );
|
opaddress = Address::decode( decoder );
|
||||||
bool missedlabel = false;
|
bool missedlabel = false;
|
||||||
for(;;) {
|
for(;;) {
|
||||||
|
|||||||
@@ -557,7 +557,6 @@ private:
|
|||||||
bool operator<(const IndexPair &op2) const; ///< Compare by position then by index
|
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
|
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 *jmodel; ///< Current model of how the jump table is implemented in code
|
||||||
JumpModel *origmodel; ///< Initial jump table model, which may be incomplete
|
JumpModel *origmodel; ///< Initial jump table model, which may be incomplete
|
||||||
vector<Address> addresstable; ///< Raw addresses in the jump-table
|
vector<Address> addresstable; ///< Raw addresses in the jump-table
|
||||||
@@ -572,6 +571,7 @@ private:
|
|||||||
uint4 maxaddsub; ///< Maximum ADDs or SUBs to normalize
|
uint4 maxaddsub; ///< Maximum ADDs or SUBs to normalize
|
||||||
uint4 maxleftright; ///< Maximum shifts to normalize
|
uint4 maxleftright; ///< Maximum shifts to normalize
|
||||||
uint4 maxext; ///< Maximum extensions 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 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 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)
|
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.
|
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
|
static bool isReachable(PcodeOp *op); ///< Check if the given PcodeOp still seems reachable in its function
|
||||||
public:
|
public:
|
||||||
JumpTable(Architecture *g,Address ad=Address()); ///< Constructor
|
JumpTable(Address ad=Address()); ///< Constructor
|
||||||
JumpTable(const JumpTable *op2); ///< Copy constructor
|
JumpTable(const JumpTable *op2); ///< Copy constructor
|
||||||
~JumpTable(void); ///< Destructor
|
~JumpTable(void); ///< Destructor
|
||||||
bool isRecovered(void) const { return !addresstable.empty(); } ///< Return \b true if a model has been recovered
|
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 setIndirectOp(PcodeOp *ind) { opaddress = ind->getAddr(); indirect = ind; } ///< Set the BRANCHIND PcodeOp
|
||||||
void setNormMax(uint4 maddsub,uint4 mleftright,uint4 mext) {
|
void setNormMax(uint4 maddsub,uint4 mleftright,uint4 mext) {
|
||||||
maxaddsub = maddsub; maxleftright = mleftright; maxext = mext; } ///< Set the switch variable normalization model restrictions
|
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);
|
void setOverride(const vector<Address> &addrtable,const Address &naddr,uintb h,uintb sv);
|
||||||
int4 numIndicesByBlock(const FlowBlock *bl) const;
|
int4 numIndicesByBlock(const FlowBlock *bl) const;
|
||||||
int4 getIndexByBlock(const FlowBlock *bl,int4 i) 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;
|
const TypeArray *ctarray = (const TypeArray *)ct;
|
||||||
ct = ctarray->getBase();
|
ct = ctarray->getBase();
|
||||||
push_integer(ctarray->numElements(),4,false,syntax,
|
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) {
|
else if (ct->getMetatype()==TYPE_CODE) {
|
||||||
const TypeCode *ctcode = (const TypeCode *)ct;
|
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));
|
pushAtom(Atom(fieldname,fieldtoken,EmitMarkup::no_color,ct,fieldid,op));
|
||||||
}
|
}
|
||||||
if (arrayvalue)
|
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) {
|
else if (ct->getMetatype() == TYPE_SPACEBASE) {
|
||||||
@@ -1093,7 +1093,7 @@ void PrintC::opPtrsub(const PcodeOp *op)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (arrayvalue)
|
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) {
|
else if (ct->getMetatype() == TYPE_ARRAY) {
|
||||||
if (in1const != 0) {
|
if (in1const != 0) {
|
||||||
@@ -1124,7 +1124,7 @@ void PrintC::opPtrsub(const PcodeOp *op)
|
|||||||
if (ptrel != (TypePointerRel *)0)
|
if (ptrel != (TypePointerRel *)0)
|
||||||
pushTypePointerRel(op);
|
pushTypePointerRel(op);
|
||||||
pushVn(in0,op,m | print_load_value); // Absorb one dereference into in0's defining 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]
|
else { // EMIT (* )[0]
|
||||||
pushOp(&subscript,op);
|
pushOp(&subscript,op);
|
||||||
@@ -1132,7 +1132,7 @@ void PrintC::opPtrsub(const PcodeOp *op)
|
|||||||
if (ptrel != (TypePointerRel *)0)
|
if (ptrel != (TypePointerRel *)0)
|
||||||
pushTypePointerRel(op);
|
pushTypePointerRel(op);
|
||||||
pushVn(in0,op,m);
|
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 tag is the type of token to associate with the integer
|
||||||
/// \param vn is the Varnode holding the value
|
/// \param vn is the Varnode holding the value
|
||||||
/// \param op is the PcodeOp using 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,
|
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 print_negsign;
|
||||||
bool force_unsigned_token;
|
bool force_unsigned_token;
|
||||||
bool force_sized_token;
|
bool force_sized_token;
|
||||||
uint4 displayFormat = 0;
|
|
||||||
|
|
||||||
force_unsigned_token = false;
|
force_unsigned_token = false;
|
||||||
force_sized_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_unsigned_token = vn->isUnsignedPrint();
|
||||||
force_sized_token = vn->isLongPrint();
|
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
|
if (sign && displayFormat != Symbol::force_char) { // Print the constant as signed
|
||||||
uintb mask = calc_mask(sz);
|
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
|
// Figure whether to print as hex or decimal
|
||||||
if (displayFormat != 0) {
|
if (displayFormat != 0) {
|
||||||
// Format is forced by the Symbol
|
// Format is forced by the Symbol or data-type
|
||||||
}
|
}
|
||||||
else if ((mods & force_hex)!=0) {
|
else if ((mods & force_hex)!=0) {
|
||||||
displayFormat = Symbol::force_hex;
|
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 (displayFormat != 0 && displayFormat != Symbol::force_char) {
|
||||||
if (!castStrategy->caresAboutCharRepresentation(vn, op)) {
|
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;
|
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
|
// 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.
|
// code-page value. In either case, we print as an integer or an escape sequence.
|
||||||
if (displayFormat != Symbol::force_hex && displayFormat != Symbol::force_char) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
displayFormat = Symbol::force_hex; // Fallthru but force a hex representation
|
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)
|
for(int4 i=0;i<rep.matchname.size();++i)
|
||||||
pushAtom(Atom(rep.matchname[i],tag,EmitMarkup::const_color,op,vn,val));
|
pushAtom(Atom(rep.matchname[i],tag,EmitMarkup::const_color,op,vn,val));
|
||||||
if (rep.shiftAmount != 0)
|
if (rep.shiftAmount != 0)
|
||||||
push_integer(rep.shiftAmount,4,false,tag,vn,op);
|
push_integer(rep.shiftAmount,4,false,tag,vn,op,0);
|
||||||
}
|
}
|
||||||
else {
|
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,
|
void PrintC::pushConstant(uintb val,const Datatype *ct,tagtype tag,
|
||||||
const Varnode *vn,
|
const Varnode *vn,const PcodeOp *op,uint4 displayFormat)
|
||||||
const PcodeOp *op)
|
|
||||||
{
|
{
|
||||||
Datatype *subtype;
|
Datatype *subtype;
|
||||||
switch(ct->getMetatype()) {
|
switch(ct->getMetatype()) {
|
||||||
@@ -1753,7 +1750,7 @@ void PrintC::pushConstant(uintb val,const Datatype *ct,tagtype tag,
|
|||||||
else if (ct->isEnumType())
|
else if (ct->isEnumType())
|
||||||
pushEnumConstant(val,(TypeEnum *)ct,tag,vn,op);
|
pushEnumConstant(val,(TypeEnum *)ct,tag,vn,op);
|
||||||
else
|
else
|
||||||
push_integer(val,ct->getSize(),false,tag,vn,op);
|
push_integer(val,ct->getSize(),false,tag,vn,op,displayFormat);
|
||||||
return;
|
return;
|
||||||
case TYPE_INT:
|
case TYPE_INT:
|
||||||
if (ct->isCharPrint())
|
if (ct->isCharPrint())
|
||||||
@@ -1761,10 +1758,10 @@ void PrintC::pushConstant(uintb val,const Datatype *ct,tagtype tag,
|
|||||||
else if (ct->isEnumType())
|
else if (ct->isEnumType())
|
||||||
pushEnumConstant(val,(TypeEnum *)ct,tag,vn,op);
|
pushEnumConstant(val,(TypeEnum *)ct,tag,vn,op);
|
||||||
else
|
else
|
||||||
push_integer(val,ct->getSize(),true,tag,vn,op);
|
push_integer(val,ct->getSize(),true,tag,vn,op,displayFormat);
|
||||||
return;
|
return;
|
||||||
case TYPE_UNKNOWN:
|
case TYPE_UNKNOWN:
|
||||||
push_integer(val,ct->getSize(),false,tag,vn,op);
|
push_integer(val,ct->getSize(),false,tag,vn,op,displayFormat);
|
||||||
return;
|
return;
|
||||||
case TYPE_BOOL:
|
case TYPE_BOOL:
|
||||||
pushBoolConstant(val,(const TypeBase *)ct,tag,vn,op);
|
pushBoolConstant(val,(const TypeBase *)ct,tag,vn,op);
|
||||||
@@ -1811,7 +1808,7 @@ void PrintC::pushConstant(uintb val,const Datatype *ct,tagtype tag,
|
|||||||
pushMod();
|
pushMod();
|
||||||
if (!isSet(force_dec))
|
if (!isSet(force_dec))
|
||||||
setMod(force_hex);
|
setMod(force_hex);
|
||||||
push_integer(val,ct->getSize(),false,tag,vn,op);
|
push_integer(val,ct->getSize(),false,tag,vn,op,displayFormat);
|
||||||
popMod();
|
popMod();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1845,14 +1842,14 @@ bool PrintC::pushEquate(uintb val,int4 sz,const EquateSymbol *sym,const Varnode
|
|||||||
if (modval == val) {
|
if (modval == val) {
|
||||||
pushOp(&binary_plus,(const PcodeOp *)0);
|
pushOp(&binary_plus,(const PcodeOp *)0);
|
||||||
pushSymbol(sym,vn,op);
|
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 true;
|
||||||
}
|
}
|
||||||
modval = (baseval - 1) & mask;
|
modval = (baseval - 1) & mask;
|
||||||
if (modval == val) {
|
if (modval == val) {
|
||||||
pushOp(&binary_minus,(const PcodeOp *)0);
|
pushOp(&binary_minus,(const PcodeOp *)0);
|
||||||
pushSymbol(sym,vn,op);
|
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 true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -2053,7 +2050,7 @@ void PrintC::pushPartialSymbol(const Symbol *sym,int4 off,int4 sz,
|
|||||||
PartialSymbolEntry &entry (stack[i]);
|
PartialSymbolEntry &entry (stack[i]);
|
||||||
if (entry.field == (const TypeField *)0) {
|
if (entry.field == (const TypeField *)0) {
|
||||||
if (entry.size <= 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 {
|
else {
|
||||||
string field = unnamedField(entry.offset,entry.size);
|
string field = unnamedField(entry.offset,entry.size);
|
||||||
pushAtom(Atom(field,syntax,entry.hilite,op));
|
pushAtom(Atom(field,syntax,entry.hilite,op));
|
||||||
@@ -2172,7 +2169,7 @@ void PrintC::emitEnumDefinition(const TypeEnum *ct)
|
|||||||
emit->spaces(1);
|
emit->spaces(1);
|
||||||
emit->print(EQUALSIGN,EmitMarkup::no_color);
|
emit->print(EQUALSIGN,EmitMarkup::no_color);
|
||||||
emit->spaces(1);
|
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();
|
recurse();
|
||||||
emit->print(SEMICOLON);
|
emit->print(SEMICOLON);
|
||||||
++iter;
|
++iter;
|
||||||
@@ -3145,12 +3142,15 @@ void PrintC::emitSwitchCase(int4 casenum,const BlockSwitch *switchbl)
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
num = switchbl->getNumLabels(casenum);
|
num = switchbl->getNumLabels(casenum);
|
||||||
|
uint4 displayFormat = switchbl->getDisplayFormat();
|
||||||
|
if (displayFormat == 0)
|
||||||
|
displayFormat = ct->getDisplayFormat();
|
||||||
for(i=0;i<num;++i) {
|
for(i=0;i<num;++i) {
|
||||||
val = switchbl->getLabel(casenum,i);
|
val = switchbl->getLabel(casenum,i);
|
||||||
emit->tagLine();
|
emit->tagLine();
|
||||||
emit->print(KEYWORD_CASE,EmitMarkup::keyword_color);
|
emit->print(KEYWORD_CASE,EmitMarkup::keyword_color);
|
||||||
emit->spaces(1);
|
emit->spaces(1);
|
||||||
pushConstant(val,ct,casetoken,(Varnode *)0,op);
|
pushConstant(val,ct,casetoken,(Varnode *)0,op,displayFormat);
|
||||||
recurse();
|
recurse();
|
||||||
emit->print(COLON);
|
emit->print(COLON);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ protected:
|
|||||||
int4 getHiddenThisSlot(const PcodeOp *op,FuncProto *fc); ///< Get position of "this" pointer needing to be hidden
|
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
|
void resetDefaultsPrintC(void); ///< Set default values for options specific to PrintC
|
||||||
virtual void pushConstant(uintb val,const Datatype *ct,tagtype tag,
|
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,
|
virtual bool pushEquate(uintb val,int4 sz,const EquateSymbol *sym,
|
||||||
const Varnode *vn,const PcodeOp *op);
|
const Varnode *vn,const PcodeOp *op);
|
||||||
virtual void pushAnnotation(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);
|
const Varnode *vn,const PcodeOp *op);
|
||||||
virtual void pushImpliedField(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,
|
virtual void push_integer(uintb val,int4 sz,bool sign,tagtype tag,
|
||||||
const Varnode *vn,
|
const Varnode *vn,const PcodeOp *op,uint4 displayFormat);
|
||||||
const PcodeOp *op);
|
|
||||||
virtual void push_float(uintb val,int4 sz,tagtype tag,const Varnode *vn,
|
virtual void push_float(uintb val,int4 sz,tagtype tag,const Varnode *vn,
|
||||||
const PcodeOp *op);
|
const PcodeOp *op);
|
||||||
virtual void printUnicode(ostream &s,int4 onechar) const;
|
virtual void printUnicode(ostream &s,int4 onechar) const;
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -234,7 +234,7 @@ void PrintJava::opLoad(const PcodeOp *op)
|
|||||||
pushOp(&subscript,op);
|
pushOp(&subscript,op);
|
||||||
pushVn(op->getIn(1),op,m);
|
pushVn(op->getIn(1),op,m);
|
||||||
if (printArrayRef)
|
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)
|
void PrintJava::opStore(const PcodeOp *op)
|
||||||
@@ -245,7 +245,7 @@ void PrintJava::opStore(const PcodeOp *op)
|
|||||||
if (needZeroArray(op->getIn(1))) {
|
if (needZeroArray(op->getIn(1))) {
|
||||||
pushOp(&subscript,op);
|
pushOp(&subscript,op);
|
||||||
pushVn(op->getIn(1),op,m);
|
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);
|
pushVn(op->getIn(2),op,mods);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -223,7 +223,8 @@ void PrintLanguage::pushVnExplicit(const Varnode *vn,const PcodeOp *op)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (vn->isConstant()) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
pushSymbolDetail(vn,op,true);
|
pushSymbolDetail(vn,op,true);
|
||||||
|
|||||||
@@ -324,10 +324,11 @@ protected:
|
|||||||
/// \param val is the value of the constant
|
/// \param val is the value of the constant
|
||||||
/// \param ct is the data-type of the constant
|
/// \param ct is the data-type of the constant
|
||||||
/// \param tag is the type of token associated with the constant
|
/// \param tag is the type of token associated with the constant
|
||||||
/// \param vn is the Varnode holding the constant (optional)
|
/// \param vn is the Varnode holding the constant (may be null)
|
||||||
/// \param op is the PcodeOp using the constant (optional)
|
/// \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,
|
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
|
/// \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 val is the value of the constant
|
||||||
/// \param sz is the number of bytes to use for the encoding
|
/// \param sz is the number of bytes to use for the encoding
|
||||||
/// \param sym is the EquateSymbol that marks up the constant
|
/// \param sym is the EquateSymbol that marks up the constant
|
||||||
/// \param vn is the Varnode holding the constant (optional)
|
/// \param vn is the Varnode holding the constant (may be null)
|
||||||
/// \param op is the PcodeOp using the constant (optional)
|
/// \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;
|
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.
|
/// \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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -36,6 +36,13 @@ public class ClangCaseToken extends ClangToken {
|
|||||||
value = 0;
|
value = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the constant value associated with this label
|
||||||
|
*/
|
||||||
|
public long getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isVariableRef() {
|
public boolean isVariableRef() {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
+7
-8
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -41,11 +41,10 @@ public class ConvertBinaryAction extends ConvertConstantAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getMenuDisplay(long value, int size, boolean isSigned, Program program) {
|
public String getMenuDisplay(Scalar scalar, Program program) {
|
||||||
Scalar scalar = new Scalar(size * 8, value);
|
|
||||||
long v;
|
long v;
|
||||||
String prefix = "0b";
|
String prefix = "0b";
|
||||||
if (isSigned) {
|
if (scalar.isSigned()) {
|
||||||
v = scalar.getSignedValue();
|
v = scalar.getSignedValue();
|
||||||
if (v < 0) {
|
if (v < 0) {
|
||||||
v = -v;
|
v = -v;
|
||||||
@@ -74,9 +73,9 @@ public class ConvertBinaryAction extends ConvertConstantAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getEquateName(long value, int size, boolean isSigned, Program program) {
|
public String getEquateName(Scalar scalar, Program program) {
|
||||||
String valueStr = Long.toBinaryString(value);
|
String valueStr = Long.toBinaryString(scalar.getValue());
|
||||||
valueStr = StringUtilities.pad(valueStr, '0', size * 8);
|
valueStr = StringUtilities.pad(valueStr, '0', scalar.bitLength());
|
||||||
return valueStr + "b";
|
return valueStr + "b";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-11
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* 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.data.StringDataInstance;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.pcode.EquateSymbol;
|
import ghidra.program.model.pcode.EquateSymbol;
|
||||||
|
import ghidra.program.model.scalar.Scalar;
|
||||||
import ghidra.util.BigEndianDataConverter;
|
import ghidra.util.BigEndianDataConverter;
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
|
|
||||||
@@ -63,9 +64,9 @@ public class ConvertCharAction extends ConvertConstantAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getEquateName(long value, int size, boolean isSigned, Program program) {
|
public String getEquateName(Scalar scalar, Program program) {
|
||||||
byte[] bytes = new byte[size];
|
byte[] bytes = new byte[scalar.bitLength() / 8];
|
||||||
BigEndianDataConverter.INSTANCE.putValue(value, size, bytes, 0);
|
BigEndianDataConverter.INSTANCE.putValue(scalar.getValue(), bytes.length, bytes, 0);
|
||||||
return StringDataInstance.getCharRepresentation(ByteDataType.dataType, bytes, null);
|
return StringDataInstance.getCharRepresentation(ByteDataType.dataType, bytes, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,13 +99,14 @@ public class ConvertCharAction extends ConvertConstantAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getMenuDisplay(long value, int size, boolean isSigned, Program program) {
|
public String getMenuDisplay(Scalar scalar, Program program) {
|
||||||
StringBuilder buffer = new StringBuilder();
|
StringBuilder buffer = new StringBuilder();
|
||||||
if (size > 1) {
|
if (scalar.bitLength() > 8) {
|
||||||
buffer.append('L');
|
buffer.append('L');
|
||||||
}
|
}
|
||||||
if ((size == 1 && value >= 0x7f) || codePointNeedsEscape((int) value)) {
|
if ((scalar.bitLength() == 8 && scalar.getUnsignedValue() >= 0x7f) ||
|
||||||
switch ((int) value) {
|
codePointNeedsEscape((int) scalar.getUnsignedValue())) {
|
||||||
|
switch ((int) scalar.getValue()) {
|
||||||
case 0:
|
case 0:
|
||||||
buffer.append("'\\0'");
|
buffer.append("'\\0'");
|
||||||
break;
|
break;
|
||||||
@@ -140,12 +142,12 @@ public class ConvertCharAction extends ConvertConstantAction {
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// Generic unicode escape
|
// Generic unicode escape
|
||||||
generateHexEscape(buffer, (int) value);
|
generateHexEscape(buffer, (int) scalar.getUnsignedValue());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
buffer.append('\'').append((char) value).append('\'');
|
buffer.append('\'').append((char) scalar.getUnsignedValue()).append('\'');
|
||||||
}
|
}
|
||||||
return buffer.toString();
|
return buffer.toString();
|
||||||
}
|
}
|
||||||
|
|||||||
+107
-263
@@ -17,27 +17,21 @@ package ghidra.app.plugin.core.decompile.actions;
|
|||||||
|
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
import java.awt.FontMetrics;
|
import java.awt.FontMetrics;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.swing.JMenuItem;
|
import javax.swing.JMenuItem;
|
||||||
|
|
||||||
|
import ghidra.app.decompiler.ClangCaseToken;
|
||||||
import ghidra.app.decompiler.ClangToken;
|
import ghidra.app.decompiler.ClangToken;
|
||||||
import ghidra.app.decompiler.ClangVariableToken;
|
|
||||||
import ghidra.app.plugin.core.decompile.DecompilePlugin;
|
import ghidra.app.plugin.core.decompile.DecompilePlugin;
|
||||||
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
|
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.*;
|
||||||
import ghidra.program.model.data.Enum;
|
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.listing.Program;
|
||||||
import ghidra.program.model.pcode.*;
|
import ghidra.program.model.pcode.*;
|
||||||
import ghidra.program.model.scalar.Scalar;
|
import ghidra.program.model.scalar.Scalar;
|
||||||
import ghidra.program.model.symbol.*;
|
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.InvalidInputException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract pop-up menu convert action for the decompiler. If triggered, it lays down
|
* 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 {
|
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;
|
protected DecompilePlugin plugin;
|
||||||
private FontMetrics metrics = null;
|
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 {
|
public static class NearMatchValues {
|
||||||
Address refAddr; // Address of instruction
|
private long[] values;
|
||||||
Scalar scalar;
|
private long mask;
|
||||||
int opIndex;
|
|
||||||
|
|
||||||
public ScalarMatch(Address addr, Scalar value, int index) {
|
public NearMatchValues(long value, int size) {
|
||||||
refAddr = addr;
|
mask = -1;
|
||||||
scalar = value;
|
if (size < 8) {
|
||||||
opIndex = index;
|
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();
|
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
|
@Override
|
||||||
protected boolean isEnabledForDecompilerContext(DecompilerActionContext context) {
|
protected boolean isEnabledForDecompilerContext(DecompilerActionContext context) {
|
||||||
ConvertConstantTask task = establishTask(context, false);
|
Scalar scalar;
|
||||||
if (task == null) {
|
scalar = getCaseConstant(context, convertType);
|
||||||
|
if (scalar == null) {
|
||||||
|
scalar = ConvertConstantEquateTask.getConvertibleConstant(context, convertType);
|
||||||
|
}
|
||||||
|
if (scalar == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
String convDisplay =
|
String convDisplay = getMenuDisplay(scalar, context.getProgram());
|
||||||
getMenuDisplay(task.getValue(), task.getSize(), task.isSigned(), context.getProgram());
|
|
||||||
if (convDisplay == null) {
|
if (convDisplay == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -352,13 +141,72 @@ public abstract class ConvertConstantAction extends AbstractDecompilerAction {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void decompilerActionPerformed(DecompilerActionContext context) {
|
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) {
|
if (task == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
task.runTask();
|
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:
|
* The menu option for this kind of action is intended to look like:
|
||||||
* {@literal Hexadecimal: 0x2408}
|
* {@literal Hexadecimal: 0x2408}
|
||||||
@@ -372,22 +220,18 @@ public abstract class ConvertConstantAction extends AbstractDecompilerAction {
|
|||||||
* {@literal Hexadecimal: 0x2408}
|
* {@literal Hexadecimal: 0x2408}
|
||||||
* This method constructs the final part of this string, after the colon by
|
* This method constructs the final part of this string, after the colon by
|
||||||
* formatting the actual value that is to be converted.
|
* formatting the actual value that is to be converted.
|
||||||
* @param value is the actual value
|
* @param scalar is the constant 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 program the program
|
* @param program the program
|
||||||
* @return the formatted String
|
* @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
|
* Construct the name of the Equate, either absolutely for a conversion or
|
||||||
* by preventing the user with a dialog to select a name.
|
* by preventing the user with a dialog to select a name.
|
||||||
* @param value is the value being converted
|
* @param scalar is the constant 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 program is the current Program
|
* @param program is the current Program
|
||||||
* @return the equate name
|
* @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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -39,14 +39,13 @@ public class ConvertDecAction extends ConvertConstantAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getMenuDisplay(long value, int size, boolean isSigned, Program program) {
|
public String getMenuDisplay(Scalar scalar, Program program) {
|
||||||
return getEquateName(value, size, isSigned, program);
|
return getEquateName(scalar, program);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getEquateName(long value, int size, boolean isSigned, Program program) {
|
public String getEquateName(Scalar scalar, Program program) {
|
||||||
Scalar scalar = new Scalar(size * 8, value);
|
if (scalar.isSigned()) {
|
||||||
if (isSigned) {
|
|
||||||
return Long.toString(scalar.getSignedValue());
|
return Long.toString(scalar.getSignedValue());
|
||||||
}
|
}
|
||||||
return Long.toString(scalar.getUnsignedValue());
|
return Long.toString(scalar.getUnsignedValue());
|
||||||
|
|||||||
+7
-8
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -41,19 +41,18 @@ public class ConvertDoubleAction extends ConvertConstantAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getMenuDisplay(long value, int size, boolean isSigned, Program program) {
|
public String getMenuDisplay(Scalar scalar, Program program) {
|
||||||
return getText(value, size, isSigned, program);
|
return getText(scalar, program);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getEquateName(long value, int size, boolean isSigned, Program program) {
|
public String getEquateName(Scalar scalar, Program program) {
|
||||||
return getText(value, size, isSigned, 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();
|
DataOrganization organization = program.getDataTypeManager().getDataOrganization();
|
||||||
int doubleSize = organization.getDoubleSize();
|
int doubleSize = organization.getDoubleSize();
|
||||||
Scalar scalar = new Scalar(size * 8, value);
|
|
||||||
BigDecimal bd = value(doubleSize, scalar);
|
BigDecimal bd = value(doubleSize, scalar);
|
||||||
if (bd != null) {
|
if (bd != null) {
|
||||||
return bd.toString();
|
return bd.toString();
|
||||||
|
|||||||
+7
-8
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -41,19 +41,18 @@ public class ConvertFloatAction extends ConvertConstantAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getMenuDisplay(long value, int size, boolean isSigned, Program program) {
|
public String getMenuDisplay(Scalar scalar, Program program) {
|
||||||
return getText(value, size, isSigned, program);
|
return getText(scalar, program);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getEquateName(long value, int size, boolean isSigned, Program program) {
|
public String getEquateName(Scalar scalar, Program program) {
|
||||||
return getText(value, size, isSigned, 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();
|
DataOrganization organization = program.getDataTypeManager().getDataOrganization();
|
||||||
int floatSize = organization.getFloatSize();
|
int floatSize = organization.getFloatSize();
|
||||||
Scalar scalar = new Scalar(size * 8, value);
|
|
||||||
BigDecimal bd = value(floatSize, scalar);
|
BigDecimal bd = value(floatSize, scalar);
|
||||||
if (bd != null) {
|
if (bd != null) {
|
||||||
return bd.toString();
|
return bd.toString();
|
||||||
|
|||||||
+6
-8
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -40,9 +40,8 @@ public class ConvertHexAction extends ConvertConstantAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getMenuDisplay(long value, int size, boolean isSigned, Program program) {
|
public String getMenuDisplay(Scalar scalar, Program program) {
|
||||||
Scalar scalar = new Scalar(size * 8, value);
|
if (scalar.isSigned()) {
|
||||||
if (isSigned) {
|
|
||||||
long v = scalar.getSignedValue();
|
long v = scalar.getSignedValue();
|
||||||
String valueStr = Long.toString(v, 16);
|
String valueStr = Long.toString(v, 16);
|
||||||
if (v < 0) {
|
if (v < 0) {
|
||||||
@@ -56,9 +55,8 @@ public class ConvertHexAction extends ConvertConstantAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getEquateName(long value, int size, boolean isSigned, Program program) {
|
public String getEquateName(Scalar scalar, Program program) {
|
||||||
Scalar scalar = new Scalar(size * 8, value);
|
if (scalar.isSigned()) {
|
||||||
if (isSigned) {
|
|
||||||
long v = scalar.getSignedValue();
|
long v = scalar.getSignedValue();
|
||||||
String valueStr = Long.toString(v, 16).toUpperCase();
|
String valueStr = Long.toString(v, 16).toUpperCase();
|
||||||
if (v < 0) {
|
if (v < 0) {
|
||||||
|
|||||||
+5
-7
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -40,9 +40,8 @@ public class ConvertOctAction extends ConvertConstantAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getMenuDisplay(long value, int size, boolean isSigned, Program program) {
|
public String getMenuDisplay(Scalar scalar, Program program) {
|
||||||
Scalar scalar = new Scalar(size * 8, value);
|
if (scalar.isSigned()) {
|
||||||
if (isSigned) {
|
|
||||||
long v = scalar.getSignedValue();
|
long v = scalar.getSignedValue();
|
||||||
String valueStr = Long.toString(v, 8);
|
String valueStr = Long.toString(v, 8);
|
||||||
if (v < 0) {
|
if (v < 0) {
|
||||||
@@ -56,8 +55,7 @@ public class ConvertOctAction extends ConvertConstantAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getEquateName(long value, int size, boolean isSigned, Program program) {
|
public String getEquateName(Scalar scalar, Program program) {
|
||||||
Scalar scalar = new Scalar(size * 8, value);
|
|
||||||
return Long.toOctalString(scalar.getUnsignedValue()) + "o";
|
return Long.toOctalString(scalar.getUnsignedValue()) + "o";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+58
-8
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* 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 java.util.List;
|
||||||
|
|
||||||
import docking.action.MenuData;
|
import docking.action.MenuData;
|
||||||
import ghidra.app.decompiler.ClangToken;
|
import ghidra.app.decompiler.*;
|
||||||
import ghidra.app.decompiler.ClangVariableToken;
|
|
||||||
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
|
import ghidra.app.plugin.core.decompile.DecompilerActionContext;
|
||||||
|
import ghidra.app.plugin.core.decompile.actions.ConvertConstantAction.NearMatchValues;
|
||||||
import ghidra.app.util.HelpTopics;
|
import ghidra.app.util.HelpTopics;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.listing.Program;
|
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.Equate;
|
||||||
import ghidra.program.model.symbol.EquateTable;
|
import ghidra.program.model.symbol.EquateTable;
|
||||||
import ghidra.util.HelpLocation;
|
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 class RemoveEquateAction extends AbstractDecompilerAction {
|
||||||
|
|
||||||
public RemoveEquateAction() {
|
public RemoveEquateAction() {
|
||||||
@@ -40,6 +45,17 @@ public class RemoveEquateAction extends AbstractDecompilerAction {
|
|||||||
@Override
|
@Override
|
||||||
protected boolean isEnabledForDecompilerContext(DecompilerActionContext context) {
|
protected boolean isEnabledForDecompilerContext(DecompilerActionContext context) {
|
||||||
ClangToken tokenAtCursor = context.getTokenAtCursor();
|
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)) {
|
if (!(tokenAtCursor instanceof ClangVariableToken)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -51,6 +67,13 @@ public class RemoveEquateAction extends AbstractDecompilerAction {
|
|||||||
return (symbol instanceof EquateSymbol);
|
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,
|
private void removeReference(Program program, Equate equate, Address refAddr,
|
||||||
long convertHash) {
|
long convertHash) {
|
||||||
int transaction = program.startTransaction("Remove Equate Reference");
|
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
|
@Override
|
||||||
protected void decompilerActionPerformed(DecompilerActionContext context) {
|
protected void decompilerActionPerformed(DecompilerActionContext context) {
|
||||||
ClangToken tokenAtCursor = context.getTokenAtCursor();
|
ClangToken tokenAtCursor = context.getTokenAtCursor();
|
||||||
|
if (tokenAtCursor instanceof ClangCaseToken) {
|
||||||
|
PcodeOp switchOp = ((ClangCaseToken) tokenAtCursor).getSwitchOp();
|
||||||
|
removeCaseOverride(context, switchOp.getSeqnum().getTarget());
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!(tokenAtCursor instanceof ClangVariableToken)) {
|
if (!(tokenAtCursor instanceof ClangVariableToken)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -91,12 +140,13 @@ public class RemoveEquateAction extends AbstractDecompilerAction {
|
|||||||
Program program = context.getProgram();
|
Program program = context.getProgram();
|
||||||
EquateTable equateTable = program.getEquateTable();
|
EquateTable equateTable = program.getEquateTable();
|
||||||
List<Equate> equates = equateTable.getEquates(convertAddr);
|
List<Equate> equates = equateTable.getEquates(convertAddr);
|
||||||
|
NearMatchValues values =
|
||||||
|
new NearMatchValues(convertVn.getOffset(), convertVn.getSize());
|
||||||
for (Equate equate : equates) {
|
for (Equate equate : equates) {
|
||||||
if (equate.getValue() != convertVn.getOffset()) {
|
if (values.isMatch(equate.getValue())) {
|
||||||
continue;
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -43,16 +43,15 @@ public class SetEquateAction extends ConvertConstantAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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
|
return null; // Menu isn't tailored for this action
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getEquateName(long value, int size, boolean isSigned, Program program) {
|
public String getEquateName(Scalar scalar, Program program) {
|
||||||
if (program == null) {
|
if (program == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Scalar scalar = new Scalar(size * 8, value, isSigned);
|
|
||||||
SetEquateDialog dialog = new SetEquateDialog(plugin.getTool(), program, scalar);
|
SetEquateDialog dialog = new SetEquateDialog(plugin.getTool(), program, scalar);
|
||||||
dialog.disableHasSelection();
|
dialog.disableHasSelection();
|
||||||
int res = dialog.showSetDialog();
|
int res = dialog.showSetDialog();
|
||||||
@@ -66,7 +65,7 @@ public class SetEquateAction extends ConvertConstantAction {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean isEnabledForDecompilerContext(DecompilerActionContext context) {
|
protected boolean isEnabledForDecompilerContext(DecompilerActionContext context) {
|
||||||
ConvertConstantTask task = establishTask(context, false);
|
Scalar scalar = ConvertConstantEquateTask.getConvertibleConstant(context, convertType);
|
||||||
return (task != null);
|
return (scalar != null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -27,6 +27,7 @@ import ghidra.app.decompiler.component.ClangTextField;
|
|||||||
import ghidra.app.plugin.core.decompile.actions.*;
|
import ghidra.app.plugin.core.decompile.actions.*;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.pcode.*;
|
import ghidra.program.model.pcode.*;
|
||||||
|
import ghidra.program.model.scalar.Scalar;
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.*;
|
||||||
|
|
||||||
public class DecompilerEquateTest extends AbstractDecompilerTest {
|
public class DecompilerEquateTest extends AbstractDecompilerTest {
|
||||||
@@ -41,7 +42,7 @@ public class DecompilerEquateTest extends AbstractDecompilerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getEquateName(long value, int size, boolean isSigned, Program program) {
|
public String getEquateName(Scalar scalar, Program program) {
|
||||||
if (program == null) {
|
if (program == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
+56
-25
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -115,34 +115,65 @@ public class EquateSymbol extends HighSymbol {
|
|||||||
decoder.closeElement(symel);
|
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
|
@Override
|
||||||
public void encode(Encoder encoder) throws IOException {
|
public void encode(Encoder encoder) throws IOException {
|
||||||
encoder.openElement(ELEM_EQUATESYMBOL);
|
encoder.openElement(ELEM_EQUATESYMBOL);
|
||||||
encodeHeader(encoder);
|
encodeHeader(encoder);
|
||||||
if (convert != 0) {
|
if (convert != 0) {
|
||||||
String formString = "hex";
|
String formString = getIntegerFormatString(convert);
|
||||||
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";
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder.writeString(ATTRIB_FORMAT, formString);
|
encoder.writeString(ATTRIB_FORMAT, formString);
|
||||||
}
|
}
|
||||||
encoder.openElement(ELEM_VALUE);
|
encoder.openElement(ELEM_VALUE);
|
||||||
|
|||||||
+1
-1
@@ -302,7 +302,7 @@ public class HighFunction extends PcodeSyntaxTree {
|
|||||||
private void decodeJumpTableList(Decoder decoder) throws DecoderException {
|
private void decodeJumpTableList(Decoder decoder) throws DecoderException {
|
||||||
int el = decoder.openElement(ELEM_JUMPTABLELIST);
|
int el = decoder.openElement(ELEM_JUMPTABLELIST);
|
||||||
while (decoder.peekElement() != 0) {
|
while (decoder.peekElement() != 0) {
|
||||||
JumpTable table = new JumpTable(entryPoint.getAddressSpace());
|
JumpTable table = new JumpTable();
|
||||||
table.decode(decoder);
|
table.decode(decoder);
|
||||||
if (!table.isEmpty()) {
|
if (!table.isEmpty()) {
|
||||||
if (jumpTables == null) {
|
if (jumpTables == null) {
|
||||||
|
|||||||
+103
-20
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* 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.database.symbol.CodeSymbol;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.address.AddressSpace;
|
|
||||||
import ghidra.program.model.listing.Function;
|
import ghidra.program.model.listing.Function;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.*;
|
||||||
@@ -101,7 +100,6 @@ public class JumpTable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private AddressSpace preferredSpace;
|
|
||||||
private Address opAddress;
|
private Address opAddress;
|
||||||
|
|
||||||
// Address corresponds to label entries. If DEFAULT_VALUE, then entry is the default guard case, not a jump target.
|
// 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 Integer labelTable[];
|
||||||
private LoadTable loadTable[];
|
private LoadTable loadTable[];
|
||||||
private BasicOverride override;
|
private BasicOverride override;
|
||||||
|
private int displayFormat; // Default format for displaying integer case values
|
||||||
|
|
||||||
public JumpTable(AddressSpace preferredSpace) {
|
public JumpTable() {
|
||||||
this.preferredSpace = preferredSpace;
|
|
||||||
opAddress = null;
|
opAddress = null;
|
||||||
addressTable = null;
|
addressTable = null;
|
||||||
labelTable = null;
|
labelTable = null;
|
||||||
loadTable = null;
|
loadTable = null;
|
||||||
override = 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;
|
opAddress = addr;
|
||||||
preferredSpace = opAddress.getAddressSpace();
|
|
||||||
labelTable = null;
|
labelTable = null;
|
||||||
loadTable = null;
|
loadTable = null;
|
||||||
|
displayFormat = format;
|
||||||
if (override) {
|
if (override) {
|
||||||
addressTable = null;
|
addressTable = null;
|
||||||
this.override = new BasicOverride(destlist);
|
this.override = new BasicOverride(destlist);
|
||||||
@@ -152,6 +151,9 @@ public class JumpTable {
|
|||||||
*/
|
*/
|
||||||
public void decode(Decoder decoder) throws DecoderException {
|
public void decode(Decoder decoder) throws DecoderException {
|
||||||
int el = decoder.openElement(ELEM_JUMPTABLE);
|
int el = decoder.openElement(ELEM_JUMPTABLE);
|
||||||
|
if (decoder.getNextAttributeId() == ATTRIB_FORMAT.id()) {
|
||||||
|
displayFormat = (int) decoder.readUnsignedInteger();
|
||||||
|
}
|
||||||
if (decoder.peekElement() == 0) { // Empty jumptable
|
if (decoder.peekElement() == 0) { // Empty jumptable
|
||||||
decoder.closeElement(el);
|
decoder.closeElement(el);
|
||||||
return;
|
return;
|
||||||
@@ -206,6 +208,9 @@ public class JumpTable {
|
|||||||
|
|
||||||
public void encode(Encoder encoder) throws IOException {
|
public void encode(Encoder encoder) throws IOException {
|
||||||
encoder.openElement(ELEM_JUMPTABLE);
|
encoder.openElement(ELEM_JUMPTABLE);
|
||||||
|
if (displayFormat != 0) {
|
||||||
|
encoder.writeUnsignedInteger(ATTRIB_FORMAT, displayFormat);
|
||||||
|
}
|
||||||
AddressXML.encode(encoder, opAddress);
|
AddressXML.encode(encoder, opAddress);
|
||||||
if (addressTable != null) {
|
if (addressTable != null) {
|
||||||
for (Address element : addressTable) {
|
for (Address element : addressTable) {
|
||||||
@@ -236,6 +241,82 @@ public class JumpTable {
|
|||||||
return loadTable.clone();
|
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 {
|
public void writeOverride(Function func) throws InvalidInputException {
|
||||||
if (override == null) {
|
if (override == null) {
|
||||||
throw new InvalidInputException("Jumptable is not an override");
|
throw new InvalidInputException("Jumptable is not an override");
|
||||||
@@ -244,23 +325,14 @@ public class JumpTable {
|
|||||||
if (destlist.length == 0) {
|
if (destlist.length == 0) {
|
||||||
throw new InvalidInputException("Jumptable has no destinations");
|
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();
|
Program program = func.getProgram();
|
||||||
SymbolTable symtab = program.getSymbolTable();
|
SymbolTable symtab = program.getSymbolTable();
|
||||||
|
|
||||||
Namespace space = HighFunction.findCreateOverrideSpace(func);
|
Namespace space = getSwitchNamespace(func, opAddress, symtab);
|
||||||
if (space == null) {
|
|
||||||
throw new InvalidInputException("Could not create \"override\" namespace");
|
|
||||||
}
|
|
||||||
space = HighFunction.findCreateNamespace(symtab, space, "jmp_" + opAddress.toString());
|
|
||||||
|
|
||||||
if (!HighFunction.clearNamespace(symtab, space)) {
|
if (!HighFunction.clearNamespace(symtab, space)) {
|
||||||
throw new InvalidInputException(
|
throw new InvalidInputException(
|
||||||
"Jumptable override namespace contains non-label symbols.");
|
"Jumptable override namespace contains non-label symbols.");
|
||||||
}
|
}
|
||||||
|
|
||||||
HighFunction.createLabelSymbol(symtab, opAddress, "switch", space, SourceType.USER_DEFINED,
|
HighFunction.createLabelSymbol(symtab, opAddress, "switch", space, SourceType.USER_DEFINED,
|
||||||
false);
|
false);
|
||||||
for (int i = 0; i < destlist.length; ++i) {
|
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,
|
HighFunction.createLabelSymbol(symtab, destlist[i], nm, space, SourceType.USER_DEFINED,
|
||||||
false);
|
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) {
|
public static JumpTable readOverride(Namespace space, SymbolTable symtab) {
|
||||||
Address branchind = null;
|
Address branchind = null;
|
||||||
ArrayList<Address> destlist = new ArrayList<>();
|
ArrayList<Address> destlist = new ArrayList<>();
|
||||||
SymbolIterator iter = symtab.getSymbols(space);
|
SymbolIterator iter = symtab.getSymbols(space);
|
||||||
|
int displayFormat = 0;
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
Symbol sym = iter.next();
|
Symbol sym = iter.next();
|
||||||
if (!(sym instanceof CodeSymbol)) {
|
if (!(sym instanceof CodeSymbol)) {
|
||||||
@@ -286,9 +364,14 @@ public class JumpTable {
|
|||||||
else if (sym.getName().startsWith("case")) {
|
else if (sym.getName().startsWith("case")) {
|
||||||
destlist.add(addr);
|
destlist.add(addr);
|
||||||
}
|
}
|
||||||
|
else if (sym.getName().startsWith("format")) {
|
||||||
|
branchind = addr;
|
||||||
|
displayFormat = EquateSymbol.getFormatStringValue(sym.getName().substring(7));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if ((branchind != null) && (destlist.size() > 0)) {
|
if ((branchind != null) && (destlist.size() > 0 || displayFormat != 0)) {
|
||||||
return new JumpTable(branchind, destlist, true);
|
boolean override = destlist.size() > 0;
|
||||||
|
return new JumpTable(branchind, destlist, override, displayFormat);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user