diff --git a/Ghidra/Features/Decompiler/certification.manifest b/Ghidra/Features/Decompiler/certification.manifest index 9aab00555b..67a824a71d 100644 --- a/Ghidra/Features/Decompiler/certification.manifest +++ b/Ghidra/Features/Decompiler/certification.manifest @@ -31,6 +31,7 @@ src/decompile/datatests/forloop_withskip.xml||GHIDRA||||END| src/decompile/datatests/impliedfield.xml||GHIDRA||||END| src/decompile/datatests/indproto.xml||GHIDRA||||END| src/decompile/datatests/injectoverride.xml||GHIDRA||||END| +src/decompile/datatests/longdouble.xml||GHIDRA||||END| src/decompile/datatests/loopcomment.xml||GHIDRA||||END| src/decompile/datatests/lzcount.xml||GHIDRA||||END| src/decompile/datatests/mixfloatint.xml||GHIDRA||||END| diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc index f03793f014..d4276a8a0e 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.cc @@ -1380,6 +1380,7 @@ void Architecture::init(DocumentStorage &store) buildDatabase(store); restoreFromSpec(store); + buildCoreTypes(store); print->initializeFromArchitecture(); symboltab->adjustCaches(); // In case the specs created additional address spaces buildSymbols(store); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.hh index a7e6af010a..2fe3aed26a 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/architecture.hh @@ -285,11 +285,16 @@ protected: /// \brief Build the data-type factory/container /// /// Build the TypeFactory object specific to \b this Architecture and - /// prepopulate it with the \e core types. Core types may be pulled - /// from the configuration information, or default core types are used. + /// prepopulate it with the \e core types. /// \param store contains possible configuration information virtual void buildTypegrp(DocumentStorage &store)=0; + /// \brief Add core primitive data-types + /// + /// Core types may be pulled from the configuration information, or default core types are used. + /// \param store contains possible configuration information + virtual void buildCoreTypes(DocumentStorage &store)=0; + /// \brief Build the comment database /// /// Build the container that holds comments in \b this Architecture. diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/block.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/block.hh index 102a9a7840..0041d0f710 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/block.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/block.hh @@ -163,37 +163,109 @@ public: FlowBlock *getCopyMap(void) const { return copymap; } ///< Get the mapped FlowBlock const FlowBlock *getParent(void) const { return (const FlowBlock *) parent; } ///< Get the parent FlowBlock of \b this uint4 getFlags(void) const { return flags; } ///< Get the block_flags properties - virtual Address getStart(void) const { return Address(); } ///< Get the starting address of code in \b this FlowBlock - virtual Address getStop(void) const { return Address(); } ///< Get the ending address of code in \b this FlowBlock - virtual block_type getType(void) const { return t_plain; } ///< Get the FlowBlock type of \b this - virtual FlowBlock *subBlock(int4 i) const { return (FlowBlock *)0; } ///< Get the i-th component block - virtual void markUnstructured(void) {} ///< Mark target blocks of any unstructured edges + + /// \brief Get the starting address of code in \b this FlowBlock + /// + /// If \b this is a basic block, the first address of (the original) instructions in the block + /// is returned. Otherwise, an \e invalid address is returned. + /// \return the starting address or an \e invalid address + virtual Address getStart(void) const { return Address(); } + + /// \brief Get the ending address of code in \b this FlowBlock + /// + /// If \b this is a basic block, the last address of (the original) instructions in the block + /// is returned. Otherwise, an \e invalid address is returned. + /// \return the starting address or an \e invalid address + virtual Address getStop(void) const { return Address(); } + + /// \brief Get the FlowBlock type of \b this + /// + /// \return one of the enumerated block types + virtual block_type getType(void) const { return t_plain; } + + /// \brief Get the i-th component block + /// + /// \param i is the index of the component block + /// \return the specified component block + virtual FlowBlock *subBlock(int4 i) const { return (FlowBlock *)0; } + + /// \brief Mark target blocks of any unstructured edges + virtual void markUnstructured(void) {} + virtual void markLabelBumpUp(bool bump); ///< Let hierarchical blocks steal labels of their (first) components - virtual void scopeBreak(int4 curexit,int4 curloopexit) {} ///< Mark unstructured edges that should be \e breaks + + /// \brief Mark unstructured edges that should be \e breaks + /// + /// \param curexit is the index of the (fall-thru) exit block for \b this block, or -1 for no fall-thru + /// \param curloopexit is the index of the exit block of the containing loop, or -1 for no containing loop + virtual void scopeBreak(int4 curexit,int4 curloopexit) {} + virtual void printHeader(ostream &s) const; ///< Print a simple description of \b this to stream virtual void printTree(ostream &s,int4 level) const; ///< Print tree structure of any blocks owned by \b this - virtual void printRaw(ostream &s) const {} ///< Print raw instructions contained in \b this FlowBlock + + /// \brief Print raw instructions contained in \b this FlowBlock + /// + /// A text representation of the control-flow and instructions contained in \b this block is + /// emitted to the given stream. + /// \param s is the given stream to write to + virtual void printRaw(ostream &s) const {} + virtual void emit(PrintLanguage *lng) const; /// &fliplist) const; virtual void flipInPlaceExecute(void); - virtual bool isComplex(void) const { return true; } ///< Is \b this too complex to be a condition (BlockCondition) + + /// \brief Is \b this too complex to be a condition (BlockCondition) + /// + /// \return \b false if the whole block can be emitted as a conditional clause + virtual bool isComplex(void) const { return true; } + virtual FlowBlock *nextFlowAfter(const FlowBlock *bl) const; - virtual void finalTransform(Funcdata &data) {} ///< Do any structure driven final transforms - virtual void finalizePrinting(Funcdata &data) const {} ///< Make any final configurations necessary to print the block + + /// \brief Do any structure driven final transforms + /// + /// \param data is the function to transform + virtual void finalTransform(Funcdata &data) {} + + /// \brief Make any final configurations necessary to emit the block + /// + /// \param data is the function to finalize + virtual void finalizePrinting(Funcdata &data) const {} + virtual void encodeHeader(Encoder &encoder) const; ///< Encode basic information as attributes virtual void decodeHeader(Decoder &decoder); ///< Decode basic information from element attributes - virtual void encodeBody(Encoder &encoder) const {} ///< Encode detail about components to a stream + + /// \brief Encode detail about \b this block and its components to a stream + /// + /// \param encoder is the stream encoder + virtual void encodeBody(Encoder &encoder) const {} /// \brief Restore details about \b this FlowBlock from an element stream /// /// \param decoder is the stream decoder virtual void decodeBody(Decoder &decoder) {} + void encodeEdges(Encoder &encoder) const; ///< Encode edge information to a stream void decodeEdges(Decoder &decoder,BlockMap &resolver); void encode(Encoder &encoder) const; ///< Encode \b this to a stream diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc index 208ca7fc7d..c814cccd7d 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc @@ -2681,7 +2681,7 @@ int4 ActionSetCasts::apply(Funcdata &data) if (opc == CPUI_PTRADD) { // Check for PTRADD that no longer fits its pointer int4 sz = (int4)op->getIn(2)->getOffset(); TypePointer *ct = (TypePointer *)op->getIn(0)->getHighTypeReadFacing(op); - if ((ct->getMetatype() != TYPE_PTR)||(ct->getPtrTo()->getSize() != AddrSpace::addressToByteInt(sz, ct->getWordSize()))) + if ((ct->getMetatype() != TYPE_PTR)||(ct->getPtrTo()->getAlignSize() != AddrSpace::addressToByteInt(sz, ct->getWordSize()))) data.opUndoPtradd(op,true); } else if (opc == CPUI_PTRSUB) { // Check for PTRSUB that no longer fits pointer diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/double.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/double.cc index 3f923b6505..ff11d1e20c 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/double.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/double.cc @@ -3324,9 +3324,23 @@ int4 RuleDoubleLoad::applyOp(PcodeOp *op,Funcdata &data) Varnode *piece1 = op->getIn(1); if (!piece0->isWritten()) return 0; if (!piece1->isWritten()) return 0; - if (piece0->getDef()->code() != CPUI_LOAD) return false; - if (piece1->getDef()->code() != CPUI_LOAD) return false; - if (!SplitVarnode::testContiguousPointers(piece0->getDef(),piece1->getDef(),loadlo,loadhi,spc)) + PcodeOp *load1 = piece1->getDef(); + if (load1->code() != CPUI_LOAD) return false; + PcodeOp *load0 = piece0->getDef(); + OpCode opc = load0->code(); + int4 offset = 0; + if (opc == CPUI_SUBPIECE) { + // Check for 2 LOADs but most significant part of most significant LOAD is discarded + if (load0->getIn(1)->getOffset() != 0) return false; + Varnode *vn0 = load0->getIn(0); + if (!vn0->isWritten()) return false; + offset = vn0->getSize() - piece0->getSize(); + load0 = vn0->getDef(); + opc = load0->code(); + } + if (opc != CPUI_LOAD) + return false; + if (!SplitVarnode::testContiguousPointers(load0,load1,loadlo,loadhi,spc)) return 0; size = piece0->getSize() + piece1->getSize(); @@ -3340,8 +3354,17 @@ int4 RuleDoubleLoad::applyOp(PcodeOp *op,Funcdata &data) data.opSetOpcode(newload,CPUI_LOAD); data.opSetInput(newload,spcvn,0); Varnode *addrvn = loadlo->getIn(1); - if (addrvn->isConstant()) - addrvn = data.newConstant(addrvn->getSize(),addrvn->getOffset()); + if (spc->isBigEndian() && offset != 0) { + // If the most significant part of LOAD is discarded, we need to add discard amount to pointer + PcodeOp *newadd = data.newOp(2,latest->getAddr()); + Varnode *addout = data.newUniqueOut(addrvn->getSize(),newadd); + data.opSetOpcode(newadd,CPUI_INT_ADD); + data.opSetInput(newadd,addrvn,0); + data.opSetInput(newadd,data.newConstant(addrvn->getSize(), offset),1); + data.opInsertAfter(newadd,latest); + addrvn = addout; + latest = newadd; + } data.opSetInput(newload,addrvn,1); // We need to guarantee that -newload- reads -addrvn- after // it has been defined. So insert it after the latest. diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.cc index 82771cc040..73798c8839 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.cc @@ -410,8 +410,9 @@ int4 ParamEntry::getSlot(const Address &addr,int4 skip) const /// Return an invalid address if the size is too small or if there are not enough slots left. /// \param slotnum is a reference to used slots (which will be updated) /// \param sz is the size of the parameter to allocated +/// \param typeAlign is the required byte alignment for the parameter /// \return the address of the new parameter (or an invalid address) -Address ParamEntry::getAddrBySlot(int4 &slotnum,int4 sz) const +Address ParamEntry::getAddrBySlot(int4 &slotnum,int4 sz,int4 typeAlign) const { Address res; // Start with an invalid result @@ -429,6 +430,11 @@ Address ParamEntry::getAddrBySlot(int4 &slotnum,int4 sz) const } } else { + if (typeAlign > alignment) { + int4 tmp = (slotnum * alignment) % typeAlign; + if (tmp != 0) + slotnum += (typeAlign - tmp) / alignment; // Waste slots to achieve typeAlign + } int4 slotsused = sz / alignment; // How many slots does a -sz- byte object need if ( (sz % alignment) != 0) slotsused += 1; @@ -657,7 +663,7 @@ Address ParamListStandard::assignAddress(const Datatype *tp,vector &status if ((curEntry.getType() != TYPE_UNKNOWN) && tp->getMetatype() != curEntry.getType()) continue; // Wrong type - Address res = curEntry.getAddrBySlot(status[grp],tp->getSize()); + Address res = curEntry.getAddrBySlot(status[grp],tp->getAlignSize(),tp->getAlignment()); if (res.isInvalid()) continue; // If -tp- doesn't fit an invalid address is returned if (curEntry.isExclusion()) { const vector &groupSet(curEntry.getAllGroups()); @@ -782,7 +788,7 @@ void ParamListStandard::buildTrialMap(ParamActive *active) const continue; int4 sz = curentry->isExclusion() ? curentry->getSize() : curentry->getAlign(); int4 nextslot = 0; - Address addr = curentry->getAddrBySlot(nextslot,sz); + Address addr = curentry->getAddrBySlot(nextslot,sz,1); int4 trialpos = active->getNumTrials(); active->registerTrial(addr,sz); ParamTrial ¶mtrial(active->getTrial(trialpos)); @@ -813,7 +819,7 @@ void ParamListStandard::buildTrialMap(ParamActive *active) const for(int4 j=0;jgetAddrBySlot(nextslot,curentry->getAlign()); + Address addr = curentry->getAddrBySlot(nextslot,curentry->getAlign(),1); int4 trialpos = active->getNumTrials(); active->registerTrial(addr,curentry->getAlign()); ParamTrial ¶mtrial(active->getTrial(trialpos)); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.hh index 1144e1b9b7..929f1eca6c 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.hh @@ -141,7 +141,7 @@ public: int4 getSlot(const Address &addr,int4 skip) const; AddrSpace *getSpace(void) const { return spaceid; } ///< Get the address space containing \b this entry uintb getBase(void) const { return addressbase; } ///< Get the starting offset of \b this entry - Address getAddrBySlot(int4 &slot,int4 sz) const; + Address getAddrBySlot(int4 &slot,int4 sz,int4 typeAlign) const; void decode(Decoder &decoder,bool normalstack,bool grouped,list &curList); bool isParamCheckHigh(void) const { return ((flags & extracheck_high)!=0); } ///< Return \b true if there is a high overlap bool isParamCheckLow(void) const { return ((flags & extracheck_low)!=0); } ///< Return \b true if there is a low overlap diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.cc index ffe5af04c9..560c6708fe 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.cc @@ -318,8 +318,13 @@ Scope *ArchitectureGhidra::buildDatabase(DocumentStorage &store) void ArchitectureGhidra::buildTypegrp(DocumentStorage &store) { - const Element *el = store.getTag("coretypes"); types = new TypeFactoryGhidra(this); +} + +void ArchitectureGhidra::buildCoreTypes(DocumentStorage &store) + +{ + const Element *el = store.getTag("coretypes"); if (el != (const Element *)0) { XmlDecode decoder(this,el); types->decodeCoreTypes(decoder); @@ -339,6 +344,7 @@ void ArchitectureGhidra::buildTypegrp(DocumentStorage &store) types->setCoreType("sqword",8,TYPE_INT,false); types->setCoreType("float",4,TYPE_FLOAT,false); types->setCoreType("float8",8,TYPE_FLOAT,false); + types->setCoreType("float10",10,TYPE_FLOAT,false); types->setCoreType("float16",16,TYPE_FLOAT,false); types->setCoreType("undefined",1,TYPE_UNKNOWN,false); types->setCoreType("undefined2",2,TYPE_UNKNOWN,false); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.hh index ba65bcc745..27ee6cada7 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ghidra_arch.hh @@ -95,6 +95,7 @@ class ArchitectureGhidra : public Architecture { virtual void buildLoader(DocumentStorage &store); virtual PcodeInjectLibrary *buildPcodeInjectLibrary(void); virtual void buildTypegrp(DocumentStorage &store); + virtual void buildCoreTypes(DocumentStorage &store); virtual void buildCommentDB(DocumentStorage &store); virtual void buildStringManager(DocumentStorage &store); virtual void buildConstantPool(DocumentStorage &store); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/grammar.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/grammar.cc index 4ce16ce5f4..14b1120696 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/grammar.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/grammar.cc @@ -2835,7 +2835,7 @@ Datatype *CParse::newStruct(const string &ident,vector *declis sublist.emplace_back(0,-1,decl->getIdentifier(),decl->buildType(glb)); } - TypeStruct::assignFieldOffsets(sublist,glb->types->getStructAlign()); + TypeStruct::assignFieldOffsets(sublist); if (!glb->types->setFields(sublist,res,-1,0)) { setError("Bad structure definition"); glb->types->destroyType(res); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/grammar.y b/Ghidra/Features/Decompiler/src/decompile/cpp/grammar.y index c740c426f6..cd7d835b99 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/grammar.y +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/grammar.y @@ -1042,7 +1042,7 @@ Datatype *CParse::newStruct(const string &ident,vector *declis sublist.emplace_back(0,-1,decl->getIdentifier(),decl->buildType(glb)); } - TypeStruct::assignFieldOffsets(sublist,glb->types->getStructAlign()); + TypeStruct::assignFieldOffsets(sublist); if (!glb->types->setFields(sublist,res,-1,0)) { setError("Bad structure definition"); glb->types->destroyType(res); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/options.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/options.cc index 8d293ffcb6..d5f2d5472e 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/options.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/options.cc @@ -104,7 +104,6 @@ OptionDatabase::OptionDatabase(Architecture *g) registerOption(new OptionForLoops()); registerOption(new OptionInline()); registerOption(new OptionNoReturn()); - registerOption(new OptionStructAlign()); registerOption(new OptionProtoEval()); registerOption(new OptionWarning()); registerOption(new OptionNullPrinting()); @@ -364,23 +363,6 @@ string OptionNoReturn::apply(Architecture *glb,const string &p1,const string &p2 return res; } -/// \class OptionStructAlign -/// \brief Alter the "structure alignment" data organization setting -/// -/// The first parameter must an integer value indicating the desired alignment -string OptionStructAlign::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const - -{ - int4 val = -1; - istringstream s(p1); - s >> dec >> val; - if (val == -1) - throw ParseError("Missing alignment value"); - - glb->types->setStructAlign(val); - return "Structure alignment set"; -} - /// \class OptionWarning /// \brief Toggle whether a warning should be issued if a specific action/rule is applied. /// diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/options.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/options.hh index 018220a4e8..2ff255c5c7 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/options.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/options.hh @@ -157,12 +157,6 @@ public: virtual string apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const; }; -class OptionStructAlign : public ArchOption { -public: - OptionStructAlign(void) { name = "structalign"; } ///< Constructor - virtual string apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const; -}; - class OptionWarning : public ArchOption { public: OptionWarning(void) { name = "warning"; } ///< Constructor diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc index 33a939790b..24aa954d22 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc @@ -5669,9 +5669,9 @@ bool AddTreeState::initAlternateForm(void) if (baseType->isVariableLength()) size = 0; // Open-ended size being pointed to, there will be no "multiples" component else - size = AddrSpace::byteToAddressInt(baseType->getSize(),ct->getWordSize()); + size = AddrSpace::byteToAddressInt(baseType->getAlignSize(),ct->getWordSize()); int4 unitsize = AddrSpace::addressToByteInt(1,ct->getWordSize()); - isDegenerate = (baseType->getSize() <= unitsize && baseType->getSize() > 0); + isDegenerate = (baseType->getAlignSize() <= unitsize && baseType->getAlignSize() > 0); preventDistribution = false; clear(); return true; @@ -5699,7 +5699,7 @@ AddTreeState::AddTreeState(Funcdata &d,PcodeOp *op,int4 slot) if (baseType->isVariableLength()) size = 0; // Open-ended size being pointed to, there will be no "multiples" component else - size = AddrSpace::byteToAddressInt(baseType->getSize(),ct->getWordSize()); + size = AddrSpace::byteToAddressInt(baseType->getAlignSize(),ct->getWordSize()); correct = 0; offset = 0; valid = true; // Valid until proven otherwise @@ -5708,7 +5708,7 @@ AddTreeState::AddTreeState(Funcdata &d,PcodeOp *op,int4 slot) isSubtype = false; distributeOp = (PcodeOp *)0; int4 unitsize = AddrSpace::addressToByteInt(1,ct->getWordSize()); - isDegenerate = (baseType->getSize() <= unitsize && baseType->getSize() > 0); + isDegenerate = (baseType->getAlignSize() <= unitsize && baseType->getAlignSize() > 0); } /// Even if the current base data-type is not an array, the pointer expression may incorporate @@ -6089,7 +6089,7 @@ Varnode *AddTreeState::buildExtra(void) bool AddTreeState::buildDegenerate(void) { - if (baseType->getSize() < ct->getWordSize()) + if (baseType->getAlignSize() < ct->getWordSize()) // If the size is really less than scale, there is // probably some sort of padding going on return false; // Don't transform at all @@ -6563,7 +6563,7 @@ int4 RulePtraddUndo::applyOp(PcodeOp *op,Funcdata &data) basevn = op->getIn(0); tp = (TypePointer *)basevn->getTypeReadFacing(op); if (tp->getMetatype() == TYPE_PTR) // Make sure we are still a pointer - if (tp->getPtrTo()->getSize()==AddrSpace::addressToByteInt(size,tp->getWordSize())) { // of the correct size + if (tp->getPtrTo()->getAlignSize()==AddrSpace::addressToByteInt(size,tp->getWordSize())) { // of the correct size Varnode *indVn = op->getIn(1); if ((!indVn->isConstant()) || (indVn->getOffset() != 0)) // and that index isn't zero return 0; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.cc index 13e0a324f9..ab5fd936dd 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.cc @@ -199,8 +199,14 @@ PcodeInjectLibrary *SleighArchitecture::buildPcodeInjectLibrary(void) void SleighArchitecture::buildTypegrp(DocumentStorage &store) { - const Element *el = store.getTag("coretypes"); types = new TypeFactory(this); // Initialize the object +} + +void SleighArchitecture::buildCoreTypes(DocumentStorage &store) + +{ + const Element *el = store.getTag("coretypes"); + if (el != (const Element *)0) { XmlDecode decoder(this,el); types->decodeCoreTypes(decoder); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.hh index 695622e608..fa1eab9667 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.hh @@ -120,6 +120,7 @@ protected: virtual Translate *buildTranslator(DocumentStorage &store); virtual PcodeInjectLibrary *buildPcodeInjectLibrary(void); virtual void buildTypegrp(DocumentStorage &store); + virtual void buildCoreTypes(DocumentStorage &store); virtual void buildCommentDB(DocumentStorage &store); virtual void buildStringManager(DocumentStorage &store); virtual void buildConstantPool(DocumentStorage &store); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc index c57f4705e9..a55ab8d038 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/type.cc @@ -427,6 +427,18 @@ void Datatype::encodeTypedef(Encoder &encoder) const encoder.closeElement(ELEM_DEF); } +/// Calculate \b size rounded up to be a multiple of \b alignment. +/// This value is returned by getAlignSize(). +void Datatype::calcAlignSize(void) + +{ + int4 mod = size % alignment; + if (mod != 0) + alignSize = size + (alignment - mod); + else + alignSize = size; +} + /// A CPUI_PTRSUB must act on a pointer data-type where the given offset addresses a component. /// Perform this check. /// \param off is the given offset @@ -546,6 +558,7 @@ void Datatype::decodeBasic(Decoder &decoder) } if (size < 0) throw LowlevelError("Bad size for type "+name); + alignSize = size; submeta = base2sub[metatype]; if ((id==0)&&(name.size()>0)) // If there is a type name id = hashName(name); // There must be some kind of id @@ -938,7 +951,7 @@ void TypePointer::calcTruncate(TypeFactory &typegrp) TypePointer *TypePointer::downChain(int8 &off,TypePointer *&par,int8 &parOff,bool allowArrayWrap,TypeFactory &typegrp) { - int4 ptrtoSize = ptrto->getSize(); + int4 ptrtoSize = ptrto->getAlignSize(); if (off < 0 || off >= ptrtoSize) { // Check if we are wrapping if (ptrtoSize != 0 && !ptrto->isVariableLength()) { // Check if pointed-to is wrappable if (!allowArrayWrap) @@ -1052,14 +1065,14 @@ int4 TypeArray::compareDependency(const Datatype &op) const Datatype *TypeArray::getSubType(int8 off,int8 *newoff) const { // Go down exactly one level, to type of element - *newoff = off % arrayof->getSize(); + *newoff = off % arrayof->getAlignSize(); return arrayof; } int4 TypeArray::getHoleSize(int4 off) const { - int4 newOff = off % arrayof->getSize(); + int4 newOff = off % arrayof->getAlignSize(); return arrayof->getHoleSize(newOff); } @@ -1073,9 +1086,9 @@ int4 TypeArray::getHoleSize(int4 off) const Datatype *TypeArray::getSubEntry(int4 off,int4 sz,int4 *newoff,int4 *el) const { - int4 noff = off % arrayof->getSize(); - int4 nel = off / arrayof->getSize(); - if (noff+sz > arrayof->getSize()) // Requesting parts of more then one element + int4 noff = off % arrayof->getAlignSize(); + int4 nel = off / arrayof->getAlignSize(); + if (noff+sz > arrayof->getAlignSize()) // Requesting parts of more then one element return (Datatype *)0; *newoff = noff; *el = nel; @@ -1151,8 +1164,9 @@ void TypeArray::decode(Decoder &decoder,TypeFactory &typegrp) } } arrayof = typegrp.decodeType(decoder); - if ((arraysize<=0)||(arraysize*arrayof->getSize()!=size)) + if ((arraysize<=0)||(arraysize*arrayof->getAlignSize()!=size)) throw LowlevelError("Bad size for array of type "+arrayof->getName()); + alignment = arrayof->getAlignment(); if (arraysize == 1) flags |= needs_resolution; // Array of size 1 needs special treatment // decoder.closeElement(elemId); @@ -1364,6 +1378,7 @@ TypeStruct::TypeStruct(const TypeStruct &op) { setFields(op.field); size = op.size; // setFields might have changed the size + alignSize = op.alignSize; } /// Copy a list of fields into this structure, establishing its size. @@ -1374,18 +1389,24 @@ void TypeStruct::setFields(const vector &fd) { vector::const_iterator iter; int4 end; - // Need to calculate size + // Need to calculate size and alignment size = 0; + alignment = 1; for(iter=fd.begin();iter!=fd.end();++iter) { field.push_back(*iter); - end = (*iter).offset + (*iter).type->getSize(); + Datatype *fieldType = (*iter).type; + end = (*iter).offset + fieldType->getSize(); if (end > size) size = end; + int4 curAlign = fieldType->getAlignment(); + if (curAlign > alignment) + alignment = curAlign; } if (field.size() == 1) { // A single field if (field[0].type->getSize() == size) // that fills the whole structure flags |= needs_resolution; // needs special attention } + calcAlignSize(); } /// Find the proper subfield given an offset. Return the index of that field @@ -1492,7 +1513,7 @@ Datatype *TypeStruct::nearestArrayedComponentBackward(int8 off,int8 *newoff,int8 Datatype *subtype = subfield.type; if (subtype->getMetatype() == TYPE_ARRAY) { *newoff = diff; - *elSize = ((TypeArray *)subtype)->getBase()->getSize(); + *elSize = ((TypeArray *)subtype)->getBase()->getAlignSize(); return subtype; } else { @@ -1520,7 +1541,7 @@ Datatype *TypeStruct::nearestArrayedComponentForward(int8 off,int8 *newoff,int8 Datatype *subtype = subfield.type; if (subtype->getMetatype() == TYPE_ARRAY) { *newoff = -diff; - *elSize = ((TypeArray *)subtype)->getBase()->getSize(); + *elSize = ((TypeArray *)subtype)->getBase()->getAlignSize(); return subtype; } else { @@ -1625,6 +1646,7 @@ void TypeStruct::encode(Encoder &encoder) const void TypeStruct::decodeFields(Decoder &decoder,TypeFactory &typegrp) { + alignment = 1; int4 maxoffset = 0; while(decoder.peekElement() != 0) { field.emplace_back(decoder,typegrp); @@ -1636,6 +1658,9 @@ void TypeStruct::decodeFields(Decoder &decoder,TypeFactory &typegrp) s << "Field " << field.back().name << " does not fit in structure " + name; throw LowlevelError(s.str()); } + int4 curAlign = field.back().type->getAlignment(); + if (curAlign > alignment) + alignment = curAlign; } if (size == 0) // We can decode an incomplete structure, indicated by 0 size flags |= type_incomplete; @@ -1645,6 +1670,7 @@ void TypeStruct::decodeFields(Decoder &decoder,TypeFactory &typegrp) if (field[0].type->getSize() == size) // that fills the whole structure flags |= needs_resolution; // needs special resolution } + calcAlignSize(); } /// If this method is called, the given data-type has a single component that fills it entirely @@ -1731,24 +1757,17 @@ int4 TypeStruct::findCompatibleResolve(Datatype *ct) const /// Assign an offset to fields in order so that each field starts at an aligned offset within the structure /// \param list is the list of fields -/// \param align is the given alignment -void TypeStruct::assignFieldOffsets(vector &list,int4 align) +void TypeStruct::assignFieldOffsets(vector &list) { int4 offset = 0; vector::iterator iter; for(iter=list.begin();iter!=list.end();++iter) { if ((*iter).offset != -1) continue; - int4 cursize = (*iter).type->getSize(); - int4 curalign = 0; - if (align > 1) { - curalign = align; - while((curalign>>1) >= cursize) - curalign >>= 1; - curalign -= 1; - } - if ((offset & curalign)!=0) - offset = (offset-(offset & curalign) + (curalign+1)); + int4 cursize = (*iter).type->getAlignSize(); + int4 align = (*iter).type->getAlignment() - 1; + if (align > 0 && (offset & align)!=0) + offset = (offset-(offset & align) + (align+1)); (*iter).offset = offset; (*iter).ident = offset; offset += cursize; @@ -1762,14 +1781,20 @@ void TypeUnion::setFields(const vector &fd) { vector::const_iterator iter; - // Need to calculate size + // Need to calculate size and alignment size = 0; + alignment = 1; for(iter=fd.begin();iter!=fd.end();++iter) { field.push_back(*iter); - int4 end = field.back().type->getSize(); + Datatype *fieldType = field.back().type; + int4 end = fieldType->getSize(); if (end > size) size = end; + int4 curAlign = fieldType->getAlignment(); + if (curAlign > alignment) + alignment = curAlign; } + calcAlignSize(); } /// Parse children of the \ element describing each field. @@ -1778,6 +1803,7 @@ void TypeUnion::setFields(const vector &fd) void TypeUnion::decodeFields(Decoder &decoder,TypeFactory &typegrp) { + alignment = 1; while(decoder.peekElement() != 0) { field.emplace_back(decoder,typegrp); if (field.back().offset + field.back().type->getSize() > size) { @@ -1785,11 +1811,15 @@ void TypeUnion::decodeFields(Decoder &decoder,TypeFactory &typegrp) s << "Field " << field.back().name << " does not fit in union " << name; throw LowlevelError(s.str()); } + int4 curAlign = field.back().type->getAlignment(); + if (curAlign > alignment) + alignment = curAlign; } if (size == 0) // We can decode an incomplete structure, indicated by 0 size flags |= type_incomplete; else markComplete(); // Otherwise the union is complete + calcAlignSize(); } TypeUnion::TypeUnion(const TypeUnion &op) @@ -1797,6 +1827,7 @@ TypeUnion::TypeUnion(const TypeUnion &op) { setFields(op.field); size = op.size; // setFields might have changed the size + alignSize = op.alignSize; } int4 TypeUnion::compare(const Datatype &op,int4 level) const @@ -1986,7 +2017,7 @@ TypePartialStruct::TypePartialStruct(const TypePartialStruct &op) } TypePartialStruct::TypePartialStruct(Datatype *contain,int4 off,int4 sz,Datatype *strip) - : Datatype(sz,TYPE_PARTIALSTRUCT) + : Datatype(sz,1,TYPE_PARTIALSTRUCT) { #ifdef CPUI_DEBUG if (contain->getMetatype() != TYPE_STRUCT && contain->getMetatype() != TYPE_ARRAY) @@ -2067,7 +2098,7 @@ TypePartialUnion::TypePartialUnion(const TypePartialUnion &op) } TypePartialUnion::TypePartialUnion(TypeUnion *contain,int4 off,int4 sz,Datatype *strip) - : Datatype(sz,TYPE_PARTIALUNION) + : Datatype(sz,1,TYPE_PARTIALUNION) { flags |= (needs_resolution | has_stripped); stripped = strip; @@ -2410,7 +2441,7 @@ TypeCode::TypeCode(const TypeCode &op) : Datatype(op) } } -TypeCode::TypeCode(void) : Datatype(1,TYPE_CODE) +TypeCode::TypeCode(void) : Datatype(1,1,TYPE_CODE) { proto = (FuncProto *)0; @@ -2661,7 +2692,7 @@ Datatype *TypeSpacebase::nearestArrayedComponentForward(int8 off,int8 *newoff,in symbolType = smallest->getSymbol()->getType(); *newoff = addr.getOffset() - smallest->getAddr().getOffset(); if (symbolType->getMetatype() == TYPE_ARRAY) { - *elSize = ((TypeArray *)symbolType)->getBase()->getSize(); + *elSize = ((TypeArray *)symbolType)->getBase()->getAlignSize(); return symbolType; } if (symbolType->getMetatype() == TYPE_STRUCT) { @@ -2680,7 +2711,7 @@ Datatype *TypeSpacebase::nearestArrayedComponentBackward(int8 off,int8 *newoff,i if (subType == (Datatype *)0) return (Datatype *)0; if (subType->getMetatype() == TYPE_ARRAY) { - *elSize = ((TypeArray *)subType)->getBase()->getSize(); + *elSize = ((TypeArray *)subType)->getBase()->getAlignSize(); return subType; } if (subType->getMetatype() == TYPE_STRUCT) { @@ -2763,7 +2794,6 @@ TypeFactory::TypeFactory(Architecture *g) sizeOfLong = 0; sizeOfPointer = 0; sizeOfAltPointer = 0; - align = 0; enumsize = 0; clearCache(); @@ -2806,10 +2836,10 @@ void TypeFactory::setupSizes(void) sizeOfPointer = segOp->getInnerSize(); sizeOfAltPointer = sizeOfPointer + segOp->getBaseSize(); } - if (align == 0) - align = glb->getDefaultSize(); + if (alignMap.empty()) + setDefaultAlignmentMap(); if (enumsize == 0) { - enumsize = align; + enumsize = glb->getDefaultSize(); enumtype = TYPE_UINT; } } @@ -2927,6 +2957,35 @@ TypeFactory::~TypeFactory(void) clear(); } +/// Return the alignment associated with a primitive data-type of the given size +/// \param size is the aligned size in bytes of the primitive +/// \return the expected alignment in bytes +int4 TypeFactory::getAlignment(uint4 size) const + +{ + if (size >= alignMap.size()) { + if (alignMap.empty()) + throw LowlevelError("TypeFactory alignment map not initialized"); + return alignMap[alignMap.size()-1]; + } + return alignMap[size]; +} + +/// Return the amount of room a data-type takes up in memory, which may be larger than the +/// raw number of bytes in the data-type. This is the size consistent with the \b sizeof operator +/// in C. +/// \param size is the raw number of bytes in the data-type +/// \return the aligned size +int4 TypeFactory::getPrimitiveAlignSize(uint4 size) const + +{ + int4 align = getAlignment(size); + uint4 mod = size % align; + if (mod != 0) + size += (align-mod); + return size; +} + /// Looking just within this container, find a Datatype by \b name and/or \b id. /// \param n is the name of the data-type /// \param id is the type id of the data-type @@ -3038,6 +3097,10 @@ Datatype *TypeFactory::findAdd(Datatype &ct) } newtype = ct.clone(); // Add the new type to trees + if (newtype->alignment < 0) { + newtype->alignSize = getPrimitiveAlignSize(newtype->size); + newtype->alignment = getAlignment(newtype->alignSize); + } insert(newtype); return newtype; } @@ -3112,8 +3175,10 @@ bool TypeFactory::setFields(vector &fd,TypeStruct *ot,int4 fixedsize, ot->flags &= ~(uint4)Datatype::type_incomplete; ot->flags |= (flags & (Datatype::opaque_string | Datatype::variable_length | Datatype::type_incomplete)); if (fixedsize > 0) { // If the caller is trying to force a size - if (fixedsize > ot->size) // If the forced size is bigger than the size required for fields + if (fixedsize > ot->size) { // If the forced size is bigger than the size required for fields ot->size = fixedsize; // Force the bigger size + ot->calcAlignSize(); + } else if (fixedsize < ot->size) // If the forced size is smaller, this is an error throw LowlevelError("Trying to force too small a size on "+ot->getName()); } @@ -3150,8 +3215,10 @@ bool TypeFactory::setFields(vector &fd,TypeUnion *ot,int4 fixedsize,u ot->flags &= ~(uint4)Datatype::type_incomplete; ot->flags |= (flags & (Datatype::variable_length | Datatype::type_incomplete)); if (fixedsize > 0) { // If the caller is trying to force a size - if (fixedsize > ot->size) // If the forced size is bigger than the size required for fields + if (fixedsize > ot->size) { // If the forced size is bigger than the size required for fields ot->size = fixedsize; // Force the bigger size + ot->calcAlignSize(); + } else if (fixedsize < ot->size) // If the forced size is smaller, this is an error throw LowlevelError("Trying to force too small a size on "+ot->getName()); } @@ -3830,7 +3897,6 @@ void TypeFactory::encode(Encoder &encoder) const encoder.openElement(ELEM_TYPEGRP); encoder.writeSignedInteger(ATTRIB_INTSIZE, sizeOfInt); encoder.writeSignedInteger(ATTRIB_LONGSIZE, sizeOfLong); - encoder.writeSignedInteger(ATTRIB_STRUCTALIGN, align); encoder.writeSignedInteger(ATTRIB_ENUMSIZE, enumsize); encoder.writeBool(ATTRIB_ENUMSIGNED, (enumtype==TYPE_INT)); for(iter=deporder.begin();iter!=deporder.end();++iter) { @@ -4157,7 +4223,6 @@ void TypeFactory::decode(Decoder &decoder) sizeOfInt = decoder.readSignedInteger(ATTRIB_INTSIZE); sizeOfLong = decoder.readSignedInteger(ATTRIB_LONGSIZE); - align = decoder.readSignedInteger(ATTRIB_STRUCTALIGN); enumsize = decoder.readSignedInteger(ATTRIB_ENUMSIZE); if (decoder.readBool(ATTRIB_ENUMSIGNED)) enumtype = TYPE_INT; @@ -4191,8 +4256,6 @@ void TypeFactory::decodeCoreTypes(Decoder &decoder) void TypeFactory::decodeDataOrganization(Decoder &decoder) { - uint4 defaultSize = glb->getDefaultSize(); - align = 0; uint4 elemId = decoder.openElement(ELEM_DATA_ORGANIZATION); for(;;) { uint4 subId = decoder.openElement(); @@ -4207,15 +4270,7 @@ void TypeFactory::decodeDataOrganization(Decoder &decoder) sizeOfPointer = decoder.readSignedInteger(ATTRIB_VALUE); } else if (subId == ELEM_SIZE_ALIGNMENT_MAP) { - for(;;) { - uint4 mapId = decoder.openElement(); - if (mapId != ELEM_ENTRY) break; - int4 sz = decoder.readSignedInteger(ATTRIB_SIZE); - int4 val = decoder.readSignedInteger(ATTRIB_ALIGNMENT); - if (sz <= defaultSize) - align = val; - decoder.closeElement(mapId); - } + decodeAlignmentMap(decoder); } else { decoder.closeElementSkipping(subId); @@ -4226,6 +4281,43 @@ void TypeFactory::decodeDataOrganization(Decoder &decoder) decoder.closeElement(elemId); } +/// Recover the map from data-type size to preferred alignment. +/// \param decoder is the stream decoder +void TypeFactory::decodeAlignmentMap(Decoder &decoder) + +{ + alignMap.clear(); + for(;;) { + uint4 mapId = decoder.openElement(); + if (mapId != ELEM_ENTRY) break; + int4 sz = decoder.readSignedInteger(ATTRIB_SIZE); + int4 val = decoder.readSignedInteger(ATTRIB_ALIGNMENT); + while(alignMap.size() <= sz) + alignMap.push_back(-1); + alignMap[sz] = val; + decoder.closeElement(mapId); + } + int4 curAlign = 1; + for(int4 sz=1;sz < alignMap.size();++sz) { + int4 tmpAlign = alignMap[sz]; + if (tmpAlign == -1) + alignMap[sz] = curAlign; // Copy alignment from nearest explicitly set value + else + curAlign = tmpAlign; + } +} + +/// The default is used if the compiler spec does not contain a \ element. +void TypeFactory::setDefaultAlignmentMap(void) + +{ + alignMap.resize(5,0); + alignMap[1] = 1; + alignMap[2] = 2; + alignMap[3] = 2; + alignMap[4] = 4; +} + /// Recover default enumeration properties (size and meta-type) from /// an \ XML tag. Should probably consider this deprecated. These /// values are only used by the internal C parser. diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/type.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/type.hh index 5064d4a9ec..8e8696c93c 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/type.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/type.hh @@ -169,20 +169,24 @@ protected: type_metatype metatype; ///< Meta-type - type disregarding size sub_metatype submeta; ///< Sub-type of of the meta-type, for comparisons Datatype *typedefImm; ///< The immediate data-type being typedefed by \e this + int4 alignment; ///< Byte alignment expected for \b this data-type in addressable memory + int4 alignSize; ///< Size of data-type rounded up to a multiple of \b alignment void decodeBasic(Decoder &decoder); ///< Recover basic data-type properties void encodeBasic(type_metatype meta,Encoder &encoder) const; ///< Encode basic data-type properties void encodeTypedef(Encoder &encoder) const; ///< Encode \b this as a \e typedef element to a stream void markComplete(void) { flags &= ~(uint4)type_incomplete; } ///< Mark \b this data-type as completely defined void setDisplayFormat(uint4 format); ///< Set a specific display format + void calcAlignSize(void); ///< Calculate aligned size, assuming alignment is known virtual Datatype *clone(void) const=0; ///< Clone the data-type static uint8 hashName(const string &nm); ///< Produce a data-type id by hashing the type name static uint8 hashSize(uint8 id,int4 size); ///< Reversibly hash size into id public: /// Construct the base data-type copying low-level properties of another Datatype(const Datatype &op) { size = op.size; name=op.name; displayName=op.displayName; metatype=op.metatype; - submeta=op.submeta; flags=op.flags; id=op.id; typedefImm=op.typedefImm; } + submeta=op.submeta; flags=op.flags; id=op.id; typedefImm=op.typedefImm; alignment=op.alignment; alignSize=op.alignSize; } /// Construct the base data-type providing size and meta-type - Datatype(int4 s,type_metatype m) { size=s; metatype=m; submeta=base2sub[m]; flags=0; id=0; typedefImm=(Datatype *)0; } + Datatype(int4 s,int4 align,type_metatype m) { + size=s; metatype=m; submeta=base2sub[m]; flags=0; id=0; typedefImm=(Datatype *)0; alignment=align; alignSize=s; } virtual ~Datatype(void) {} ///< Destructor bool isCoreType(void) const { return ((flags&coretype)!=0); } ///< Is this a core data-type bool isCharPrint(void) const { return ((flags&(chartype|utf16|utf32|opaque_string))!=0); } ///< Does this print as a 'char' @@ -207,6 +211,8 @@ public: uint8 getId(void) const { return id; } ///< Get the type id uint8 getUnsizedId(void) const; ///< Get the type id, without variable length size adjustment int4 getSize(void) const { return size; } ///< Get the type size + int4 getAlignSize(void) const { return alignSize; } ///< Get size rounded up to multiple of alignment + int4 getAlignment(void) const { return alignment; } ///< Get the expected byte alignment const string &getName(void) const { return name; } ///< Get the type name const string &getDisplayName(void) const { return displayName; } ///< Get string to use in display Datatype *getTypedef(void) const { return typedefImm; } ///< Get the data-type immediately typedefed by \e this (or null) @@ -303,9 +309,9 @@ public: /// Construct TypeBase copying properties from another data-type TypeBase(const TypeBase &op) : Datatype(op) {} /// Construct TypeBase from a size and meta-type - TypeBase(int4 s,type_metatype m) : Datatype(s,m) {} + TypeBase(int4 s,type_metatype m) : Datatype(s,-1,m) {} /// Construct TypeBase from a size, meta-type, and name - TypeBase(int4 s,type_metatype m,const string &n) : Datatype(s,m) { name = n; displayName = n; } + TypeBase(int4 s,type_metatype m,const string &n) : Datatype(s,-1,m) { name = n; displayName = n; } virtual Datatype *clone(void) const { return new TypeBase(*this); } }; @@ -353,7 +359,7 @@ public: /// Construct from another TypeVoid TypeVoid(const TypeVoid &op) : Datatype(op) { flags |= Datatype::coretype; } /// Constructor - TypeVoid(void) : Datatype(0,TYPE_VOID) { name = "void"; displayName = name; flags |= Datatype::coretype; } + TypeVoid(void) : Datatype(0,1,TYPE_VOID) { name = "void"; displayName = name; flags |= Datatype::coretype; } virtual Datatype *clone(void) const { return new TypeVoid(*this); } virtual void encode(Encoder &encoder) const; }; @@ -370,15 +376,15 @@ protected: void calcSubmeta(void); ///< Calculate specific submeta for \b this pointer void calcTruncate(TypeFactory &typegrp); // Assign a truncated pointer subcomponent if necessary /// Internal constructor for use with decode - TypePointer(void) : Datatype(0,TYPE_PTR) { ptrto = (Datatype *)0; wordsize=1; spaceid=(AddrSpace *)0; truncate=(TypePointer *)0; } + TypePointer(void) : Datatype(0,-1,TYPE_PTR) { ptrto = (Datatype *)0; wordsize=1; spaceid=(AddrSpace *)0; truncate=(TypePointer *)0; } public: /// Construct from another TypePointer TypePointer(const TypePointer &op) : Datatype(op) { ptrto = op.ptrto; wordsize=op.wordsize; spaceid=op.spaceid; truncate=op.truncate; } /// Construct from a size, pointed-to type, and wordsize - TypePointer(int4 s,Datatype *pt,uint4 ws) : Datatype(s,TYPE_PTR) { + TypePointer(int4 s,Datatype *pt,uint4 ws) : Datatype(s,-1,TYPE_PTR) { ptrto = pt; flags = ptrto->getInheritable(); wordsize=ws; spaceid=(AddrSpace *)0; truncate=(TypePointer *)0; calcSubmeta(); } /// Construct from a pointed-to type and an address space attribute - TypePointer(Datatype *pt,AddrSpace *spc) : Datatype(spc->getAddrSize(), TYPE_PTR) { + TypePointer(Datatype *pt,AddrSpace *spc) : Datatype(spc->getAddrSize(), -1, TYPE_PTR) { ptrto = pt; flags = ptrto->getInheritable(); spaceid=spc; wordsize=spc->getWordSize(); truncate=(TypePointer *)0; calcSubmeta(); } Datatype *getPtrTo(void) const { return ptrto; } ///< Get the pointed-to Datatype uint4 getWordSize(void) const { return wordsize; } ///< Get the size of the addressable unit being pointed to @@ -406,7 +412,7 @@ protected: int4 arraysize; ///< Number of elements in the array void decode(Decoder &decoder,TypeFactory &typegrp); ///< Restore \b this array from a stream /// Internal constructor for decode - TypeArray(void) : Datatype(0,TYPE_ARRAY) { arraysize = 0; arrayof = (Datatype *)0; } + TypeArray(void) : Datatype(0,-1,TYPE_ARRAY) { arraysize = 0; arrayof = (Datatype *)0; } public: /// Construct from another TypeArray TypeArray(const TypeArray &op) : Datatype(op) { arrayof = op.arrayof; arraysize = op.arraysize; } @@ -470,7 +476,7 @@ protected: void decodeFields(Decoder &decoder,TypeFactory &typegrp); ///< Restore fields from a stream public: TypeStruct(const TypeStruct &op); ///< Construct from another TypeStruct - TypeStruct(void) : Datatype(0,TYPE_STRUCT) { flags |= type_incomplete; } ///< Construct incomplete/empty TypeStruct + TypeStruct(void) : Datatype(0,-1,TYPE_STRUCT) { flags |= type_incomplete; } ///< Construct incomplete/empty TypeStruct vector::const_iterator beginField(void) const { return field.begin(); } ///< Beginning of fields vector::const_iterator endField(void) const { return field.end(); } ///< End of fields virtual const TypeField *findTruncation(int8 off,int4 sz,const PcodeOp *op,int4 slot,int8 &newoff) const; @@ -487,7 +493,7 @@ public: virtual Datatype *resolveInFlow(PcodeOp *op,int4 slot); virtual Datatype* findResolve(const PcodeOp *op,int4 slot); virtual int4 findCompatibleResolve(Datatype *ct) const; - static void assignFieldOffsets(vector &list,int4 align); ///< Assign field offsets given a byte alignment + static void assignFieldOffsets(vector &list); ///< Assign field offsets static int4 scoreSingleComponent(Datatype *parent,PcodeOp *op,int4 slot); ///< Determine best type fit for given PcodeOp use }; @@ -503,7 +509,7 @@ protected: void decodeFields(Decoder &decoder,TypeFactory &typegrp); ///< Restore fields from a stream public: TypeUnion(const TypeUnion &op); ///< Construct from another TypeUnion - TypeUnion(void) : Datatype(0,TYPE_UNION) { flags |= (type_incomplete | needs_resolution); } ///< Construct incomplete TypeUnion + TypeUnion(void) : Datatype(0,-1,TYPE_UNION) { flags |= (type_incomplete | needs_resolution); } ///< Construct incomplete TypeUnion const TypeField *getField(int4 i) const { return &field[i]; } ///< Get the i-th field of the union virtual const TypeField *findTruncation(int8 offset,int4 sz,const PcodeOp *op,int4 slot,int8 &newoff) const; // virtual Datatype *getSubType(int8 off,int8 *newoff) const; @@ -658,7 +664,7 @@ public: } /// Construct given an address space, scope, and architecture TypeSpacebase(AddrSpace *id,const Address &frame,Architecture *g) - : Datatype(0,TYPE_SPACEBASE), localframe(frame) { spaceid = id; glb = g; } + : Datatype(0,1,TYPE_SPACEBASE), localframe(frame) { spaceid = id; glb = g; } Scope *getMap(void) const; ///< Get the symbol table indexed by \b this Address getAddress(uintb off,int4 sz,const Address &point) const; ///< Construct an Address given an offset virtual Datatype *getSubType(int8 off,int8 *newoff) const; @@ -676,9 +682,9 @@ class TypeFactory { int4 sizeOfLong; ///< Size of the core "long" datatype int4 sizeOfPointer; ///< Size of pointers (into default data address space) int4 sizeOfAltPointer; ///< Size of alternate pointers used by architecture (if not 0) - int4 align; ///< Alignment of structures int4 enumsize; ///< Size of an enumerated type type_metatype enumtype; ///< Default enumeration meta-type (when parsing C) + vector alignMap; ///< Alignment of primitive data-types based on their size DatatypeSet tree; ///< Datatypes within this factory (sorted by function) DatatypeNameSet nametree; ///< Cross-reference by name Datatype *typecache[9][8]; ///< Matrix of the most common atomic data-types @@ -689,6 +695,8 @@ class TypeFactory { void insert(Datatype *newtype); ///< Insert pointer into the cross-reference sets Datatype *findAdd(Datatype &ct); ///< Find data-type in this container or add it void orderRecurse(vector &deporder,DatatypeSet &mark,Datatype *ct) const; ///< Write out dependency list + void decodeAlignmentMap(Decoder &decoder); ///< Parse a \ element + void setDefaultAlignmentMap(void); ///< Provide default alignments for data-types Datatype *decodeTypedef(Decoder &decoder); ///< Restore a \ element describing a typedef Datatype *decodeStruct(Decoder &decoder,bool forcecore); ///< Restore a \ element describing a structure Datatype *decodeUnion(Decoder &decoder,bool forcecore); ///< Restore a \ element describing a union @@ -709,8 +717,8 @@ public: void clear(void); ///< Clear out all types void clearNoncore(void); ///< Clear out non-core types virtual ~TypeFactory(void); ///< Destructor - void setStructAlign(int4 al) { align = al; } ///< Set the default structure alignment - int4 getStructAlign(void) const { return align; } ///< Get the default structure alignment + int4 getAlignment(uint4 size) const; ///< Get data-type alignment based on size + int4 getPrimitiveAlignSize(uint4 size) const; ///< Get the aligned size of a primitive data-type 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" int4 getSizeOfPointer(void) const { return sizeOfPointer; } ///< Get the size of pointers @@ -832,7 +840,7 @@ inline bool Datatype::isPieceStructured(void) const return (metatype <= TYPE_ARRAY); } -inline TypeArray::TypeArray(int4 n,Datatype *ao) : Datatype(n*ao->getSize(),TYPE_ARRAY) +inline TypeArray::TypeArray(int4 n,Datatype *ao) : Datatype(n*ao->getAlignSize(),ao->getAlignment(),TYPE_ARRAY) { arraysize = n; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.cc index 0d3543d26d..611d0a9ea0 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/typeop.cc @@ -1151,7 +1151,7 @@ Datatype *TypeOpIntAdd::propagateAddIn2Out(Datatype *alttype,TypeFactory *typegr { TypePointer *pointer = (TypePointer *)alttype; uintb offset; - int4 command = propagateAddPointer(offset,op,inslot,pointer->getPtrTo()->getSize()); + int4 command = propagateAddPointer(offset,op,inslot,pointer->getPtrTo()->getAlignSize()); if (command == 2) return op->getOut()->getTempType(); // Doesn't look like a good pointer add TypePointer *parent = (TypePointer *)0; int8 parentOff; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/unionresolve.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/unionresolve.cc index 8b40cb8cd8..3076dce7a6 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/unionresolve.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/unionresolve.cc @@ -449,7 +449,7 @@ void ScoreUnionFields::scoreTrialDown(const Trial &trial,bool lastLevel) } } TypePointer *baseType = (TypePointer *)trial.fitType; - if (baseType->getPtrTo()->getSize() == elSize) { + if (baseType->getPtrTo()->getAlignSize() == elSize) { score = 5; resType = trial.fitType; } @@ -601,7 +601,7 @@ void ScoreUnionFields::scoreTrialDown(const Trial &trial,bool lastLevel) if (meta == TYPE_PTR) { if (trial.inslot == 0) { Datatype *ptrto = ((TypePointer *)trial.fitType)->getPtrTo(); - if (ptrto->getSize() == trial.op->getIn(2)->getOffset()) { + if (ptrto->getAlignSize() == trial.op->getIn(2)->getOffset()) { score = 10; resType = trial.fitType; } @@ -812,7 +812,7 @@ void ScoreUnionFields::scoreTrialUp(const Trial &trial,bool lastLevel) case CPUI_PTRADD: if (meta == TYPE_PTR) { Datatype *ptrto = ((TypePointer *)trial.fitType)->getPtrTo(); - if (ptrto->getSize() == def->getIn(2)->getOffset()) + if (ptrto->getAlignSize() == def->getIn(2)->getOffset()) score = 10; else score = 2; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/varmap.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/varmap.cc index 0ac915aa45..ef4387dfa5 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/varmap.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/varmap.cc @@ -34,22 +34,22 @@ bool RangeHint::reconcile(const RangeHint *b) const { const RangeHint *a = this; - if (a->type->getSize() < b->type->getSize()) { + if (a->type->getAlignSize() < b->type->getAlignSize()) { const RangeHint *tmp = b; b = a; // Make sure b is smallest a = tmp; } - int8 mod = (b->sstart - a->sstart) % a->type->getSize(); + int8 mod = (b->sstart - a->sstart) % a->type->getAlignSize(); if (mod < 0) - mod += a->type->getSize(); + mod += a->type->getAlignSize(); Datatype *sub = a->type; - while((sub!=(Datatype *)0)&&(sub->getSize() > b->type->getSize())) + while((sub!=(Datatype *)0)&&(sub->getAlignSize() > b->type->getAlignSize())) sub = sub->getSubType(mod,&mod); if (sub == (Datatype *)0) return false; if (mod != 0) return false; - if (sub->getSize() == b->type->getSize()) return true; + if (sub->getAlignSize() == b->type->getAlignSize()) return true; if ((b->flags & Varnode::typelock)!=0) return false; // If we reach here, component sizes do not match // Check for data-types we want to protect more @@ -130,7 +130,7 @@ bool RangeHint::attemptJoin(RangeHint *b) if (highind < 0) return false; if (b->rangeType == endpoint) return false; // Don't merge with bounding range Datatype *settype = type; // Assume we will keep this data-type - if (settype->getSize() != b->type->getSize()) return false; + if (settype->getAlignSize() != b->type->getAlignSize()) return false; if (settype != b->type) { Datatype *aTestType = type; Datatype *bTestType = b->type; @@ -155,8 +155,8 @@ bool RangeHint::attemptJoin(RangeHint *b) if ((b->flags & Varnode::typelock)!=0) return false; if (flags != b->flags) return false; intb diffsz = b->sstart - sstart; - if ((diffsz % settype->getSize()) != 0) return false; - diffsz /= settype->getSize(); + if ((diffsz % settype->getAlignSize()) != 0) return false; + diffsz /= settype->getAlignSize(); if (diffsz > highind) return false; type = settype; absorb(b); @@ -170,11 +170,11 @@ bool RangeHint::attemptJoin(RangeHint *b) void RangeHint::absorb(RangeHint *b) { - if (b->rangeType == open && type->getSize() == b->type->getSize()) { + if (b->rangeType == open && type->getAlignSize() == b->type->getAlignSize()) { rangeType = open; if (0 <= b->highind) { // If b has array indexing intb diffsz = b->sstart - sstart; - diffsz /= type->getSize(); + diffsz /= type->getAlignSize(); int4 trialhi = b->highind + diffsz; if (highind < trialhi) highind = trialhi; @@ -554,7 +554,7 @@ void ScopeLocal::createEntry(const RangeHint &a) Address addr(space,a.start); Address usepoint; Datatype *ct = glb->types->concretize(a.type); - int4 num = a.size/ct->getSize(); + int4 num = a.size/ct->getAlignSize(); if (num>1) ct = glb->types->getTypeArray(num,ct); @@ -919,7 +919,7 @@ void MapState::addGuard(const LoadGuard &guard,OpCode opc,TypeFactory *typeFacto // we pretend we have an array of LOAD's size step = outSize; } - if (ct->getSize() != step) { // Make sure data-type matches our step size + if (ct->getAlignSize() != step) { // Make sure data-type matches our step size if (step > 8) return; // Don't manufacture primitives bigger than 8-bytes ct = typeFactory->getBase(step, TYPE_UNKNOWN); diff --git a/Ghidra/Features/Decompiler/src/decompile/datatests/impliedfield.xml b/Ghidra/Features/Decompiler/src/decompile/datatests/impliedfield.xml index 885a176cb7..2bd72de28e 100644 --- a/Ghidra/Features/Decompiler/src/decompile/datatests/impliedfield.xml +++ b/Ghidra/Features/Decompiler/src/decompile/datatests/impliedfield.xml @@ -19,7 +19,6 @@ f8c30fafc7c3 +ldarr\[0\] = valpass \+ \(float10\)27\.632 +ldarr\[1\] = valpass \+ \(float10\)27\.632 +writeLongDouble\(ldarr,x\); +return \(int4\)y \+ \(int4\)z \+ \(int4\)w; +writeLongDouble\(ldarr,ptrldstr->a\); +writeLongDouble\(ldarr,ptrldstr->b\); +return \(int4\)ptrldstr->c \+ \(int4\)ptrldstr->d \+ \(int4\)ptrldstr->e \+ \(int4\)ptrldstr->f; +printf_chk\(1,\"%d\\n\",v1\); +printf_chk\(1,\"%d\\n\",firstval\.b\); +printf_chk\(1,\"%d\\n\",v2\); +writeLongDouble\(ldarr,firstval\.a\); +\*ptrwrite = valwrite; +ptrwrite\[1\] = valwrite \+ \(float10\)0.7; +ldarr\[val\] = ldarr\[7 \- val\] \+ ldarr\[val \+ 7\]; +ptr\[val & 0xfffe\] = ptr\[.*\(val \* 3\) \+ 1\]; + diff --git a/Ghidra/Features/Decompiler/src/decompile/datatests/nestedoffset.xml b/Ghidra/Features/Decompiler/src/decompile/datatests/nestedoffset.xml index 06b6bb7251..82c0366837 100644 --- a/Ghidra/Features/Decompiler/src/decompile/datatests/nestedoffset.xml +++ b/Ghidra/Features/Decompiler/src/decompile/datatests/nestedoffset.xml @@ -12,7 +12,7 @@ -return mStack.*array\[param_1 \+ -2\] +return mStack.*array\[param_1 \+ -1\] firstfield diff --git a/Ghidra/Features/Decompiler/src/decompile/datatests/packstructaccess.xml b/Ghidra/Features/Decompiler/src/decompile/datatests/packstructaccess.xml index 48505f2b09..5470a9ab65 100644 --- a/Ghidra/Features/Decompiler/src/decompile/datatests/packstructaccess.xml +++ b/Ghidra/Features/Decompiler/src/decompile/datatests/packstructaccess.xml @@ -12,7 +12,6 @@