diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc index a583368dce..0decce3481 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc @@ -372,7 +372,7 @@ void Architecture::setPrintLanguage(const string &nm) ostream *t = print->getOutputStream(); print = capa->buildLanguage(this); print->setOutputStream(t); // Restore settings from previous language - print->getCastStrategy()->setTypeFactory(types); + print->initializeFromArchitecture(); if (printxml) print->setXML(true); printlist.push_back(print); @@ -1342,7 +1342,7 @@ void Architecture::init(DocumentStorage &store) buildDatabase(store); restoreFromSpec(store); - print->getCastStrategy()->setTypeFactory(types); + print->initializeFromArchitecture(); symboltab->adjustCaches(); // In case the specs created additional address spaces postSpecFile(); // Let subclasses do things after translate is ready diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/cast.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/cast.cc index 86429db85b..dc8baa764e 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/cast.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/cast.cc @@ -25,6 +25,80 @@ void CastStrategy::setTypeFactory(TypeFactory *t) 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 { diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/cast.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/cast.hh index c4b1c2d3c7..86d3bfd5c8 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/cast.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/cast.hh @@ -153,6 +153,12 @@ public: /// \param intype is the input data-type /// \return \b true if the INT_ZEXT should be represented as a cast 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 diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc index b1a3c0304f..3c90de4263 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc @@ -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 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 0; } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/op.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/op.hh index 57bb99b411..6029b040a1 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/op.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/op.hh @@ -231,8 +231,6 @@ public: 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 - 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 diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc index 161c07ad5b..be166a5708 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc @@ -1152,9 +1152,11 @@ void PrintC::push_integer(uintb val,int4 sz,bool sign, { bool print_negsign; bool force_unsigned_token; + bool force_sized_token; uint4 displayFormat = 0; force_unsigned_token = false; + force_sized_token = false; if ((vn != (const Varnode *)0)&&(!vn->isAnnotation())) { Symbol *sym = vn->getHigh()->getSymbol(); if (sym != (Symbol *)0) { @@ -1164,6 +1166,8 @@ void PrintC::push_integer(uintb val,int4 sz,bool sign, } displayFormat = sym->getDisplayFormat(); } + force_unsigned_token = vn->isUnsignedPrint(); + force_sized_token = vn->isLongPrint(); } if (sign && displayFormat != Symbol::force_char) { // Print the constant as signed uintb mask = calc_mask(sz); @@ -1171,11 +1175,10 @@ void PrintC::push_integer(uintb val,int4 sz,bool sign, print_negsign = (flip < val); if (print_negsign) val = flip+1; + force_unsigned_token = false; } else { print_negsign = false; - if (vn != (const Varnode *)0) - force_unsigned_token = vn->isUnsignedPrint(); } // 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) t << 'U'; // Force unsignedness explicitly + if (force_sized_token) + t << sizeSuffix; if (vn==(const Varnode *)0) pushAtom(Atom(t.str(),syntax,EmitXml::const_color,op)); @@ -2190,6 +2195,16 @@ void PrintC::resetDefaults(void) 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) { diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh index 9f5c67a22c..4796c9dac1 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh @@ -121,6 +121,7 @@ protected: 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 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 // 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 virtual ~PrintC(void) {} virtual void resetDefaults(void); + virtual void initializeFromArchitecture(void); virtual void adjustTypeOperators(void); virtual void setCommentStyle(const string &nm); virtual void docTypeDefinitions(const TypeFactory *typegrp); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/printlanguage.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/printlanguage.hh index 93c1de1d45..00dedad198 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/printlanguage.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/printlanguage.hh @@ -435,10 +435,11 @@ public: 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 - virtual void adjustTypeOperators(void)=0; ///< Set basic data-type information for p-code operators - virtual void resetDefaults(void); ///< Set printing options to their default value - virtual void clear(void); ///< Clear the RPN stack and the low-level emitter - virtual void setIntegerFormat(const string &nm); ///< Set the default integer format + virtual void initializeFromArchitecture(void)=0; ///< Initialize architecture specific aspects of printer + virtual void adjustTypeOperators(void)=0; ///< Set basic data-type information for p-code operators + virtual void resetDefaults(void); ///< Set printing options to their default value + 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 /// diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc index a84da67820..4517d9fb1e 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc @@ -2308,6 +2308,7 @@ TypeFactory::TypeFactory(Architecture *g) { glb = g; sizeOfInt = 0; + sizeOfLong = 0; align = 0; enumsize = 0; @@ -2341,6 +2342,9 @@ void TypeFactory::setupSizes(void) sizeOfInt = 4; } } + if (sizeOfLong == 0) { + sizeOfLong = (sizeOfInt == 4) ? 8 : sizeOfInt; + } if (align == 0) align = glb->getDefaultSize(); if (enumsize == 0) { @@ -3271,6 +3275,7 @@ void TypeFactory::saveXml(ostream &s) const dependentOrder(deporder); // Put types in correct order s << "getAttributeValue("intsize")); i3.unsetf(ios::dec | ios::hex | ios::oct); i3 >> sizeOfInt; + istringstream i4(el->getAttributeValue("longsize")); + i4.unsetf(ios::dec | ios::hex | ios::oct); + i4 >> sizeOfLong; istringstream i(el->getAttributeValue("structalign")); i.unsetf(ios::dec | ios::hex | ios::oct); i >> align; @@ -3621,6 +3629,11 @@ void TypeFactory::parseDataOrganization(const Element *el) i.unsetf(ios::dec | ios::hex | ios::oct); 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") { const List &childlist(subel->getChildren()); List::const_iterator iter2; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/type.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/type.hh index 998c38743b..dd75efe83e 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/type.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/type.hh @@ -534,6 +534,7 @@ public: /// \brief Container class for all Datatype objects in an Architecture class TypeFactory { int4 sizeOfInt; ///< Size of the core "int" datatype + int4 sizeOfLong; ///< Size of the core "long" datatype int4 align; ///< Alignment of structures int4 enumsize; ///< Size of an enumerated type 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 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 getSizeOfLong(void) const { return sizeOfLong; } ///< Get the size of the default "long" Architecture *getArch(void) const { return glb; } ///< Get the Architecture object Datatype *findByName(const string &n); ///< Return type of given name Datatype *setName(Datatype *ct,const string &n); ///< Set the given types name diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.cc index 016be7b88e..b904264b0f 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.cc @@ -237,46 +237,6 @@ Datatype *TypeOp::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varn 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 { @@ -1462,7 +1422,7 @@ TypeOpIntLeft::TypeOpIntLeft(TypeFactory *t) : TypeOpBinary(t,CPUI_INT_LEFT,"<<",TYPE_INT,TYPE_INT) { opflags = PcodeOp::binary; - addlflags = inherits_sign | inherits_sign_zero; + addlflags = inherits_sign | inherits_sign_zero | shift_op; behave = new OpBehaviorIntLeft(); } @@ -1487,7 +1447,7 @@ TypeOpIntRight::TypeOpIntRight(TypeFactory *t) : TypeOpBinary(t,CPUI_INT_RIGHT,">>",TYPE_UINT,TYPE_UINT) { opflags = PcodeOp::binary; - addlflags = inherits_sign | inherits_sign_zero; + addlflags = inherits_sign | inherits_sign_zero | shift_op; behave = new OpBehaviorIntRight(); } @@ -1527,7 +1487,7 @@ TypeOpIntSright::TypeOpIntSright(TypeFactory *t) : TypeOpBinary(t,CPUI_INT_SRIGHT,">>",TYPE_INT,TYPE_INT) { opflags = PcodeOp::binary; - addlflags = inherits_sign | inherits_sign_zero; + addlflags = inherits_sign | inherits_sign_zero | shift_op; behave = new OpBehaviorIntSright(); } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.hh index e5206355b0..f8976eb5ee 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.hh @@ -38,7 +38,8 @@ class TypeOp { public: enum { 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: TypeFactory *tlst; ///< Pointer to data-type factory @@ -57,7 +58,6 @@ public: 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 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 /// @@ -103,9 +103,15 @@ public: 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); } + /// \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 virtual Datatype *getOutputLocal(const PcodeOp *op) const; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/varnode.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/varnode.hh index bffc500eb5..452b8b3240 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/varnode.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/varnode.hh @@ -113,13 +113,14 @@ public: lisconsume = 0x08, ///< In consume worklist ptrcheck = 0x10, ///< The Varnode value is \e NOT a pointer ptrflow = 0x20, ///< If this varnode flows to or from a pointer - unsignedprint = 0x40, ///< Constant that must be explicitly printed as unsigned - stack_store = 0x80, ///< Created by an explicit STORE - locked_input = 0x100, ///< Input that exists even if its unused - spacebase_placeholder = 0x200, ///< This varnode is inserted artificially to track a register + unsignedprint = 0x40, ///< Constant that must be explicitly printed as an unsigned token + longprint = 0x80, ///< Constant that must be explicitly printed as a \e long integer token + stack_store = 0x100, ///< Created by an explicit STORE + 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 - stop_uppropagation = 0x400, ///< 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 + stop_uppropagation = 0x800, ///< Data-types do not propagate from an output into \b this + has_implied_field = 0x1000 ///< The varnode is implied but also has a data-type that needs resolution }; private: 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 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 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? /// 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 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 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 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 diff --git a/Ghidra/Features/Decompiler/src/decompile/unittests/testtypes.cc b/Ghidra/Features/Decompiler/src/decompile/unittests/testtypes.cc index 267ec781d5..81b1b7f669 100644 --- a/Ghidra/Features/Decompiler/src/decompile/unittests/testtypes.cc +++ b/Ghidra/Features/Decompiler/src/decompile/unittests/testtypes.cc @@ -99,6 +99,23 @@ bool castPrinted(OpCode opc,Datatype *t1,Datatype *t2) { 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) { TypeTestEnvironment::build(); 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("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)); +} diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileDebug.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileDebug.java index d3389c0fb8..7d4eed2806 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileDebug.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileDebug.java @@ -26,8 +26,7 @@ import ghidra.app.plugin.processors.sleigh.symbol.ContextSymbol; import ghidra.app.plugin.processors.sleigh.symbol.Symbol; import ghidra.app.util.DataTypeDependencyOrderer; import ghidra.program.model.address.*; -import ghidra.program.model.data.BuiltIn; -import ghidra.program.model.data.DataType; +import ghidra.program.model.data.*; import ghidra.program.model.lang.*; import ghidra.program.model.listing.*; import ghidra.program.model.mem.MemoryAccessException; @@ -327,10 +326,13 @@ public class DecompileDebug { } 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(); buf.append("