GP-1922 Integer size suffix

This commit is contained in:
caheckman 2022-04-13 19:02:24 -04:00
parent d7f9cdfe5c
commit fb3366a4e2
15 changed files with 178 additions and 66 deletions

View file

@ -372,7 +372,7 @@ void Architecture::setPrintLanguage(const string &nm)
ostream *t = print->getOutputStream(); ostream *t = print->getOutputStream();
print = capa->buildLanguage(this); print = capa->buildLanguage(this);
print->setOutputStream(t); // Restore settings from previous language print->setOutputStream(t); // Restore settings from previous language
print->getCastStrategy()->setTypeFactory(types); print->initializeFromArchitecture();
if (printxml) if (printxml)
print->setXML(true); print->setXML(true);
printlist.push_back(print); printlist.push_back(print);
@ -1342,7 +1342,7 @@ void Architecture::init(DocumentStorage &store)
buildDatabase(store); buildDatabase(store);
restoreFromSpec(store); restoreFromSpec(store);
print->getCastStrategy()->setTypeFactory(types); print->initializeFromArchitecture();
symboltab->adjustCaches(); // In case the specs created additional address spaces symboltab->adjustCaches(); // In case the specs created additional address spaces
postSpecFile(); // Let subclasses do things after translate is ready postSpecFile(); // Let subclasses do things after translate is ready

View file

@ -25,6 +25,80 @@ void CastStrategy::setTypeFactory(TypeFactory *t)
promoteSize = tlst->getSizeOfInt(); promoteSize = tlst->getSizeOfInt();
} }
/// Many languages can mark an integer constant as explicitly \e unsigned. When
/// the decompiler is deciding on \e cast operations, this is one of the checks
/// it performs. This method checks if the indicated input is an
/// integer constant that needs to be coerced (as a source token) into being unsigned.
/// If this is \b true, the input Varnode is marked for printing as explicitly \e unsigned.
/// \param op is the PcodeOp taking the value as input
/// \param slot is the input slot of the value
/// \return \b true if the Varnode gets marked for printing
bool CastStrategy::markExplicitUnsigned(PcodeOp *op,int4 slot) const
{
TypeOp *opcode = op->getOpcode();
if (!opcode->inheritsSign()) return false;
bool inheritsFirstParamOnly = opcode->inheritsSignFirstParamOnly();
if ((slot==1) && inheritsFirstParamOnly) return false;
Varnode *vn = op->getIn(slot);
if (!vn->isConstant()) return false;
Datatype *dt = vn->getHighTypeReadFacing(op);
type_metatype meta = dt->getMetatype();
if ((meta != TYPE_UINT)&&(meta != TYPE_UNKNOWN)) return false;
if (dt->isCharPrint()) return false;
if (dt->isEnumType()) return false;
if ((op->numInput() == 2) && !inheritsFirstParamOnly) {
Varnode *firstvn = op->getIn(1-slot);
meta = firstvn->getHighTypeReadFacing(op)->getMetatype();
if ((meta == TYPE_UINT)||(meta == TYPE_UNKNOWN))
return false; // Other side of the operation will force the unsigned
}
// Check if type is going to get forced anyway
Varnode *outvn = op->getOut();
if (outvn != (Varnode *)0) {
if (outvn->isExplicit()) return false;
PcodeOp *lone = outvn->loneDescend();
if (lone != (PcodeOp *)0) {
if (!lone->getOpcode()->inheritsSign()) return false;
}
}
vn->setUnsignedPrint();
return true;
}
/// This method checks if the indicated input is an integer constant that needs to be coerced
/// (as a source token) into a data-type that is larger than the base integer. If this is \b true,
/// the input Varnode is marked for printing as explicitly a larger integer (typically \e long).
/// \param op is the PcodeOp taking the value as input
/// \param slot is the input slot of the value
/// \return \b true if the Varnode gets marked for printing
bool CastStrategy::markExplicitLongSize(PcodeOp *op,int4 slot) const
{
if (!op->getOpcode()->isShiftOp()) return false;
if (slot != 0) return false;
Varnode *vn = op->getIn(slot);
if (!vn->isConstant()) return false;
if (vn->getSize() <= promoteSize) return false;
Datatype *dt = vn->getHigh()->getType();
type_metatype meta = dt->getMetatype();
if ((meta != TYPE_UINT)&&(meta != TYPE_INT)&&(meta != TYPE_UNKNOWN)) return false;
uintb off = vn->getOffset();
if (meta == TYPE_INT && signbit_negative(off, vn->getSize())) {
off = uintb_negate(off, vn->getSize());
int4 bit = mostsigbit_set(off);
if (bit >= promoteSize * 8 - 1) return false;
}
else {
int4 bit = mostsigbit_set(off);
if (bit >= promoteSize * 8) return false; // If integer is big enough, it naturally becomes a long
}
vn->setLongPrint();
return true;
}
bool CastStrategyC::checkIntPromotionForCompare(const PcodeOp *op,int4 slot) const bool CastStrategyC::checkIntPromotionForCompare(const PcodeOp *op,int4 slot) const
{ {

View file

@ -153,6 +153,12 @@ public:
/// \param intype is the input data-type /// \param intype is the input data-type
/// \return \b true if the INT_ZEXT should be represented as a cast /// \return \b true if the INT_ZEXT should be represented as a cast
virtual bool isZextCast(Datatype *outtype,Datatype *intype) const=0; virtual bool isZextCast(Datatype *outtype,Datatype *intype) const=0;
/// \brief Check if a constant input should be explicitly labeled as an \e unsigned token
bool markExplicitUnsigned(PcodeOp *op,int4 slot) const;
/// \brief Check is a constant input should be explicitly labeled as a \e long integer token
bool markExplicitLongSize(PcodeOp *op,int4 slot) const;
}; };
/// \brief Casting strategies that are specific to the C language /// \brief Casting strategies that are specific to the C language

View file

@ -2474,7 +2474,9 @@ int4 ActionSetCasts::castInput(PcodeOp *op,int4 slot,Funcdata &data,CastStrategy
ct = op->getOpcode()->getInputCast(op,slot,castStrategy); // Input type expected by this operation ct = op->getOpcode()->getInputCast(op,slot,castStrategy); // Input type expected by this operation
if (ct == (Datatype *)0) { if (ct == (Datatype *)0) {
if (op->markExplicitUnsigned(slot)) // Decide if this input should be explicitly printed as unsigned constant bool resUnsigned = castStrategy->markExplicitUnsigned(op, slot);
bool resSized = castStrategy->markExplicitLongSize(op, slot);
if (resUnsigned || resSized)
return 1; return 1;
return 0; return 0;
} }

View file

@ -231,8 +231,6 @@ public:
Datatype *outputTypeLocal(void) const { return opcode->getOutputLocal(this); } ///< Calculate the local output type Datatype *outputTypeLocal(void) const { return opcode->getOutputLocal(this); } ///< Calculate the local output type
Datatype *inputTypeLocal(int4 slot) const { return opcode->getInputLocal(this,slot); } ///< Calculate the local input type Datatype *inputTypeLocal(int4 slot) const { return opcode->getInputLocal(this,slot); } ///< Calculate the local input type
bool markExplicitUnsigned(int4 slot) { return opcode->markExplicitUnsigned(this,slot); } ///< Decide on unsignedness printing
bool inheritsSign(void) const { return opcode->inheritsSign(); } ///< Does this token inherit its sign from operands
}; };
/// \brief An edge in a data-flow path or graph /// \brief An edge in a data-flow path or graph

View file

@ -1152,9 +1152,11 @@ void PrintC::push_integer(uintb val,int4 sz,bool sign,
{ {
bool print_negsign; bool print_negsign;
bool force_unsigned_token; bool force_unsigned_token;
bool force_sized_token;
uint4 displayFormat = 0; uint4 displayFormat = 0;
force_unsigned_token = false; force_unsigned_token = false;
force_sized_token = false;
if ((vn != (const Varnode *)0)&&(!vn->isAnnotation())) { if ((vn != (const Varnode *)0)&&(!vn->isAnnotation())) {
Symbol *sym = vn->getHigh()->getSymbol(); Symbol *sym = vn->getHigh()->getSymbol();
if (sym != (Symbol *)0) { if (sym != (Symbol *)0) {
@ -1164,6 +1166,8 @@ void PrintC::push_integer(uintb val,int4 sz,bool sign,
} }
displayFormat = sym->getDisplayFormat(); displayFormat = sym->getDisplayFormat();
} }
force_unsigned_token = vn->isUnsignedPrint();
force_sized_token = vn->isLongPrint();
} }
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);
@ -1171,11 +1175,10 @@ void PrintC::push_integer(uintb val,int4 sz,bool sign,
print_negsign = (flip < val); print_negsign = (flip < val);
if (print_negsign) if (print_negsign)
val = flip+1; val = flip+1;
force_unsigned_token = false;
} }
else { else {
print_negsign = false; print_negsign = false;
if (vn != (const Varnode *)0)
force_unsigned_token = vn->isUnsignedPrint();
} }
// Figure whether to print as hex or decimal // Figure whether to print as hex or decimal
@ -1217,6 +1220,8 @@ void PrintC::push_integer(uintb val,int4 sz,bool sign,
} }
if (force_unsigned_token) if (force_unsigned_token)
t << 'U'; // Force unsignedness explicitly t << 'U'; // Force unsignedness explicitly
if (force_sized_token)
t << sizeSuffix;
if (vn==(const Varnode *)0) if (vn==(const Varnode *)0)
pushAtom(Atom(t.str(),syntax,EmitXml::const_color,op)); pushAtom(Atom(t.str(),syntax,EmitXml::const_color,op));
@ -2190,6 +2195,16 @@ void PrintC::resetDefaults(void)
resetDefaultsPrintC(); resetDefaultsPrintC();
} }
void PrintC::initializeFromArchitecture(void)
{
castStrategy->setTypeFactory(glb->types);
if (glb->types->getSizeOfLong() == glb->types->getSizeOfInt()) // If long and int sizes are the same
sizeSuffix = "LL"; // Use "long long" suffix to indicate large integer
else
sizeSuffix = "L"; // Otherwise just use long suffix
}
void PrintC::adjustTypeOperators(void) void PrintC::adjustTypeOperators(void)
{ {

View file

@ -121,6 +121,7 @@ protected:
bool option_unplaced; ///< Set to \b true if we should display unplaced comments bool option_unplaced; ///< Set to \b true if we should display unplaced comments
bool option_hide_exts; ///< Set to \b true if we should hide implied extension operations bool option_hide_exts; ///< Set to \b true if we should hide implied extension operations
string nullToken; ///< Token to use for 'null' string nullToken; ///< Token to use for 'null'
string sizeSuffix; ///< Characters to print to indicate a \e long integer token
CommentSorter commsorter; ///< Container/organizer for comments in the current function CommentSorter commsorter; ///< Container/organizer for comments in the current function
// Routines that are specific to C/C++ // Routines that are specific to C/C++
@ -210,6 +211,7 @@ public:
void setHideImpliedExts(bool val) { option_hide_exts = val; } ///< Toggle whether implied extensions are hidden void setHideImpliedExts(bool val) { option_hide_exts = val; } ///< Toggle whether implied extensions are hidden
virtual ~PrintC(void) {} virtual ~PrintC(void) {}
virtual void resetDefaults(void); virtual void resetDefaults(void);
virtual void initializeFromArchitecture(void);
virtual void adjustTypeOperators(void); virtual void adjustTypeOperators(void);
virtual void setCommentStyle(const string &nm); virtual void setCommentStyle(const string &nm);
virtual void docTypeDefinitions(const TypeFactory *typegrp); virtual void docTypeDefinitions(const TypeFactory *typegrp);

View file

@ -435,10 +435,11 @@ public:
void setXML(bool val); ///< Set whether the low-level emitter, emits XML markup void setXML(bool val); ///< Set whether the low-level emitter, emits XML markup
void setFlat(bool val); ///< Set whether nesting code structure should be emitted void setFlat(bool val); ///< Set whether nesting code structure should be emitted
virtual void adjustTypeOperators(void)=0; ///< Set basic data-type information for p-code operators virtual void initializeFromArchitecture(void)=0; ///< Initialize architecture specific aspects of printer
virtual void resetDefaults(void); ///< Set printing options to their default value virtual void adjustTypeOperators(void)=0; ///< Set basic data-type information for p-code operators
virtual void clear(void); ///< Clear the RPN stack and the low-level emitter virtual void resetDefaults(void); ///< Set printing options to their default value
virtual void setIntegerFormat(const string &nm); ///< Set the default integer format virtual void clear(void); ///< Clear the RPN stack and the low-level emitter
virtual void setIntegerFormat(const string &nm); ///< Set the default integer format
/// \brief Set the way comments are displayed in decompiler output /// \brief Set the way comments are displayed in decompiler output
/// ///

View file

@ -2308,6 +2308,7 @@ TypeFactory::TypeFactory(Architecture *g)
{ {
glb = g; glb = g;
sizeOfInt = 0; sizeOfInt = 0;
sizeOfLong = 0;
align = 0; align = 0;
enumsize = 0; enumsize = 0;
@ -2341,6 +2342,9 @@ void TypeFactory::setupSizes(void)
sizeOfInt = 4; sizeOfInt = 4;
} }
} }
if (sizeOfLong == 0) {
sizeOfLong = (sizeOfInt == 4) ? 8 : sizeOfInt;
}
if (align == 0) if (align == 0)
align = glb->getDefaultSize(); align = glb->getDefaultSize();
if (enumsize == 0) { if (enumsize == 0) {
@ -3271,6 +3275,7 @@ void TypeFactory::saveXml(ostream &s) const
dependentOrder(deporder); // Put types in correct order dependentOrder(deporder); // Put types in correct order
s << "<typegrp"; s << "<typegrp";
a_v_i(s,"intsize",sizeOfInt); a_v_i(s,"intsize",sizeOfInt);
a_v_i(s,"longsize",sizeOfLong);
a_v_i(s,"structalign",align); a_v_i(s,"structalign",align);
a_v_i(s,"enumsize",enumsize); a_v_i(s,"enumsize",enumsize);
a_v_b(s,"enumsigned",(enumtype==TYPE_INT)); a_v_b(s,"enumsigned",(enumtype==TYPE_INT));
@ -3573,6 +3578,9 @@ void TypeFactory::restoreXml(const Element *el)
istringstream i3(el->getAttributeValue("intsize")); istringstream i3(el->getAttributeValue("intsize"));
i3.unsetf(ios::dec | ios::hex | ios::oct); i3.unsetf(ios::dec | ios::hex | ios::oct);
i3 >> sizeOfInt; i3 >> sizeOfInt;
istringstream i4(el->getAttributeValue("longsize"));
i4.unsetf(ios::dec | ios::hex | ios::oct);
i4 >> sizeOfLong;
istringstream i(el->getAttributeValue("structalign")); istringstream i(el->getAttributeValue("structalign"));
i.unsetf(ios::dec | ios::hex | ios::oct); i.unsetf(ios::dec | ios::hex | ios::oct);
i >> align; i >> align;
@ -3621,6 +3629,11 @@ void TypeFactory::parseDataOrganization(const Element *el)
i.unsetf(ios::dec | ios::hex | ios::oct); i.unsetf(ios::dec | ios::hex | ios::oct);
i >> sizeOfInt; i >> sizeOfInt;
} }
else if (subel->getName() == "long_size") {
istringstream i(subel->getAttributeValue("value"));
i.unsetf(ios::dec | ios::hex | ios::oct);
i >> sizeOfLong;
}
else if (subel->getName() == "size_alignment_map") { else if (subel->getName() == "size_alignment_map") {
const List &childlist(subel->getChildren()); const List &childlist(subel->getChildren());
List::const_iterator iter2; List::const_iterator iter2;

View file

@ -534,6 +534,7 @@ public:
/// \brief Container class for all Datatype objects in an Architecture /// \brief Container class for all Datatype objects in an Architecture
class TypeFactory { class TypeFactory {
int4 sizeOfInt; ///< Size of the core "int" datatype int4 sizeOfInt; ///< Size of the core "int" datatype
int4 sizeOfLong; ///< Size of the core "long" datatype
int4 align; ///< Alignment of structures int4 align; ///< Alignment of structures
int4 enumsize; ///< Size of an enumerated type int4 enumsize; ///< Size of an enumerated type
type_metatype enumtype; ///< Default enumeration meta-type (when parsing C) type_metatype enumtype; ///< Default enumeration meta-type (when parsing C)
@ -570,6 +571,7 @@ public:
void setStructAlign(int4 al) { align = al; } ///< Set the default structure alignment void setStructAlign(int4 al) { align = al; } ///< Set the default structure alignment
int4 getStructAlign(void) const { return align; } ///< Get the default structure alignment int4 getStructAlign(void) const { return align; } ///< Get the default structure alignment
int4 getSizeOfInt(void) const { return sizeOfInt; } ///< Get the size of the default "int" int4 getSizeOfInt(void) const { return sizeOfInt; } ///< Get the size of the default "int"
int4 getSizeOfLong(void) const { return sizeOfLong; } ///< Get the size of the default "long"
Architecture *getArch(void) const { return glb; } ///< Get the Architecture object Architecture *getArch(void) const { return glb; } ///< Get the Architecture object
Datatype *findByName(const string &n); ///< Return type of given name Datatype *findByName(const string &n); ///< Return type of given name
Datatype *setName(Datatype *ct,const string &n); ///< Set the given types name Datatype *setName(Datatype *ct,const string &n); ///< Set the given types name

View file

@ -237,46 +237,6 @@ Datatype *TypeOp::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varn
return (Datatype *)0; // Don't propagate by default return (Datatype *)0; // Don't propagate by default
} }
/// Many languages can mark an integer constant as explicitly \e unsigned. When
/// the decompiler is deciding on \e cast operations, this is one of the checks
/// it performs. This method checks if the indicated input is an
/// integer constant that needs to be coerced (as a source token) into being unsigned.
/// If this is \b true, the input Varnode is marked for printing as explicitly \e unsigned.
/// \param op is the PcodeOp taking the value as input
/// \param slot is the input slot of the value
/// \return \b true if the Varnode gets marked for printing
bool TypeOp::markExplicitUnsigned(PcodeOp *op,int4 slot) const
{
if ((addlflags & inherits_sign)==0) return false;
if ((slot==1) && ((addlflags & inherits_sign_zero)!=0)) return false;
Varnode *vn = op->getIn(slot);
if (!vn->isConstant()) return false;
Datatype *dt = vn->getHighTypeReadFacing(op);
type_metatype meta = dt->getMetatype();
if ((meta != TYPE_UINT)&&(meta != TYPE_UNKNOWN)) return false;
if (dt->isCharPrint()) return false;
if (dt->isEnumType()) return false;
if ((op->numInput() == 2) && ((addlflags & inherits_sign_zero)==0)) {
Varnode *firstvn = op->getIn(1-slot);
meta = firstvn->getHighTypeReadFacing(op)->getMetatype();
if ((meta == TYPE_UINT)||(meta == TYPE_UNKNOWN))
return false; // Other side of the operation will force the unsigned
}
// Check if type is going to get forced anyway
Varnode *outvn = op->getOut();
if (outvn != (Varnode *)0) {
if (outvn->isExplicit()) return false;
PcodeOp *lone = outvn->loneDescend();
if (lone != (PcodeOp *)0) {
if (!lone->inheritsSign()) return false;
}
}
vn->setUnsignedPrint();
return true;
}
Datatype *TypeOpBinary::getOutputLocal(const PcodeOp *op) const Datatype *TypeOpBinary::getOutputLocal(const PcodeOp *op) const
{ {
@ -1462,7 +1422,7 @@ TypeOpIntLeft::TypeOpIntLeft(TypeFactory *t)
: TypeOpBinary(t,CPUI_INT_LEFT,"<<",TYPE_INT,TYPE_INT) : TypeOpBinary(t,CPUI_INT_LEFT,"<<",TYPE_INT,TYPE_INT)
{ {
opflags = PcodeOp::binary; opflags = PcodeOp::binary;
addlflags = inherits_sign | inherits_sign_zero; addlflags = inherits_sign | inherits_sign_zero | shift_op;
behave = new OpBehaviorIntLeft(); behave = new OpBehaviorIntLeft();
} }
@ -1487,7 +1447,7 @@ TypeOpIntRight::TypeOpIntRight(TypeFactory *t)
: TypeOpBinary(t,CPUI_INT_RIGHT,">>",TYPE_UINT,TYPE_UINT) : TypeOpBinary(t,CPUI_INT_RIGHT,">>",TYPE_UINT,TYPE_UINT)
{ {
opflags = PcodeOp::binary; opflags = PcodeOp::binary;
addlflags = inherits_sign | inherits_sign_zero; addlflags = inherits_sign | inherits_sign_zero | shift_op;
behave = new OpBehaviorIntRight(); behave = new OpBehaviorIntRight();
} }
@ -1527,7 +1487,7 @@ TypeOpIntSright::TypeOpIntSright(TypeFactory *t)
: TypeOpBinary(t,CPUI_INT_SRIGHT,">>",TYPE_INT,TYPE_INT) : TypeOpBinary(t,CPUI_INT_SRIGHT,">>",TYPE_INT,TYPE_INT)
{ {
opflags = PcodeOp::binary; opflags = PcodeOp::binary;
addlflags = inherits_sign | inherits_sign_zero; addlflags = inherits_sign | inherits_sign_zero | shift_op;
behave = new OpBehaviorIntSright(); behave = new OpBehaviorIntSright();
} }

View file

@ -38,7 +38,8 @@ class TypeOp {
public: public:
enum { enum {
inherits_sign = 1, ///< Operator token inherits signedness from its inputs inherits_sign = 1, ///< Operator token inherits signedness from its inputs
inherits_sign_zero = 2 ///< Only inherits sign from first operand, not the second inherits_sign_zero = 2, ///< Only inherits sign from first operand, not the second
shift_op = 4 ///< Shift operation
}; };
protected: protected:
TypeFactory *tlst; ///< Pointer to data-type factory TypeFactory *tlst; ///< Pointer to data-type factory
@ -57,7 +58,6 @@ public:
OpCode getOpcode(void) const { return opcode; } ///< Get the op-code value OpCode getOpcode(void) const { return opcode; } ///< Get the op-code value
uint4 getFlags(void) const { return opflags; } ///< Get the properties associated with the op-code uint4 getFlags(void) const { return opflags; } ///< Get the properties associated with the op-code
OpBehavior *getBehavior(void) const { return behave; } ///< Get the behavior associated with the op-code OpBehavior *getBehavior(void) const { return behave; } ///< Get the behavior associated with the op-code
bool markExplicitUnsigned(PcodeOp *op,int4 slot) const; ///< Check if a constant input should be explicitly labeled as \e unsigned
/// \brief Emulate the unary op-code on an input value /// \brief Emulate the unary op-code on an input value
/// ///
@ -103,9 +103,15 @@ public:
bool isCommutative(void) const; ///< Return \b true if this op-code is commutative bool isCommutative(void) const; ///< Return \b true if this op-code is commutative
/// \brief Return \b true if the op-code inherits it signedness from its inputs /// \brief Return \b true if the op-code inherits its signedness from its inputs
bool inheritsSign(void) const { return ((addlflags & inherits_sign)!=0); } bool inheritsSign(void) const { return ((addlflags & inherits_sign)!=0); }
/// \brief Return \b true if the op-code inherits its signedness from only its first input
bool inheritsSignFirstParamOnly(void) const { return ((addlflags & inherits_sign_zero)!=0); }
/// \brief Return \b true if the op-code is a shift (INT_LEFT, INT_RIGHT, or INT_SRIGHT)
bool isShiftOp(void) const { return ((addlflags & shift_op)!=0); }
/// \brief Find the minimal (or suggested) data-type of an output to \b this op-code /// \brief Find the minimal (or suggested) data-type of an output to \b this op-code
virtual Datatype *getOutputLocal(const PcodeOp *op) const; virtual Datatype *getOutputLocal(const PcodeOp *op) const;

View file

@ -113,13 +113,14 @@ public:
lisconsume = 0x08, ///< In consume worklist lisconsume = 0x08, ///< In consume worklist
ptrcheck = 0x10, ///< The Varnode value is \e NOT a pointer ptrcheck = 0x10, ///< The Varnode value is \e NOT a pointer
ptrflow = 0x20, ///< If this varnode flows to or from a pointer ptrflow = 0x20, ///< If this varnode flows to or from a pointer
unsignedprint = 0x40, ///< Constant that must be explicitly printed as unsigned unsignedprint = 0x40, ///< Constant that must be explicitly printed as an unsigned token
stack_store = 0x80, ///< Created by an explicit STORE longprint = 0x80, ///< Constant that must be explicitly printed as a \e long integer token
locked_input = 0x100, ///< Input that exists even if its unused stack_store = 0x100, ///< Created by an explicit STORE
spacebase_placeholder = 0x200, ///< This varnode is inserted artificially to track a register locked_input = 0x200, ///< Input that exists even if its unused
spacebase_placeholder = 0x400, ///< This varnode is inserted artificially to track a register
///< value at a specific point in the code ///< value at a specific point in the code
stop_uppropagation = 0x400, ///< Data-types do not propagate from an output into \b this stop_uppropagation = 0x800, ///< Data-types do not propagate from an output into \b this
has_implied_field = 0x800 ///< The varnode is implied but also has a data-type that needs resolution has_implied_field = 0x1000 ///< The varnode is implied but also has a data-type that needs resolution
}; };
private: private:
mutable uint4 flags; ///< The collection of boolean attributes for this Varnode mutable uint4 flags; ///< The collection of boolean attributes for this Varnode
@ -262,6 +263,7 @@ public:
bool isIncidentalCopy(void) const { return ((flags&Varnode::incidental_copy)!=0); } ///< Does this varnode get copied as a side-effect bool isIncidentalCopy(void) const { return ((flags&Varnode::incidental_copy)!=0); } ///< Does this varnode get copied as a side-effect
bool isWriteMask(void) const { return ((addlflags&Varnode::writemask)!=0); } ///< Is \b this (not) considered a true write location when calculating SSA form? bool isWriteMask(void) const { return ((addlflags&Varnode::writemask)!=0); } ///< Is \b this (not) considered a true write location when calculating SSA form?
bool isUnsignedPrint(void) const { return ((addlflags&Varnode::unsignedprint)!=0); } ///< Must \b this be printed as unsigned bool isUnsignedPrint(void) const { return ((addlflags&Varnode::unsignedprint)!=0); } ///< Must \b this be printed as unsigned
bool isLongPrint(void) const { return ((addlflags&Varnode::longprint)!=0); } ///< Must \b this be printed as a \e long token
bool isWritten(void) const { return ((flags&Varnode::written)!=0); } ///< Does \b this have a defining write operation? bool isWritten(void) const { return ((flags&Varnode::written)!=0); } ///< Does \b this have a defining write operation?
/// Does \b this have Cover information? /// Does \b this have Cover information?
@ -309,6 +311,7 @@ public:
void setAutoLiveHold(void) { flags |= Varnode::autolive_hold; } ///< Place temporary hold on dead code removal void setAutoLiveHold(void) { flags |= Varnode::autolive_hold; } ///< Place temporary hold on dead code removal
void clearAutoLiveHold(void) { flags &= ~Varnode::autolive_hold; } ///< Clear temporary hold on dead code removal void clearAutoLiveHold(void) { flags &= ~Varnode::autolive_hold; } ///< Clear temporary hold on dead code removal
void setUnsignedPrint(void) { addlflags |= Varnode::unsignedprint; } ///< Force \b this to be printed as unsigned void setUnsignedPrint(void) { addlflags |= Varnode::unsignedprint; } ///< Force \b this to be printed as unsigned
void setLongPrint(void) { addlflags |= Varnode::longprint; } ///< Force \b this to be printed as a \e long token
void setStopUpPropagation(void) { addlflags |= Varnode::stop_uppropagation; } ///< Stop up-propagation thru \b this void setStopUpPropagation(void) { addlflags |= Varnode::stop_uppropagation; } ///< Stop up-propagation thru \b this
void clearStopUpPropagation(void) { addlflags &= ~Varnode::stop_uppropagation; } ///< Stop up-propagation thru \b this void clearStopUpPropagation(void) { addlflags &= ~Varnode::stop_uppropagation; } ///< Stop up-propagation thru \b this
void setImpliedField(void) { addlflags |= Varnode::has_implied_field; } ///< Mark \this as having an implied field void setImpliedField(void) { addlflags |= Varnode::has_implied_field; } ///< Mark \this as having an implied field

View file

@ -99,6 +99,23 @@ bool castPrinted(OpCode opc,Datatype *t1,Datatype *t2) {
return (inst->getInputCast(op, 0, strategy) != (Datatype *)0); return (inst->getInputCast(op, 0, strategy) != (Datatype *)0);
} }
bool longPrinted(OpCode opc,Datatype *t1,uintb val)
{
PcodeOp *op;
Address addr(glb->getDefaultCodeSpace(),0x1000);
op = dummyFunc->newOp(2, addr);
Datatype *sa = glb->types->getBase(4,TYPE_INT);
Varnode *vn1 = dummyFunc->newConstant(t1->getSize(), val);
vn1->updateType(t1, false, true);
Varnode *vn2 = dummyFunc->newUnique(sa->getSize(), sa);
dummyFunc->opSetOpcode(op, opc);
dummyFunc->opSetInput(op, vn1, 0);
dummyFunc->opSetInput(op, vn2, 1);
dummyFunc->newUniqueOut(vn1->getSize(), op);
return glb->print->getCastStrategy()->markExplicitLongSize(op, 0);
}
TEST(cast_basic) { TEST(cast_basic) {
TypeTestEnvironment::build(); TypeTestEnvironment::build();
ASSERT(castPrinted(CPUI_COPY,parse("int4"),parse("int2"))); ASSERT(castPrinted(CPUI_COPY,parse("int4"),parse("int2")));
@ -181,3 +198,14 @@ TEST(type_ordering) {
ASSERT(parse("int4 *")->compare(*parse("void *"),10) < 0); ASSERT(parse("int4 *")->compare(*parse("void *"),10) < 0);
ASSERT(parse("int2 *")->compare(*parse("xunknown2 *"),10) < 0); ASSERT(parse("int2 *")->compare(*parse("xunknown2 *"),10) < 0);
} }
TEST(cast_integertoken) {
TypeTestEnvironment::build();
ASSERT(longPrinted(CPUI_INT_LEFT,parse("int8"),10));
ASSERT(!longPrinted(CPUI_INT_LEFT,parse("int8"),0x100000000));
ASSERT(longPrinted(CPUI_INT_SRIGHT,parse("int8"),-3));
ASSERT(!longPrinted(CPUI_INT_SRIGHT,parse("int8"),0xffffffff7fffffff));
ASSERT(longPrinted(CPUI_INT_SRIGHT,parse("int8"),0xffffffff80000000));
ASSERT(longPrinted(CPUI_INT_RIGHT,parse("uint8"),0xffffffff));
ASSERT(!longPrinted(CPUI_INT_RIGHT,parse("uint8"),0x100000000));
}

View file

@ -26,8 +26,7 @@ import ghidra.app.plugin.processors.sleigh.symbol.ContextSymbol;
import ghidra.app.plugin.processors.sleigh.symbol.Symbol; import ghidra.app.plugin.processors.sleigh.symbol.Symbol;
import ghidra.app.util.DataTypeDependencyOrderer; import ghidra.app.util.DataTypeDependencyOrderer;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.data.BuiltIn; import ghidra.program.model.data.*;
import ghidra.program.model.data.DataType;
import ghidra.program.model.lang.*; import ghidra.program.model.lang.*;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
import ghidra.program.model.mem.MemoryAccessException; import ghidra.program.model.mem.MemoryAccessException;
@ -327,10 +326,13 @@ public class DecompileDebug {
} }
private void dumpDataTypes(OutputStream debugStream) throws IOException { private void dumpDataTypes(OutputStream debugStream) throws IOException {
int intSize = program.getCompilerSpec().getDataOrganization().getIntegerSize(); DataOrganization dataOrganization = program.getCompilerSpec().getDataOrganization();
int intSize = dataOrganization.getIntegerSize();
int longSize = dataOrganization.getLongSize();
StringBuilder buf = new StringBuilder(); StringBuilder buf = new StringBuilder();
buf.append("<typegrp"); buf.append("<typegrp");
SpecXmlUtils.encodeSignedIntegerAttribute(buf, "intsize", intSize); SpecXmlUtils.encodeSignedIntegerAttribute(buf, "intsize", intSize);
SpecXmlUtils.encodeSignedIntegerAttribute(buf, "longsize", longSize);
SpecXmlUtils.encodeSignedIntegerAttribute(buf, "structalign", 4); SpecXmlUtils.encodeSignedIntegerAttribute(buf, "structalign", 4);
SpecXmlUtils.encodeSignedIntegerAttribute(buf, "enumsize", 4); SpecXmlUtils.encodeSignedIntegerAttribute(buf, "enumsize", 4);
SpecXmlUtils.encodeBooleanAttribute(buf, "enumsigned", false); SpecXmlUtils.encodeBooleanAttribute(buf, "enumsigned", false);