mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
GP-2578 Display volatile reads/writes as simple assignments
This commit is contained in:
parent
7e24c986ad
commit
072d8fa08f
22 changed files with 221 additions and 65 deletions
|
@ -3831,6 +3831,8 @@ int4 ActionDeadCode::apply(Funcdata &data)
|
||||||
}
|
}
|
||||||
if (!op->isAssignment())
|
if (!op->isAssignment())
|
||||||
continue;
|
continue;
|
||||||
|
if (op->holdOutput())
|
||||||
|
pushConsumed(~((uintb)0),op->getOut(),worklist);
|
||||||
}
|
}
|
||||||
else if (!op->isAssignment()) {
|
else if (!op->isAssignment()) {
|
||||||
OpCode opc = op->code();
|
OpCode opc = op->code();
|
||||||
|
|
|
@ -225,6 +225,7 @@ public:
|
||||||
bool isTypeLocked(void) const { return ((flags&Varnode::typelock)!=0); } ///< Is the Symbol type-locked
|
bool isTypeLocked(void) const { return ((flags&Varnode::typelock)!=0); } ///< Is the Symbol type-locked
|
||||||
bool isNameLocked(void) const { return ((flags&Varnode::namelock)!=0); } ///< Is the Symbol name-locked
|
bool isNameLocked(void) const { return ((flags&Varnode::namelock)!=0); } ///< Is the Symbol name-locked
|
||||||
bool isSizeTypeLocked(void) const { return ((dispflags & size_typelock)!=0); } ///< Is the Symbol size type-locked
|
bool isSizeTypeLocked(void) const { return ((dispflags & size_typelock)!=0); } ///< Is the Symbol size type-locked
|
||||||
|
bool isVolatile(void) const { return ((flags & Varnode::volatil)!=0); } ///< Is the Symbol volatile
|
||||||
bool isThisPointer(void) const { return ((dispflags & is_this_ptr)!=0); } ///< Is \b this the "this" pointer
|
bool isThisPointer(void) const { return ((dispflags & is_this_ptr)!=0); } ///< Is \b this the "this" pointer
|
||||||
bool isIndirectStorage(void) const { return ((flags&Varnode::indirectstorage)!=0); } ///< Is storage really a pointer to the true Symbol
|
bool isIndirectStorage(void) const { return ((flags&Varnode::indirectstorage)!=0); } ///< Is storage really a pointer to the true Symbol
|
||||||
bool isHiddenReturn(void) const { return ((flags&Varnode::hiddenretparm)!=0); } ///< Is this a reference to the function return value
|
bool isHiddenReturn(void) const { return ((flags&Varnode::hiddenretparm)!=0); } ///< Is this a reference to the function return value
|
||||||
|
|
|
@ -608,7 +608,9 @@ bool Funcdata::replaceVolatile(Varnode *vn)
|
||||||
// Create a userop of type specified by vw_op
|
// Create a userop of type specified by vw_op
|
||||||
opSetInput(newop,newConstant(4,vw_op->getIndex()),0);
|
opSetInput(newop,newConstant(4,vw_op->getIndex()),0);
|
||||||
// The first parameter is the offset of volatile memory location
|
// The first parameter is the offset of volatile memory location
|
||||||
opSetInput(newop,newCodeRef(vn->getAddr()),1);
|
Varnode *annoteVn = newCodeRef(vn->getAddr());
|
||||||
|
annoteVn->setFlags(Varnode::volatil);
|
||||||
|
opSetInput(newop,annoteVn,1);
|
||||||
// Replace the volatile variable with a temp
|
// Replace the volatile variable with a temp
|
||||||
Varnode *tmp = newUnique(vn->getSize());
|
Varnode *tmp = newUnique(vn->getSize());
|
||||||
opSetOutput(defop,tmp);
|
opSetOutput(defop,tmp);
|
||||||
|
@ -629,9 +631,13 @@ bool Funcdata::replaceVolatile(Varnode *vn)
|
||||||
// Create a userop of type specified by vr_op
|
// Create a userop of type specified by vr_op
|
||||||
opSetInput(newop,newConstant(4,vr_op->getIndex()),0);
|
opSetInput(newop,newConstant(4,vr_op->getIndex()),0);
|
||||||
// The first parameter is the offset of the volatile memory loc
|
// The first parameter is the offset of the volatile memory loc
|
||||||
opSetInput(newop,newCodeRef(vn->getAddr()),1);
|
Varnode *annoteVn = newCodeRef(vn->getAddr());
|
||||||
|
annoteVn->setFlags(Varnode::volatil);
|
||||||
|
opSetInput(newop,annoteVn,1);
|
||||||
opSetInput(readop,tmp,readop->getSlot(vn));
|
opSetInput(readop,tmp,readop->getSlot(vn));
|
||||||
opInsertBefore(newop,readop); // Insert before read
|
opInsertBefore(newop,readop); // Insert before read
|
||||||
|
if (vr_op->getDisplay() != 0) // Unless the display is functional,
|
||||||
|
newop->setHoldOutput(); // read value may not be used. Keep it around anyway.
|
||||||
}
|
}
|
||||||
if (vn->isTypeLock()) // If the original varnode had a type locked on it
|
if (vn->isTypeLock()) // If the original varnode had a type locked on it
|
||||||
newop->setAdditionalFlag(PcodeOp::special_prop); // Mark this op as doing special propagation
|
newop->setAdditionalFlag(PcodeOp::special_prop); // Mark this op as doing special propagation
|
||||||
|
|
|
@ -110,7 +110,8 @@ public:
|
||||||
warning = 8, ///< Warning has been generated for this op
|
warning = 8, ///< Warning has been generated for this op
|
||||||
incidental_copy = 0x10, ///< Treat this as \e incidental for parameter recovery algorithms
|
incidental_copy = 0x10, ///< Treat this as \e incidental for parameter recovery algorithms
|
||||||
is_cpool_transformed = 0x20, ///< Have we checked for cpool transforms
|
is_cpool_transformed = 0x20, ///< Have we checked for cpool transforms
|
||||||
stop_type_propagation = 0x40 ///< Stop data-type propagation into output from descendants
|
stop_type_propagation = 0x40, ///< Stop data-type propagation into output from descendants
|
||||||
|
hold_output = 0x80 ///< Output varnode (of call) should not be removed if it is unread
|
||||||
};
|
};
|
||||||
private:
|
private:
|
||||||
TypeOp *opcode; ///< Pointer to class providing behavioral details of the operation
|
TypeOp *opcode; ///< Pointer to class providing behavioral details of the operation
|
||||||
|
@ -209,6 +210,8 @@ public:
|
||||||
bool stopsTypePropagation(void) const { return ((addlflags&stop_type_propagation)!=0); } ///< Is data-type propagation from below stopped
|
bool stopsTypePropagation(void) const { return ((addlflags&stop_type_propagation)!=0); } ///< Is data-type propagation from below stopped
|
||||||
void setStopTypePropagation(void) { addlflags |= stop_type_propagation; } ///< Stop data-type propagation from below
|
void setStopTypePropagation(void) { addlflags |= stop_type_propagation; } ///< Stop data-type propagation from below
|
||||||
void clearStopTypePropagation(void) { addlflags &= ~stop_type_propagation; } ///< Allow data-type propagation from below
|
void clearStopTypePropagation(void) { addlflags &= ~stop_type_propagation; } ///< Allow data-type propagation from below
|
||||||
|
bool holdOutput(void) const { return ((addlflags&hold_output)!=0); } ///< If \b true, do not remove output as dead code
|
||||||
|
void setHoldOutput(void) { addlflags |= hold_output; } ///< Prevent output from being removed as dead code
|
||||||
bool stopsCopyPropagation(void) const { return ((flags&no_copy_propagation)!=0); } ///< Does \b this allow COPY propagation
|
bool stopsCopyPropagation(void) const { return ((flags&no_copy_propagation)!=0); } ///< Does \b this allow COPY propagation
|
||||||
void setStopCopyPropagation(void) { flags |= no_copy_propagation; } ///< Stop COPY propagation through inputs
|
void setStopCopyPropagation(void) { flags |= no_copy_propagation; } ///< Stop COPY propagation through inputs
|
||||||
/// \brief Return \b true if this LOADs or STOREs from a dynamic \e spacebase pointer
|
/// \brief Return \b true if this LOADs or STOREs from a dynamic \e spacebase pointer
|
||||||
|
|
|
@ -115,7 +115,8 @@ public:
|
||||||
param_color = 6, ///< Function parameters
|
param_color = 6, ///< Function parameters
|
||||||
global_color = 7, ///< Global variable identifiers
|
global_color = 7, ///< Global variable identifiers
|
||||||
no_color = 8, ///< Un-highlighted
|
no_color = 8, ///< Un-highlighted
|
||||||
error_color = 9 ///< Indicates a warning or error state
|
error_color = 9, ///< Indicates a warning or error state
|
||||||
|
special_color = 10 ///< A token with special/highlighted meaning
|
||||||
};
|
};
|
||||||
virtual ~Emit(void) {} ///< Destructor
|
virtual ~Emit(void) {} ///< Destructor
|
||||||
|
|
||||||
|
|
|
@ -614,19 +614,31 @@ void PrintC::opCallind(const PcodeOp *op)
|
||||||
void PrintC::opCallother(const PcodeOp *op)
|
void PrintC::opCallother(const PcodeOp *op)
|
||||||
|
|
||||||
{
|
{
|
||||||
string nm = op->getOpcode()->getOperatorName(op);
|
UserPcodeOp *userop = glb->userops.getOp(op->getIn(0)->getOffset());
|
||||||
pushOp(&function_call,op);
|
uint4 display = userop->getDisplay();
|
||||||
pushAtom(Atom(nm,optoken,EmitMarkup::funcname_color,op));
|
if (display == UserPcodeOp::annotation_assignment) {
|
||||||
if (op->numInput() > 1) {
|
pushOp(&assignment,op);
|
||||||
for(int4 i=1;i<op->numInput()-1;++i)
|
pushVn(op->getIn(2),op,mods);
|
||||||
pushOp(&comma,op);
|
pushVn(op->getIn(1),op,mods);
|
||||||
// implied vn's pushed on in reverse order for efficiency
|
}
|
||||||
// see PrintLanguage::pushVnImplied
|
else if (display == UserPcodeOp::no_operator) {
|
||||||
for(int4 i=op->numInput()-1;i>=1;--i)
|
pushVn(op->getIn(1),op,mods);
|
||||||
pushVn(op->getIn(i),op,mods);
|
}
|
||||||
|
else { // Emit using functional syntax
|
||||||
|
string nm = op->getOpcode()->getOperatorName(op);
|
||||||
|
pushOp(&function_call,op);
|
||||||
|
pushAtom(Atom(nm,optoken,EmitMarkup::funcname_color,op));
|
||||||
|
if (op->numInput() > 1) {
|
||||||
|
for(int4 i = 1;i < op->numInput() - 1;++i)
|
||||||
|
pushOp(&comma,op);
|
||||||
|
// implied vn's pushed on in reverse order for efficiency
|
||||||
|
// see PrintLanguage::pushVnImplied
|
||||||
|
for(int4 i = op->numInput() - 1;i >= 1;--i)
|
||||||
|
pushVn(op->getIn(i),op,mods);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
pushAtom(Atom(EMPTY_STRING,blanktoken,EmitMarkup::no_color)); // Push empty token for void
|
||||||
}
|
}
|
||||||
else // Push empty token for void
|
|
||||||
pushAtom(Atom(EMPTY_STRING,blanktoken,EmitMarkup::no_color));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrintC::opConstructor(const PcodeOp *op,bool withNew)
|
void PrintC::opConstructor(const PcodeOp *op,bool withNew)
|
||||||
|
@ -1755,21 +1767,8 @@ void PrintC::pushAnnotation(const Varnode *vn,const PcodeOp *op)
|
||||||
const Scope *symScope = op->getParent()->getFuncdata()->getScopeLocal();
|
const Scope *symScope = op->getParent()->getFuncdata()->getScopeLocal();
|
||||||
int4 size = 0;
|
int4 size = 0;
|
||||||
if (op->code() == CPUI_CALLOTHER) {
|
if (op->code() == CPUI_CALLOTHER) {
|
||||||
// This construction is for volatile CALLOTHERs where the input annotation is the original address
|
|
||||||
// of the volatile access
|
|
||||||
int4 userind = (int4)op->getIn(0)->getOffset();
|
int4 userind = (int4)op->getIn(0)->getOffset();
|
||||||
VolatileWriteOp *vw_op = glb->userops.getVolatileWrite();
|
size = glb->userops.getOp(userind)->extractAnnotationSize(vn, op);
|
||||||
VolatileReadOp *vr_op = glb->userops.getVolatileRead();
|
|
||||||
if (userind == vw_op->getIndex()) { // Annotation from a volatile write
|
|
||||||
size = op->getIn(2)->getSize(); // Get size from the 3rd parameter of write function
|
|
||||||
}
|
|
||||||
else if (userind == vr_op->getIndex()) {
|
|
||||||
const Varnode *outvn = op->getOut();
|
|
||||||
if (outvn != (const Varnode *)0)
|
|
||||||
size = op->getOut()->getSize(); // Get size from output of read function
|
|
||||||
else
|
|
||||||
size = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
SymbolEntry *entry;
|
SymbolEntry *entry;
|
||||||
if (size != 0)
|
if (size != 0)
|
||||||
|
@ -1793,11 +1792,16 @@ void PrintC::pushAnnotation(const Varnode *vn,const PcodeOp *op)
|
||||||
else {
|
else {
|
||||||
string regname = glb->translate->getRegisterName(vn->getSpace(),vn->getOffset(),size);
|
string regname = glb->translate->getRegisterName(vn->getSpace(),vn->getOffset(),size);
|
||||||
if (regname.empty()) {
|
if (regname.empty()) {
|
||||||
Datatype *ct = glb->types->getBase(size,TYPE_UINT);
|
AddrSpace *spc = vn->getSpace();
|
||||||
pushConstant(AddrSpace::byteToAddress(vn->getOffset(),vn->getSpace()->getWordSize()),ct,vn,op);
|
string spacename = spc->getName();
|
||||||
|
spacename[0] = toupper( spacename[0] ); // Capitalize space
|
||||||
|
ostringstream s;
|
||||||
|
s << spacename;
|
||||||
|
s << hex << setfill('0') << setw(2*spc->getAddrSize());
|
||||||
|
s << AddrSpace::byteToAddress( vn->getOffset(), spc->getWordSize() );
|
||||||
|
regname = s.str();
|
||||||
}
|
}
|
||||||
else
|
pushAtom(Atom(regname,vartoken,EmitMarkup::special_color,op,vn));
|
||||||
pushAtom(Atom(regname,vartoken,EmitMarkup::var_color,op,vn));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1805,7 +1809,9 @@ void PrintC::pushSymbol(const Symbol *sym,const Varnode *vn,const PcodeOp *op)
|
||||||
|
|
||||||
{
|
{
|
||||||
EmitMarkup::syntax_highlight tokenColor;
|
EmitMarkup::syntax_highlight tokenColor;
|
||||||
if (sym->getScope()->isGlobal())
|
if (sym->isVolatile())
|
||||||
|
tokenColor = EmitMarkup::special_color;
|
||||||
|
else if (sym->getScope()->isGlobal())
|
||||||
tokenColor = EmitMarkup::global_color;
|
tokenColor = EmitMarkup::global_color;
|
||||||
else if (sym->getCategory() == Symbol::function_parameter)
|
else if (sym->getCategory() == Symbol::function_parameter)
|
||||||
tokenColor = EmitMarkup::param_color;
|
tokenColor = EmitMarkup::param_color;
|
||||||
|
|
|
@ -25,6 +25,12 @@ ElementId ELEM_CONSTRESOLVE = ElementId("constresolve",127);
|
||||||
ElementId ELEM_JUMPASSIST = ElementId("jumpassist",128);
|
ElementId ELEM_JUMPASSIST = ElementId("jumpassist",128);
|
||||||
ElementId ELEM_SEGMENTOP = ElementId("segmentop",129);
|
ElementId ELEM_SEGMENTOP = ElementId("segmentop",129);
|
||||||
|
|
||||||
|
int4 UserPcodeOp::extractAnnotationSize(const Varnode *vn,const PcodeOp *op)
|
||||||
|
|
||||||
|
{
|
||||||
|
throw LowlevelError("Unexpected annotation input for CALLOTHER " + name);
|
||||||
|
}
|
||||||
|
|
||||||
void InjectedUserOp::decode(Decoder &decoder)
|
void InjectedUserOp::decode(Decoder &decoder)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -68,6 +74,15 @@ string VolatileReadOp::getOperatorName(const PcodeOp *op) const
|
||||||
return appendSize(name,op->getOut()->getSize());
|
return appendSize(name,op->getOut()->getSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int4 VolatileReadOp::extractAnnotationSize(const Varnode *vn,const PcodeOp *op)
|
||||||
|
|
||||||
|
{
|
||||||
|
const Varnode *outvn = op->getOut();
|
||||||
|
if (outvn != (const Varnode *)0)
|
||||||
|
return op->getOut()->getSize(); // Get size from output of read function
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
string VolatileWriteOp::getOperatorName(const PcodeOp *op) const
|
string VolatileWriteOp::getOperatorName(const PcodeOp *op) const
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -75,6 +90,12 @@ string VolatileWriteOp::getOperatorName(const PcodeOp *op) const
|
||||||
return appendSize(name,op->getIn(2)->getSize());
|
return appendSize(name,op->getIn(2)->getSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int4 VolatileWriteOp::extractAnnotationSize(const Varnode *vn,const PcodeOp *op)
|
||||||
|
|
||||||
|
{
|
||||||
|
return op->getIn(2)->getSize(); // Get size from the 3rd parameter of write function
|
||||||
|
}
|
||||||
|
|
||||||
/// \param g is the owning Architecture for this instance of the segment operation
|
/// \param g is the owning Architecture for this instance of the segment operation
|
||||||
/// \param nm is the low-level name of the segment operation
|
/// \param nm is the low-level name of the segment operation
|
||||||
/// \param ind is the constant id identifying the specific CALLOTHER variant
|
/// \param ind is the constant id identifying the specific CALLOTHER variant
|
||||||
|
@ -291,11 +312,11 @@ void UserOpManage::setDefaults(Architecture *glb)
|
||||||
|
|
||||||
{
|
{
|
||||||
if (vol_read == (VolatileReadOp *)0) {
|
if (vol_read == (VolatileReadOp *)0) {
|
||||||
VolatileReadOp *volread = new VolatileReadOp(glb,"read_volatile",useroplist.size());
|
VolatileReadOp *volread = new VolatileReadOp(glb,"read_volatile",useroplist.size(), false);
|
||||||
registerOp(volread);
|
registerOp(volread);
|
||||||
}
|
}
|
||||||
if (vol_write == (VolatileWriteOp *)0) {
|
if (vol_write == (VolatileWriteOp *)0) {
|
||||||
VolatileWriteOp *volwrite = new VolatileWriteOp(glb,"write_volatile",useroplist.size());
|
VolatileWriteOp *volwrite = new VolatileWriteOp(glb,"write_volatile",useroplist.size(), false);
|
||||||
registerOp(volwrite);
|
registerOp(volwrite);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -392,28 +413,39 @@ void UserOpManage::decodeSegmentOp(Decoder &decoder,Architecture *glb)
|
||||||
void UserOpManage::decodeVolatile(Decoder &decoder,Architecture *glb)
|
void UserOpManage::decodeVolatile(Decoder &decoder,Architecture *glb)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
string readOpName;
|
||||||
|
string writeOpName;
|
||||||
|
bool functionalDisplay = false;
|
||||||
for(;;) {
|
for(;;) {
|
||||||
uint4 attribId = decoder.getNextAttributeId();
|
uint4 attribId = decoder.getNextAttributeId();
|
||||||
if (attribId == 0) break;
|
if (attribId == 0) break;
|
||||||
if (attribId==ATTRIB_INPUTOP) {
|
if (attribId==ATTRIB_INPUTOP) {
|
||||||
VolatileReadOp *vr_op = new VolatileReadOp(glb,decoder.readString(),useroplist.size());
|
readOpName = decoder.readString();
|
||||||
try {
|
|
||||||
registerOp(vr_op);
|
|
||||||
} catch(LowlevelError &err) {
|
|
||||||
delete vr_op;
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (attribId==ATTRIB_OUTPUTOP) {
|
else if (attribId==ATTRIB_OUTPUTOP) {
|
||||||
// Read in the volatile output tag
|
writeOpName = decoder.readString();
|
||||||
VolatileWriteOp *vw_op = new VolatileWriteOp(glb,decoder.readString(),useroplist.size());
|
|
||||||
try {
|
|
||||||
registerOp(vw_op);
|
|
||||||
} catch(LowlevelError &err) {
|
|
||||||
delete vw_op;
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else if (attribId == ATTRIB_FORMAT) {
|
||||||
|
string format = decoder.readString();
|
||||||
|
if (format == "functional")
|
||||||
|
functionalDisplay = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (readOpName.size() == 0 || writeOpName.size() == 0)
|
||||||
|
throw LowlevelError("Missing inputop/outputop attributes in <volatile> element");
|
||||||
|
VolatileReadOp *vr_op = new VolatileReadOp(glb,readOpName,useroplist.size(),functionalDisplay);
|
||||||
|
try {
|
||||||
|
registerOp(vr_op);
|
||||||
|
} catch(LowlevelError &err) {
|
||||||
|
delete vr_op;
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
VolatileWriteOp *vw_op = new VolatileWriteOp(glb,writeOpName,useroplist.size(),functionalDisplay);
|
||||||
|
try {
|
||||||
|
registerOp(vw_op);
|
||||||
|
} catch(LowlevelError &err) {
|
||||||
|
delete vw_op;
|
||||||
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,15 +43,22 @@ extern ElementId ELEM_SEGMENTOP; ///< Marshaling element \<segmentop>
|
||||||
/// or program. At this base level, the only commonality is a formal \b name of the operator and
|
/// or program. At this base level, the only commonality is a formal \b name of the operator and
|
||||||
/// its CALLOTHER index. A facility for reading in implementation details is provided via decode().
|
/// its CALLOTHER index. A facility for reading in implementation details is provided via decode().
|
||||||
class UserPcodeOp {
|
class UserPcodeOp {
|
||||||
|
public:
|
||||||
|
enum userop_flags {
|
||||||
|
annotation_assignment = 1, ///< Displayed as assignment, `in1 = in2`, where the first parameter is an annotation
|
||||||
|
no_operator = 2 ///< Don't emit special token, just emit the first input parameter as expression
|
||||||
|
};
|
||||||
protected:
|
protected:
|
||||||
string name; ///< Low-level name of p-code operator
|
string name; ///< Low-level name of p-code operator
|
||||||
int4 useropindex; ///< Index passed in the CALLOTHER op
|
int4 useropindex; ///< Index passed in the CALLOTHER op
|
||||||
Architecture *glb; ///< Architecture owning the user defined op
|
Architecture *glb; ///< Architecture owning the user defined op
|
||||||
|
uint4 flags; ///< Boolean attributes of the CALLOTHER
|
||||||
public:
|
public:
|
||||||
UserPcodeOp(Architecture *g,const string &nm,int4 ind) {
|
UserPcodeOp(Architecture *g,const string &nm,int4 ind) {
|
||||||
name = nm; useropindex = ind; glb = g; } ///< Construct from name and index
|
name = nm; useropindex = ind; glb = g; flags = 0; } ///< Construct from name and index
|
||||||
const string &getName(void) const { return name; } ///< Get the low-level name of the p-code op
|
const string &getName(void) const { return name; } ///< Get the low-level name of the p-code op
|
||||||
int4 getIndex(void) const { return useropindex; } ///< Get the constant id of the op
|
int4 getIndex(void) const { return useropindex; } ///< Get the constant id of the op
|
||||||
|
uint4 getDisplay(void) const { return (flags & (annotation_assignment | no_operator)); } ///< Get display type (0=functional)
|
||||||
virtual ~UserPcodeOp(void) {} ///< Destructor
|
virtual ~UserPcodeOp(void) {} ///< Destructor
|
||||||
|
|
||||||
/// \brief Get the symbol representing this operation in decompiled code
|
/// \brief Get the symbol representing this operation in decompiled code
|
||||||
|
@ -63,6 +70,14 @@ public:
|
||||||
virtual string getOperatorName(const PcodeOp *op) const {
|
virtual string getOperatorName(const PcodeOp *op) const {
|
||||||
return name; }
|
return name; }
|
||||||
|
|
||||||
|
/// \brief Assign a size to an annotation input to \b this userop
|
||||||
|
///
|
||||||
|
/// Assuming an annotation refers to a special symbol accessed by \b this operation, retrieve the
|
||||||
|
/// size (in bytes) of the symbol, which isn't ordinarily stored as part of the annotation.
|
||||||
|
/// \param vn is the annotation Varnode
|
||||||
|
/// \param op is the specific PcodeOp instance of \b this userop
|
||||||
|
virtual int4 extractAnnotationSize(const Varnode *vn,const PcodeOp *op);
|
||||||
|
|
||||||
/// \brief Restore the detailed description from a stream element
|
/// \brief Restore the detailed description from a stream element
|
||||||
///
|
///
|
||||||
/// The details of how a user defined operation behaves are parsed from the element.
|
/// The details of how a user defined operation behaves are parsed from the element.
|
||||||
|
@ -120,9 +135,10 @@ public:
|
||||||
/// is the actual value read from memory.
|
/// is the actual value read from memory.
|
||||||
class VolatileReadOp : public VolatileOp {
|
class VolatileReadOp : public VolatileOp {
|
||||||
public:
|
public:
|
||||||
VolatileReadOp(Architecture *g,const string &nm,int4 ind)
|
VolatileReadOp(Architecture *g,const string &nm,int4 ind,bool functional)
|
||||||
: VolatileOp(g,nm,ind) {} ///< Constructor
|
: VolatileOp(g,nm,ind) { flags = functional ? 0 : no_operator; } ///< Constructor
|
||||||
virtual string getOperatorName(const PcodeOp *op) const;
|
virtual string getOperatorName(const PcodeOp *op) const;
|
||||||
|
virtual int4 extractAnnotationSize(const Varnode *vn,const PcodeOp *op);
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief An operation that writes to volatile memory
|
/// \brief An operation that writes to volatile memory
|
||||||
|
@ -133,9 +149,10 @@ public:
|
||||||
/// - The Varnode value being written to the memory
|
/// - The Varnode value being written to the memory
|
||||||
class VolatileWriteOp : public VolatileOp {
|
class VolatileWriteOp : public VolatileOp {
|
||||||
public:
|
public:
|
||||||
VolatileWriteOp(Architecture *g,const string &nm,int4 ind)
|
VolatileWriteOp(Architecture *g,const string &nm,int4 ind,bool functional)
|
||||||
: VolatileOp(g,nm,ind) {} ///< Constructor
|
: VolatileOp(g,nm,ind) { flags = functional ? 0 : annotation_assignment; } ///< Constructor
|
||||||
virtual string getOperatorName(const PcodeOp *op) const;
|
virtual string getOperatorName(const PcodeOp *op) const;
|
||||||
|
virtual int4 extractAnnotationSize(const Varnode *vn,const PcodeOp *op);
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief A user defined p-code op that has a dynamically defined procedure
|
/// \brief A user defined p-code op that has a dynamically defined procedure
|
||||||
|
|
|
@ -910,6 +910,8 @@ void Varnode::encode(Encoder &encoder) const
|
||||||
encoder.writeBool(ATTRIB_UNAFF, true);
|
encoder.writeBool(ATTRIB_UNAFF, true);
|
||||||
if (isInput())
|
if (isInput())
|
||||||
encoder.writeBool(ATTRIB_INPUT, true);
|
encoder.writeBool(ATTRIB_INPUT, true);
|
||||||
|
if (isVolatile())
|
||||||
|
encoder.writeBool(ATTRIB_VOLATILE, true);
|
||||||
encoder.closeElement(ELEM_ADDR);
|
encoder.closeElement(ELEM_ADDR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,5 +26,6 @@
|
||||||
<com>print C</com>
|
<com>print C</com>
|
||||||
<com>quit</com>
|
<com>quit</com>
|
||||||
</script>
|
</script>
|
||||||
<stringmatch name="Dead Volatile #1" min="1" max="1">read_volatile.*0x1000</stringmatch>
|
<stringmatch name="Dead Volatile #1" min="1" max="1">xVar1 = Ram00001000;</stringmatch>
|
||||||
|
<stringmatch name="Dead Volatile #2" min="2" max="2">xVar1</stringmatch>
|
||||||
</decompilertest>
|
</decompilertest>
|
||||||
|
|
|
@ -19,6 +19,6 @@
|
||||||
<com>print C</com>
|
<com>print C</com>
|
||||||
<com>quit</com>
|
<com>quit</com>
|
||||||
</script>
|
</script>
|
||||||
<stringmatch name="Read Volatile #1" min="1" max="1">read_volatile.*NVRAM.*30</stringmatch>
|
<stringmatch name="Read Volatile #1" min="1" max="1">Var1 = NVRAM\[30\];</stringmatch>
|
||||||
<stringmatch name="Read Volatile #2" min="5" max="5">write_volatile.*NVRAM</stringmatch>
|
<stringmatch name="Read Volatile #2" min="5" max="5">NVRAM\[.0\] = 0;</stringmatch>
|
||||||
</decompilertest>
|
</decompilertest>
|
||||||
|
|
|
@ -3016,6 +3016,7 @@
|
||||||
<listitem><emphasis role="bold">Parameters</emphasis> - names of function input variables</listitem>
|
<listitem><emphasis role="bold">Parameters</emphasis> - names of function input variables</listitem>
|
||||||
<listitem><emphasis role="bold">Types</emphasis> - names of data-types in variable declarations and casts</listitem>
|
<listitem><emphasis role="bold">Types</emphasis> - names of data-types in variable declarations and casts</listitem>
|
||||||
<listitem><emphasis role="bold">Variables</emphasis> - names of local variables</listitem>
|
<listitem><emphasis role="bold">Variables</emphasis> - names of local variables</listitem>
|
||||||
|
<listitem><emphasis role="bold">Special</emphasis> - volatile variables and other special symbols</listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
</informalexample>
|
</informalexample>
|
||||||
</para>
|
</para>
|
||||||
|
|
|
@ -48,7 +48,8 @@ public class ClangToken implements ClangNode {
|
||||||
public final static int GLOBAL_COLOR = 7;
|
public final static int GLOBAL_COLOR = 7;
|
||||||
public final static int DEFAULT_COLOR = 8;
|
public final static int DEFAULT_COLOR = 8;
|
||||||
public final static int ERROR_COLOR = 9;
|
public final static int ERROR_COLOR = 9;
|
||||||
public final static int MAX_COLOR = 10;
|
public final static int SPECIAL_COLOR = 10;
|
||||||
|
public final static int MAX_COLOR = 11;
|
||||||
|
|
||||||
private ClangNode parent;
|
private ClangNode parent;
|
||||||
private ClangLine lineparent;
|
private ClangLine lineparent;
|
||||||
|
|
|
@ -334,6 +334,9 @@ public class DecompileOptions {
|
||||||
private final static String HIGHLIGHT_GLOBAL_MSG = "Display.Color for Globals";
|
private final static String HIGHLIGHT_GLOBAL_MSG = "Display.Color for Globals";
|
||||||
private final static Color HIGHLIGHT_GLOBAL_DEF = Color.decode("0x009999");
|
private final static Color HIGHLIGHT_GLOBAL_DEF = Color.decode("0x009999");
|
||||||
private Color globalColor;
|
private Color globalColor;
|
||||||
|
private final static String HIGHLIGHT_SPECIAL_MSG = "Display.Color for Special";
|
||||||
|
private final static Color HIGHLIGHT_SPECIAL_DEF = Color.decode("0xCC0033");
|
||||||
|
private Color specialColor;
|
||||||
private final static String HIGHLIGHT_DEFAULT_MSG = "Display.Color Default";
|
private final static String HIGHLIGHT_DEFAULT_MSG = "Display.Color Default";
|
||||||
private final static Color HIGHLIGHT_DEFAULT_DEF = Color.BLACK;
|
private final static Color HIGHLIGHT_DEFAULT_DEF = Color.BLACK;
|
||||||
private Color defaultColor;
|
private Color defaultColor;
|
||||||
|
@ -407,6 +410,7 @@ public class DecompileOptions {
|
||||||
typeColor = HIGHLIGHT_TYPE_DEF;
|
typeColor = HIGHLIGHT_TYPE_DEF;
|
||||||
parameterColor = HIGHLIGHT_PARAMETER_DEF;
|
parameterColor = HIGHLIGHT_PARAMETER_DEF;
|
||||||
globalColor = HIGHLIGHT_GLOBAL_DEF;
|
globalColor = HIGHLIGHT_GLOBAL_DEF;
|
||||||
|
specialColor = HIGHLIGHT_SPECIAL_DEF;
|
||||||
defaultColor = HIGHLIGHT_DEFAULT_DEF;
|
defaultColor = HIGHLIGHT_DEFAULT_DEF;
|
||||||
codeViewerBackgroundColor = CODE_VIEWER_BACKGROUND_COLOR;
|
codeViewerBackgroundColor = CODE_VIEWER_BACKGROUND_COLOR;
|
||||||
defaultFont = DEFAULT_FONT;
|
defaultFont = DEFAULT_FONT;
|
||||||
|
@ -470,6 +474,7 @@ public class DecompileOptions {
|
||||||
constantColor = opt.getColor(HIGHLIGHT_CONST_MSG, HIGHLIGHT_CONST_DEF);
|
constantColor = opt.getColor(HIGHLIGHT_CONST_MSG, HIGHLIGHT_CONST_DEF);
|
||||||
parameterColor = opt.getColor(HIGHLIGHT_PARAMETER_MSG, HIGHLIGHT_PARAMETER_DEF);
|
parameterColor = opt.getColor(HIGHLIGHT_PARAMETER_MSG, HIGHLIGHT_PARAMETER_DEF);
|
||||||
globalColor = opt.getColor(HIGHLIGHT_GLOBAL_MSG, HIGHLIGHT_GLOBAL_DEF);
|
globalColor = opt.getColor(HIGHLIGHT_GLOBAL_MSG, HIGHLIGHT_GLOBAL_DEF);
|
||||||
|
specialColor = opt.getColor(HIGHLIGHT_SPECIAL_MSG, HIGHLIGHT_SPECIAL_DEF);
|
||||||
defaultColor = opt.getColor(HIGHLIGHT_DEFAULT_MSG, HIGHLIGHT_DEFAULT_DEF);
|
defaultColor = opt.getColor(HIGHLIGHT_DEFAULT_MSG, HIGHLIGHT_DEFAULT_DEF);
|
||||||
codeViewerBackgroundColor =
|
codeViewerBackgroundColor =
|
||||||
opt.getColor(CODE_VIEWER_BACKGROUND_COLOR_MSG, CODE_VIEWER_BACKGROUND_COLOR);
|
opt.getColor(CODE_VIEWER_BACKGROUND_COLOR_MSG, CODE_VIEWER_BACKGROUND_COLOR);
|
||||||
|
@ -638,6 +643,9 @@ public class DecompileOptions {
|
||||||
opt.registerOption(HIGHLIGHT_GLOBAL_MSG, HIGHLIGHT_GLOBAL_DEF,
|
opt.registerOption(HIGHLIGHT_GLOBAL_MSG, HIGHLIGHT_GLOBAL_DEF,
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "DisplayTokenColor"),
|
new HelpLocation(HelpTopics.DECOMPILER, "DisplayTokenColor"),
|
||||||
"Color used for highlighting global variables.");
|
"Color used for highlighting global variables.");
|
||||||
|
opt.registerOption(HIGHLIGHT_SPECIAL_MSG, HIGHLIGHT_SPECIAL_DEF,
|
||||||
|
new HelpLocation(HelpTopics.DECOMPILER, "DisplayTokenColor"),
|
||||||
|
"Color used for volatile or other exceptional variables.");
|
||||||
opt.registerOption(HIGHLIGHT_DEFAULT_MSG, HIGHLIGHT_DEFAULT_DEF,
|
opt.registerOption(HIGHLIGHT_DEFAULT_MSG, HIGHLIGHT_DEFAULT_DEF,
|
||||||
new HelpLocation(HelpTopics.DECOMPILER, "DisplayColorDefault"),
|
new HelpLocation(HelpTopics.DECOMPILER, "DisplayColorDefault"),
|
||||||
"The color used when a specific color is not specified.");
|
"The color used when a specific color is not specified.");
|
||||||
|
@ -857,6 +865,13 @@ public class DecompileOptions {
|
||||||
return globalColor;
|
return globalColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return color associated with volatile variables or other special tokens
|
||||||
|
*/
|
||||||
|
public Color getSpecialColor() {
|
||||||
|
return specialColor;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return color for generic syntax or other unspecified tokens
|
* @return color for generic syntax or other unspecified tokens
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -240,6 +240,7 @@ public class ClangLayoutController implements LayoutModel, LayoutModelListener {
|
||||||
syntax_color[ClangToken.GLOBAL_COLOR] = options.getGlobalColor();
|
syntax_color[ClangToken.GLOBAL_COLOR] = options.getGlobalColor();
|
||||||
syntax_color[ClangToken.DEFAULT_COLOR] = options.getDefaultColor();
|
syntax_color[ClangToken.DEFAULT_COLOR] = options.getDefaultColor();
|
||||||
syntax_color[ClangToken.ERROR_COLOR] = options.getErrorColor();
|
syntax_color[ClangToken.ERROR_COLOR] = options.getErrorColor();
|
||||||
|
syntax_color[ClangToken.SPECIAL_COLOR] = options.getSpecialColor();
|
||||||
|
|
||||||
// setting the metrics here will indirectly trigger the new font to be used deeper in
|
// setting the metrics here will indirectly trigger the new font to be used deeper in
|
||||||
// the bowels of the FieldPanel (you can get the font from the metrics)
|
// the bowels of the FieldPanel (you can get the font from the metrics)
|
||||||
|
|
|
@ -77,6 +77,9 @@ public class DecompilerHoverProvider extends AbstractHoverProvider {
|
||||||
if (highVar instanceof HighGlobal) {
|
if (highVar instanceof HighGlobal) {
|
||||||
reference = highVar.getRepresentative().getAddress();
|
reference = highVar.getRepresentative().getAddress();
|
||||||
}
|
}
|
||||||
|
else if (highVar == null && vn.getAddress().isLoadedMemoryAddress()) {
|
||||||
|
reference = vn.getAddress();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ProgramLocation(program, token.getMinAddress(), reference);
|
return new ProgramLocation(program, token.getMinAddress(), reference);
|
||||||
|
|
|
@ -72,6 +72,10 @@
|
||||||
<element name="volatile">
|
<element name="volatile">
|
||||||
<attribute name="inputop"/>
|
<attribute name="inputop"/>
|
||||||
<attribute name="outputop"/>
|
<attribute name="outputop"/>
|
||||||
|
<optional>
|
||||||
|
<attribute name="format"/>
|
||||||
|
<!-- format="functional" forces functional operator synxtax-->
|
||||||
|
</optional>
|
||||||
<oneOrMore>
|
<oneOrMore>
|
||||||
<ref name="memory_tags_type"/>
|
<ref name="memory_tags_type"/>
|
||||||
</oneOrMore>
|
</oneOrMore>
|
||||||
|
|
|
@ -51,8 +51,8 @@ public class GlobalSymbolMap {
|
||||||
program = f.getFunction().getProgram();
|
program = f.getFunction().getProgram();
|
||||||
func = f;
|
func = f;
|
||||||
symbolTable = program.getSymbolTable();
|
symbolTable = program.getSymbolTable();
|
||||||
addrMappedSymbols = new HashMap<Address, HighSymbol>();
|
addrMappedSymbols = new HashMap<>();
|
||||||
symbolMap = new HashMap<Long, HighSymbol>();
|
symbolMap = new HashMap<>();
|
||||||
uniqueSymbolId = 0;
|
uniqueSymbolId = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,6 +111,42 @@ public class GlobalSymbolMap {
|
||||||
return highSym;
|
return highSym;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some Varnode annotations refer to global symbols. Check if there is symbol at the
|
||||||
|
* Varnode address and, if there is, create a corresponding HighSymbol
|
||||||
|
* @param vn is the annotation Varnode
|
||||||
|
*/
|
||||||
|
public void populateAnnotation(Varnode vn) {
|
||||||
|
Address addr = vn.getAddress();
|
||||||
|
if (!addr.isLoadedMemoryAddress() || addrMappedSymbols.containsKey(addr)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Symbol symbol = symbolTable.getPrimarySymbol(addr);
|
||||||
|
if (symbol == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
HighSymbol highSym;
|
||||||
|
if (symbol instanceof CodeSymbol) {
|
||||||
|
Data dataAt = program.getListing().getDataAt(addr);
|
||||||
|
DataType dataType = DataType.DEFAULT;
|
||||||
|
int sz = 1;
|
||||||
|
if (dataAt != null) {
|
||||||
|
dataType = dataAt.getDataType();
|
||||||
|
sz = dataAt.getLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
highSym = new HighCodeSymbol((CodeSymbol) symbol, dataType, sz, func);
|
||||||
|
}
|
||||||
|
else if (symbol instanceof FunctionSymbol) {
|
||||||
|
highSym = new HighFunctionShellSymbol(symbol.getID(), symbol.getName(),
|
||||||
|
symbol.getAddress(), func.getDataTypeManager());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
insertSymbol(highSym, symbol.getAddress());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a HighSymbol corresponding to an underlying Data object. The name of the symbol is
|
* Create a HighSymbol corresponding to an underlying Data object. The name of the symbol is
|
||||||
* generated dynamically. A symbol is always returned unless the address is invalid,
|
* generated dynamically. A symbol is always returned unless the address is invalid,
|
||||||
|
|
|
@ -471,6 +471,15 @@ public class HighFunction extends PcodeSyntaxTree {
|
||||||
encoder.closeElement(ELEM_FUNCTION);
|
encoder.closeElement(ELEM_FUNCTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setVolatile(Varnode vn, boolean val) {
|
||||||
|
if (val) {
|
||||||
|
// Volatile varnodes are modeled as annotations with no HighVariable
|
||||||
|
// Give the volatile a chance to populate a global symbol
|
||||||
|
globalSymbols.populateAnnotation(vn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static Namespace findOverrideSpace(Function func) {
|
public static Namespace findOverrideSpace(Function func) {
|
||||||
SymbolTable symtab = func.getProgram().getSymbolTable();
|
SymbolTable symtab = func.getProgram().getSymbolTable();
|
||||||
return findNamespace(symtab, func, "override");
|
return findNamespace(symtab, func, "override");
|
||||||
|
|
|
@ -144,6 +144,13 @@ public interface PcodeFactory {
|
||||||
*/
|
*/
|
||||||
public void setUnaffected(Varnode vn, boolean val);
|
public void setUnaffected(Varnode vn, boolean val);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark (or unmark) the given Varnode with the "volatile" property
|
||||||
|
* @param vn is the given Varnode
|
||||||
|
* @param val is true if the Varnode should be marked volatile
|
||||||
|
*/
|
||||||
|
public void setVolatile(Varnode vn, boolean val);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Associate a specific merge group with the given Varnode
|
* Associate a specific merge group with the given Varnode
|
||||||
* @param vn is the given Varnode
|
* @param vn is the given Varnode
|
||||||
|
@ -167,5 +174,4 @@ public interface PcodeFactory {
|
||||||
* @return the new PcodeOp
|
* @return the new PcodeOp
|
||||||
*/
|
*/
|
||||||
public PcodeOp newOp(SequenceNumber sq, int opc, ArrayList<Varnode> inputs, Varnode output);
|
public PcodeOp newOp(SequenceNumber sq, int opc, ArrayList<Varnode> inputs, Varnode output);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -331,6 +331,11 @@ public class PcodeSyntaxTree implements PcodeFactory {
|
||||||
vnast.setUnaffected(val);
|
vnast.setUnaffected(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setVolatile(Varnode vn, boolean val) {
|
||||||
|
// Currently we don't set anything directly on the Varnode
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setMergeGroup(Varnode vn, short val) {
|
public void setMergeGroup(Varnode vn, short val) {
|
||||||
VarnodeAST vnast = (VarnodeAST) vn;
|
VarnodeAST vnast = (VarnodeAST) vn;
|
||||||
|
@ -524,5 +529,4 @@ public class PcodeSyntaxTree implements PcodeFactory {
|
||||||
}
|
}
|
||||||
decoder.closeElement(el);
|
decoder.closeElement(el);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -438,6 +438,11 @@ public class Varnode {
|
||||||
vn = factory.setInput(vn, true);
|
vn = factory.setInput(vn, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (attribId == ATTRIB_VOLATILE.id()) {
|
||||||
|
if (decoder.readBool()) {
|
||||||
|
factory.setVolatile(vn, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
decoder.closeElement(el);
|
decoder.closeElement(el);
|
||||||
return vn;
|
return vn;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue