GP-3873 Data-type alignment support in decompiler

This commit is contained in:
caheckman 2023-09-22 16:08:18 +00:00
parent 6508088623
commit 64a58bdeab
29 changed files with 456 additions and 149 deletions

View File

@ -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|

View File

@ -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);

View File

@ -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.

View File

@ -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; ///<Emit the instructions in \b this FlowBlock as structured code
virtual const FlowBlock *getExitLeaf(void) const { return (const FlowBlock *)0; } ///< Get the FlowBlock to which \b this block exits
virtual PcodeOp *firstOp(void) const { return (PcodeOp *)0; } ///< Get the first PcodeOp executed by \b this FlowBlock
virtual PcodeOp *lastOp(void) const { return (PcodeOp *)0; } ///< Get the last PcodeOp executed by \b this FlowBlock
/// \brief Get the leaf block from which \b this block exits
///
/// This will be the only basic block with (structured) edges out of \b this block.
/// \return the specific exiting block or null if there isn't a unique block
virtual const FlowBlock *getExitLeaf(void) const { return (const FlowBlock *)0; }
/// \brief Get the first PcodeOp executed by \b this FlowBlock
///
/// If there are no PcodeOps in the block, null is returned.
/// \return the first PcodeOp or null
virtual PcodeOp *firstOp(void) const { return (PcodeOp *)0; }
/// \brief Get the last PcodeOp executed by \b this FlowBlock
///
/// If \b this has a unique last PcodeOp, it is returned.
/// \return the last PcodeOp or null
virtual PcodeOp *lastOp(void) const { return (PcodeOp *)0; }
virtual bool negateCondition(bool toporbottom); ///< Flip the condition computed by \b this
virtual bool preferComplement(Funcdata &data); ///< Rearrange \b this hierarchy to simplify boolean expressions
virtual FlowBlock *getSplitPoint(void); ///< Get the leaf splitting block
virtual int4 flipInPlaceTest(vector<PcodeOp *> &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

View File

@ -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

View File

@ -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.

View File

@ -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<int4> &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<int4> &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 &paramtrial(active->getTrial(trialpos));
@ -813,7 +819,7 @@ void ParamListStandard::buildTrialMap(ParamActive *active) const
for(int4 j=0;j<slotlist.size();++j) {
if (slotlist[j] == 0) {
int4 nextslot = j; // Make copy of j, so that getAddrBySlot can change it
Address addr = curentry->getAddrBySlot(nextslot,curentry->getAlign());
Address addr = curentry->getAddrBySlot(nextslot,curentry->getAlign(),1);
int4 trialpos = active->getNumTrials();
active->registerTrial(addr,curentry->getAlign());
ParamTrial &paramtrial(active->getTrial(trialpos));

View File

@ -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<ParamEntry> &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

View File

@ -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);

View File

@ -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);

View File

@ -2835,7 +2835,7 @@ Datatype *CParse::newStruct(const string &ident,vector<TypeDeclarator *> *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);

View File

@ -1042,7 +1042,7 @@ Datatype *CParse::newStruct(const string &ident,vector<TypeDeclarator *> *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);

View File

@ -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.
///

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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<TypeField> &fd)
{
vector<TypeField>::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<TypeField> &list,int4 align)
void TypeStruct::assignFieldOffsets(vector<TypeField> &list)
{
int4 offset = 0;
vector<TypeField>::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<TypeField> &fd)
{
vector<TypeField>::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 \<type> element describing each field.
@ -1778,6 +1803,7 @@ void TypeUnion::setFields(const vector<TypeField> &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<TypeField> &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<TypeField> &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 \<size_alignment_map> 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 \<enum> XML tag. Should probably consider this deprecated. These
/// values are only used by the internal C parser.

View File

@ -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<TypeField>::const_iterator beginField(void) const { return field.begin(); } ///< Beginning of fields
vector<TypeField>::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<TypeField> &list,int4 align); ///< Assign field offsets given a byte alignment
static void assignFieldOffsets(vector<TypeField> &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<int4> 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<Datatype *> &deporder,DatatypeSet &mark,Datatype *ct) const; ///< Write out dependency list
void decodeAlignmentMap(Decoder &decoder); ///< Parse a \<size_alignment_map> element
void setDefaultAlignmentMap(void); ///< Provide default alignments for data-types
Datatype *decodeTypedef(Decoder &decoder); ///< Restore a \<def> element describing a typedef
Datatype *decodeStruct(Decoder &decoder,bool forcecore); ///< Restore a \<type> element describing a structure
Datatype *decodeUnion(Decoder &decoder,bool forcecore); ///< Restore a \<type> 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;

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -19,7 +19,6 @@ f8c30fafc7c3
</binaryimage>
<script>
<com>option readonly on</com>
<com>option structalign 1</com>
<com>parse line union myalt { int4 myint; float4 myfloat; };</com>
<com>parse line struct packstruct { int4 a; myalt u; };</com>
<com>parse line extern int4 getvalue(packstruct val,int4 sel);</com>

View File

@ -0,0 +1,103 @@
<decompilertest>
<!--
Functions manipulating longdouble data-types.
-->
<binaryimage arch="x86:LE:64:default:gcc">
<bytechunk space="ram" offset="0x100000" readonly="true">
f30f1efadb6c2408dc05aa010000488d
3deb0f0000db7c2408e9e2100000f30f
1efa4154488d3dd50f000055538b5c24
20448b6424408b6c2448ff742438ff74
2438450fbfe40fbfede8b21000000fbf
c35a594401e05b01e85d415cc3f30f1e
fa534889fbff7718ff7710488d3d8e0f
0000e889100000ff7328488d3d7f0f00
00ff7320e8771000000fbf53020fbf03
4883c42001d00fbf533001d00fbf5332
5b01d0c3
</bytechunk>
<bytechunk space="ram" offset="0x10014b" readonly="true">
f30f1efa41
548b542410488d355600000031c0bf01
000000448b642440e89b0f0000ff7424
28488d3d880e0000ff742428e87f0f00
008b542440bf0100000031c0488d351f
000000e8700f000058bf010000005a48
8d350c0000004489e231c0415ce9560f
000025640a00
</bytechunk>
<bytechunk space="ram" offset="0x1001b8" readonly="true">
6f1283c0caa13b40
</bytechunk>
<bytechunk space="ram" offset="0x1001d2" readonly="true">
f30f1efab8070000008d57074c8d
051b0e00004863cf29f84863d248c1e1
04489848c1e20441db2c1048c1e00441
db2c008d047f81e7feff0000489848c1
e70448c1e004dec141db3c08db6c3010
db3c3ec3
</bytechunk>
<bytechunk space="ram" offset="0x101100" readonly="true">
f30f1efadb6c2408d9c0db3fdc059e01
0000db7f10c3
</bytechunk>
<bytechunk space="ram" offset="0x1012b0" readonly="true">
666666666666e63f
</bytechunk>
<symbol space="ram" offset="0x100000" name="pass"/>
<symbol space="ram" offset="0x10001e" name="passmany"/>
<symbol space="ram" offset="0x10005d" name="printstruct"/>
<symbol space="ram" offset="0x1001d2" name="arrayindex"/>
<symbol space="ram" offset="0x101100" name="writeLongDouble"/>
<symbol space="ram" offset="0x101108" name="printf_chk"/>
</binaryimage>
<script>
<com>option readonly on</com>
<com>map addr r0x101000 float10 ldarr[16]</com>
<com>map fun r0x10014b printldfirst</com>
<com>override flow r0x1001ad callreturn</com>
<com>parse line struct ldstruct { int2 c; int2 d; float10 a; float10 b; int2 e; int2 f; };</com>
<com>parse line struct ldfirst { float10 a; int4 b; };</com>
<com>parse line extern void writeLongDouble(float10 *ptrwrite,float10 valwrite);</com>
<com>parse line extern void printf_chk(int4 pipe,char *str,int4 val);</com>
<com>parse line extern void pass(float10 valpass);</com>
<com>parse line extern int4 passmany(int8 a,int8 b,int8 c,int8 d,int8 e,int8 f,int2 y,float10 x,int2 z,int2 w);</com>
<com>parse line extern int4 printstruct(ldstruct *ptrldstr);</com>
<com>parse line extern void printldfirst(int8 a,int8 b,int8 c,int8 d,int8 e,int8 f,int4 v1,ldfirst firstval,int4 v2);</com>
<com>parse line extern void arrayindex(int4 val,float10 *ptr);</com>
<com>lo fu pass</com>
<com>dec</com>
<com>print C</com>
<com>lo fu passmany</com>
<com>dec</com>
<com>print C</com>
<com>lo fu printstruct</com>
<com>dec</com>
<com>print C</com>
<com>lo fu printldfirst</com>
<com>dec</com>
<com>print C</com>
<com>lo fu arrayindex</com>
<com>dec</com>
<com>print C</com>
<com>lo fu writeLongDouble</com>
<com>dec</com>
<com>print C</com>
<com>quit</com>
</script>
<stringmatch name="Long double #1" min="1" max="1">ldarr\[0\] = valpass \+ \(float10\)27\.632</stringmatch>
<stringmatch name="Long double #2" min="1" max="1">ldarr\[1\] = valpass \+ \(float10\)27\.632</stringmatch>
<stringmatch name="Long double #3" min="1" max="1">writeLongDouble\(ldarr,x\);</stringmatch>
<stringmatch name="Long double #4" min="1" max="1">return \(int4\)y \+ \(int4\)z \+ \(int4\)w;</stringmatch>
<stringmatch name="Long double #5" min="1" max="1">writeLongDouble\(ldarr,ptrldstr-&gt;a\);</stringmatch>
<stringmatch name="Long double #6" min="1" max="1">writeLongDouble\(ldarr,ptrldstr-&gt;b\);</stringmatch>
<stringmatch name="Long double #7" min="1" max="1">return \(int4\)ptrldstr-&gt;c \+ \(int4\)ptrldstr-&gt;d \+ \(int4\)ptrldstr-&gt;e \+ \(int4\)ptrldstr-&gt;f;</stringmatch>
<stringmatch name="Long double #8" min="1" max="1">printf_chk\(1,\"%d\\n\",v1\);</stringmatch>
<stringmatch name="Long double #9" min="1" max="1">printf_chk\(1,\"%d\\n\",firstval\.b\);</stringmatch>
<stringmatch name="Long double #10" min="1" max="1">printf_chk\(1,\"%d\\n\",v2\);</stringmatch>
<stringmatch name="Long double #11" min="1" max="1">writeLongDouble\(ldarr,firstval\.a\);</stringmatch>
<stringmatch name="Long double #12" min="1" max="1">\*ptrwrite = valwrite;</stringmatch>
<stringmatch name="Long double #13" min="1" max="1">ptrwrite\[1\] = valwrite \+ \(float10\)0.7;</stringmatch>
<stringmatch name="Long double #14" min="1" max="1">ldarr\[val\] = ldarr\[7 \- val\] \+ ldarr\[val \+ 7\];</stringmatch>
<stringmatch name="Long double #15" min="1" max="1">ptr\[val &amp; 0xfffe\] = ptr\[.*\(val \* 3\) \+ 1\];</stringmatch>
</decompilertest>

View File

@ -12,7 +12,7 @@
<symbol space="ram" offset="0x400517" name="readstruct"/>
</binaryimage>
<script>
<com>parse line struct twostruct { int4 field1; int4 array[5]; };</com>
<com>parse line struct twostruct { int4 field1; int4 field2; int4 array[5]; };</com>
<com>parse line extern int4 readstruct(twostruct *ptr,int8 a,int8 b);</com>
<com>lo fu readstruct</com>
<com>decompile</com>

View File

@ -22,6 +22,6 @@
<com>print C</com>
<com>quit</com>
</script>
<stringmatch name="Offset array #1" min="1" max="1">return mStack.*array\[param_1 \+ -2\]</stringmatch>
<stringmatch name="Offset array #1" min="1" max="1">return mStack.*array\[param_1 \+ -1\]</stringmatch>
<stringmatch name="Offset array #2" min="0" max="0">firstfield</stringmatch>
</decompilertest>

View File

@ -12,7 +12,6 @@
<symbol space="ram" offset="0x1006da" name="getstruct"/>
</binaryimage>
<script>
<com>option structalign 1</com>
<com>parse line struct tinystruct { int4 a; int2 b; int2 c; };</com>
<com>parse line extern tinystruct getstruct(int4 i);</com>
<com>parse line extern int4 access(int4 i);</com>

View File

@ -342,10 +342,11 @@ public class ParamEntry {
* there are not enough slots left
* @param slotnum number of slots already assigned
* @param sz number of bytes to being assigned
* @param typeAlign required byte alignment for the parameter
* @param res the final storage address
* @return slotnum plus the number of slots used
*/
public int getAddrBySlot(int slotnum, int sz, VarnodeData res) {
public int getAddrBySlot(int slotnum, int sz, int typeAlign, VarnodeData res) {
res.space = null; // Start with an invalid result
int spaceused;
if (sz < minsize) {
@ -366,6 +367,12 @@ public class ParamEntry {
}
}
else {
if (typeAlign > alignment) {
int tmp = (slotnum * alignment) % typeAlign;
if (tmp != 0) {
slotnum += (typeAlign - tmp) / alignment; // Waste slots to achieve typeAlign
}
}
int slotsused = sz / alignment; // How many slots does a -sz- byte object need
if ((sz % alignment) != 0) {
slotsused += 1;

View File

@ -98,7 +98,8 @@ public class ParamListStandard implements ParamList {
}
VarnodeData res = new VarnodeData();
status[grp] = element.getAddrBySlot(status[grp], tp.getLength(), res);
status[grp] =
element.getAddrBySlot(status[grp], tp.getAlignedLength(), tp.getAlignment(), res);
if (res.space == null) {
continue; // -tp- does not fit in this entry
}