mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
Merge remote-tracking branch 'origin/GP-4356_ghintern_avr8_cspec--SQUASHED'
This commit is contained in:
commit
88bfdeb429
17 changed files with 564 additions and 63 deletions
|
@ -773,14 +773,19 @@ void ParamListStandard::assignMap(const PrototypePieces &proto,TypeFactory &type
|
||||||
|
|
||||||
if (res.size() == 2) { // Check for hidden parameters defined by the output list
|
if (res.size() == 2) { // Check for hidden parameters defined by the output list
|
||||||
Datatype *dt = res.back().type;
|
Datatype *dt = res.back().type;
|
||||||
type_class store;
|
if ((res.back().flags & ParameterPieces::hiddenretparm) != 0) {
|
||||||
if ((res.back().flags & ParameterPieces::hiddenretparm) != 0)
|
// Need to pull from registers marked as hiddenret
|
||||||
store = TYPECLASS_HIDDENRET;
|
if (assignAddressFallback(TYPECLASS_HIDDENRET,dt,false,status,res.back()) == AssignAction::fail) {
|
||||||
else
|
throw ParamUnassignedError("Cannot assign parameter address for " + res.back().type->getName());
|
||||||
store = metatype2typeclass(dt->getMetatype());
|
}
|
||||||
// Reserve first param for hidden return pointer
|
}
|
||||||
if (assignAddressFallback(store,dt,false,status,res.back()) == AssignAction::fail)
|
else {
|
||||||
throw ParamUnassignedError("Cannot assign parameter address for " + res.back().type->getName());
|
// Assign as a regular first input pointer parameter
|
||||||
|
if (assignAddress(dt,proto,0,typefactory,status,res.back()) == AssignAction::fail) {
|
||||||
|
throw ParamUnassignedError("Cannot assign parameter address for " + res.back().type->getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
res.back().flags |= ParameterPieces::hiddenretparm;
|
res.back().flags |= ParameterPieces::hiddenretparm;
|
||||||
}
|
}
|
||||||
for(int4 i=0;i<proto.intypes.size();++i) {
|
for(int4 i=0;i<proto.intypes.size();++i) {
|
||||||
|
@ -1573,8 +1578,10 @@ void ParamListStandardOut::assignMap(const PrototypePieces &proto,TypeFactory &t
|
||||||
res.back().type = typefactory.getTypeVoid();
|
res.back().type = typefactory.getTypeVoid();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (assignAddressFallback(TYPECLASS_PTR,pointertp,false,status,res.back()) == AssignAction::fail)
|
res.back().type = pointertp;
|
||||||
throw ParamUnassignedError("Cannot assign return value as a pointer");
|
if (assignAddress(pointertp,proto,-1,typefactory,status,res.back()) == AssignAction::fail) {
|
||||||
|
throw ParamUnassignedError("Cannot assign return value as a pointer");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
res.back().flags = ParameterPieces::indirectstorage;
|
res.back().flags = ParameterPieces::indirectstorage;
|
||||||
|
|
||||||
|
|
|
@ -1254,8 +1254,7 @@ AttributeId ATTRIB_WORDSIZE = AttributeId("wordsize",26);
|
||||||
AttributeId ATTRIB_STORAGE = AttributeId("storage",149);
|
AttributeId ATTRIB_STORAGE = AttributeId("storage",149);
|
||||||
AttributeId ATTRIB_STACKSPILL = AttributeId("stackspill",150);
|
AttributeId ATTRIB_STACKSPILL = AttributeId("stackspill",150);
|
||||||
|
|
||||||
AttributeId ATTRIB_UNKNOWN = AttributeId("XMLunknown",154); // Number serves as next open index
|
AttributeId ATTRIB_UNKNOWN = AttributeId("XMLunknown",156); // Number serves as next open index
|
||||||
|
|
||||||
|
|
||||||
ElementId ELEM_DATA = ElementId("data",1);
|
ElementId ELEM_DATA = ElementId("data",1);
|
||||||
ElementId ELEM_INPUT = ElementId("input",2);
|
ElementId ELEM_INPUT = ElementId("input",2);
|
||||||
|
@ -1268,6 +1267,6 @@ ElementId ELEM_VAL = ElementId("val",8);
|
||||||
ElementId ELEM_VALUE = ElementId("value",9);
|
ElementId ELEM_VALUE = ElementId("value",9);
|
||||||
ElementId ELEM_VOID = ElementId("void",10);
|
ElementId ELEM_VOID = ElementId("void",10);
|
||||||
|
|
||||||
ElementId ELEM_UNKNOWN = ElementId("XMLunknown",288); // Number serves as next open index
|
ElementId ELEM_UNKNOWN = ElementId("XMLunknown",289); // Number serves as next open index
|
||||||
|
|
||||||
} // End namespace ghidra
|
} // End namespace ghidra
|
||||||
|
|
|
@ -20,6 +20,8 @@ namespace ghidra {
|
||||||
|
|
||||||
AttributeId ATTRIB_SIZES = AttributeId("sizes",151);
|
AttributeId ATTRIB_SIZES = AttributeId("sizes",151);
|
||||||
AttributeId ATTRIB_MAX_PRIMITIVES = AttributeId("maxprimitives", 153);
|
AttributeId ATTRIB_MAX_PRIMITIVES = AttributeId("maxprimitives", 153);
|
||||||
|
AttributeId ATTRIB_REVERSESIGNIF = AttributeId("reversesignif", 154);
|
||||||
|
AttributeId ATTRIB_MATCHSIZE = AttributeId("matchsize", 155);
|
||||||
|
|
||||||
ElementId ELEM_DATATYPE = ElementId("datatype",273);
|
ElementId ELEM_DATATYPE = ElementId("datatype",273);
|
||||||
ElementId ELEM_CONSUME = ElementId("consume",274);
|
ElementId ELEM_CONSUME = ElementId("consume",274);
|
||||||
|
@ -34,6 +36,7 @@ ElementId ELEM_HIDDEN_RETURN = ElementId("hidden_return",282);
|
||||||
ElementId ELEM_JOIN_PER_PRIMITIVE = ElementId("join_per_primitive",283);
|
ElementId ELEM_JOIN_PER_PRIMITIVE = ElementId("join_per_primitive",283);
|
||||||
ElementId ELEM_JOIN_DUAL_CLASS = ElementId("join_dual_class",285);
|
ElementId ELEM_JOIN_DUAL_CLASS = ElementId("join_dual_class",285);
|
||||||
ElementId ELEM_EXTRA_STACK = ElementId("extra_stack",287);
|
ElementId ELEM_EXTRA_STACK = ElementId("extra_stack",287);
|
||||||
|
ElementId ELEM_CONSUME_REMAINING = ElementId("consume_remaining",288);
|
||||||
|
|
||||||
/// \brief Check that a big Primitive properly overlaps smaller Primitives
|
/// \brief Check that a big Primitive properly overlaps smaller Primitives
|
||||||
///
|
///
|
||||||
|
@ -619,6 +622,29 @@ AssignAction *AssignAction::decodeAction(Decoder &decoder,const ParamListStandar
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Read the next model rule precondition element from the stream
|
||||||
|
///
|
||||||
|
/// Allocate the precondition object corresponding to the element and configure it.
|
||||||
|
/// If the next element is not a precondition, return null.
|
||||||
|
/// \param decoder is the stream decoder
|
||||||
|
/// \param res is the resource set for the new precondition
|
||||||
|
/// \return the new precondition, or null if no more preconditions are in the stream
|
||||||
|
AssignAction *AssignAction::decodePrecondition(Decoder &decoder,const ParamListStandard *res)
|
||||||
|
{
|
||||||
|
AssignAction *action;
|
||||||
|
uint4 elemId = decoder.peekElement();
|
||||||
|
|
||||||
|
if (elemId == ELEM_CONSUME_EXTRA) {
|
||||||
|
action = new ConsumeExtra(res);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return (AssignAction *)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
action->decode(decoder);
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Read the next model rule sideeffect element from the stream
|
/// \brief Read the next model rule sideeffect element from the stream
|
||||||
///
|
///
|
||||||
/// Allocate the sideeffect object corresponding to the element and configure it.
|
/// Allocate the sideeffect object corresponding to the element and configure it.
|
||||||
|
@ -638,6 +664,9 @@ AssignAction *AssignAction::decodeSideeffect(Decoder &decoder,const ParamListSta
|
||||||
else if (elemId == ELEM_EXTRA_STACK) {
|
else if (elemId == ELEM_EXTRA_STACK) {
|
||||||
action = new ExtraStack(res,0);
|
action = new ExtraStack(res,0);
|
||||||
}
|
}
|
||||||
|
else if (elemId == ELEM_CONSUME_REMAINING) {
|
||||||
|
action = new ConsumeRemaining(res);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
throw DecoderError("Expecting model rule sideeffect");
|
throw DecoderError("Expecting model rule sideeffect");
|
||||||
action->decode(decoder);
|
action->decode(decoder);
|
||||||
|
@ -911,8 +940,12 @@ void MultiSlotAssign::decode(Decoder &decoder)
|
||||||
if (attribId == 0) break;
|
if (attribId == 0) break;
|
||||||
if (attribId == ATTRIB_REVERSEJUSTIFY) {
|
if (attribId == ATTRIB_REVERSEJUSTIFY) {
|
||||||
if (decoder.readBool())
|
if (decoder.readBool())
|
||||||
justifyRight = !justifyRight;
|
justifyRight = !justifyRight;
|
||||||
}
|
}
|
||||||
|
else if (attribId == ATTRIB_REVERSESIGNIF) {
|
||||||
|
if (decoder.readBool())
|
||||||
|
consumeMostSig = !consumeMostSig;
|
||||||
|
}
|
||||||
else if (attribId == ATTRIB_STORAGE) {
|
else if (attribId == ATTRIB_STORAGE) {
|
||||||
resourceType = string2typeclass(decoder.readString());
|
resourceType = string2typeclass(decoder.readString());
|
||||||
}
|
}
|
||||||
|
@ -1216,8 +1249,12 @@ void MultiSlotDualAssign::decode(Decoder &decoder)
|
||||||
if (attribId == 0) break;
|
if (attribId == 0) break;
|
||||||
if (attribId == ATTRIB_REVERSEJUSTIFY) {
|
if (attribId == ATTRIB_REVERSEJUSTIFY) {
|
||||||
if (decoder.readBool())
|
if (decoder.readBool())
|
||||||
justifyRight = !justifyRight;
|
justifyRight = !justifyRight;
|
||||||
}
|
}
|
||||||
|
else if (attribId == ATTRIB_REVERSESIGNIF) {
|
||||||
|
if (decoder.readBool())
|
||||||
|
consumeMostSig = !consumeMostSig;
|
||||||
|
}
|
||||||
else if (attribId == ATTRIB_STORAGE || attribId == ATTRIB_A) {
|
else if (attribId == ATTRIB_STORAGE || attribId == ATTRIB_A) {
|
||||||
baseType = string2typeclass(decoder.readString());
|
baseType = string2typeclass(decoder.readString());
|
||||||
}
|
}
|
||||||
|
@ -1353,6 +1390,61 @@ void ConsumeExtra::decode(Decoder &decoder)
|
||||||
|
|
||||||
{
|
{
|
||||||
uint4 elemId = decoder.openElement(ELEM_CONSUME_EXTRA);
|
uint4 elemId = decoder.openElement(ELEM_CONSUME_EXTRA);
|
||||||
|
for(;;) {
|
||||||
|
uint4 attribId = decoder.getNextAttributeId();
|
||||||
|
if (attribId == 0) break;
|
||||||
|
else if (attribId == ATTRIB_STORAGE) {
|
||||||
|
resourceType = string2typeclass(decoder.readString());
|
||||||
|
}
|
||||||
|
else if (attribId == ATTRIB_MATCHSIZE) {
|
||||||
|
matchSize = decoder.readBool();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
decoder.closeElement(elemId);
|
||||||
|
initializeEntries();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Find the first ParamEntry matching the \b resourceType.
|
||||||
|
void ConsumeRemaining::initializeEntries(void)
|
||||||
|
|
||||||
|
{
|
||||||
|
resource->extractTiles(tiles,resourceType);
|
||||||
|
if (tiles.size() == 0)
|
||||||
|
throw LowlevelError("Could not find matching resources for action: consume_remaining");
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsumeRemaining::ConsumeRemaining(const ParamListStandard *res)
|
||||||
|
: AssignAction(res)
|
||||||
|
{
|
||||||
|
resourceType = TYPECLASS_GENERAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConsumeRemaining::ConsumeRemaining(type_class store,const ParamListStandard *res)
|
||||||
|
: AssignAction(res)
|
||||||
|
{
|
||||||
|
resourceType = store;
|
||||||
|
initializeEntries();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint4 ConsumeRemaining::assignAddress(Datatype *dt,const PrototypePieces &proto,int4 pos,TypeFactory &tlist,
|
||||||
|
vector<int4> &status,ParameterPieces &res) const
|
||||||
|
{
|
||||||
|
int4 iter = 0;
|
||||||
|
while(iter != tiles.size()) {
|
||||||
|
const ParamEntry *entry = tiles[iter];
|
||||||
|
++iter;
|
||||||
|
if (status[entry->getGroup()] != 0)
|
||||||
|
continue; // Already consumed
|
||||||
|
status[entry->getGroup()] = -1; // Consume the slot/register
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConsumeRemaining::decode(Decoder &decoder)
|
||||||
|
|
||||||
|
{
|
||||||
|
uint4 elemId = decoder.openElement(ELEM_CONSUME_REMAINING);
|
||||||
resourceType = string2typeclass(decoder.readString(ATTRIB_STORAGE));
|
resourceType = string2typeclass(decoder.readString(ATTRIB_STORAGE));
|
||||||
decoder.closeElement(elemId);
|
decoder.closeElement(elemId);
|
||||||
initializeEntries();
|
initializeEntries();
|
||||||
|
@ -1416,6 +1508,8 @@ ModelRule::ModelRule(const ModelRule &op2,const ParamListStandard *res)
|
||||||
assign = op2.assign->clone(res);
|
assign = op2.assign->clone(res);
|
||||||
else
|
else
|
||||||
assign = (AssignAction *)0;
|
assign = (AssignAction *)0;
|
||||||
|
for (int4 i=0;i<op2.preconditions.size();++i)
|
||||||
|
preconditions.push_back(op2.preconditions[i]->clone(res));
|
||||||
for(int4 i=0;i<op2.sideeffects.size();++i)
|
for(int4 i=0;i<op2.sideeffects.size();++i)
|
||||||
sideeffects.push_back(op2.sideeffects[i]->clone(res));
|
sideeffects.push_back(op2.sideeffects[i]->clone(res));
|
||||||
}
|
}
|
||||||
|
@ -1441,6 +1535,8 @@ ModelRule::~ModelRule(void)
|
||||||
delete qualifier;
|
delete qualifier;
|
||||||
if (assign != (AssignAction *)0)
|
if (assign != (AssignAction *)0)
|
||||||
delete assign;
|
delete assign;
|
||||||
|
for(int4 i=0;i<preconditions.size();++i)
|
||||||
|
delete preconditions[i];
|
||||||
for(int4 i=0;i<sideeffects.size();++i)
|
for(int4 i=0;i<sideeffects.size();++i)
|
||||||
delete sideeffects[i];
|
delete sideeffects[i];
|
||||||
}
|
}
|
||||||
|
@ -1467,8 +1563,13 @@ uint4 ModelRule::assignAddress(Datatype *dt,const PrototypePieces &proto,int4 po
|
||||||
if (qualifier != (QualifierFilter *)0 && !qualifier->filter(proto,pos)) {
|
if (qualifier != (QualifierFilter *)0 && !qualifier->filter(proto,pos)) {
|
||||||
return AssignAction::fail;
|
return AssignAction::fail;
|
||||||
}
|
}
|
||||||
uint4 response = assign->assignAddress(dt,proto,pos,tlist,status,res);
|
vector<int4> tmpStatus = status;
|
||||||
|
for(int4 i =0;i<preconditions.size();++i) {
|
||||||
|
preconditions[i]->assignAddress(dt,proto,pos,tlist,tmpStatus,res);
|
||||||
|
}
|
||||||
|
uint4 response = assign->assignAddress(dt,proto,pos,tlist,tmpStatus,res);
|
||||||
if (response != AssignAction::fail) {
|
if (response != AssignAction::fail) {
|
||||||
|
status = tmpStatus;
|
||||||
for(int4 i=0;i<sideeffects.size();++i) {
|
for(int4 i=0;i<sideeffects.size();++i) {
|
||||||
sideeffects[i]->assignAddress(dt,proto,pos,tlist,status,res);
|
sideeffects[i]->assignAddress(dt,proto,pos,tlist,status,res);
|
||||||
}
|
}
|
||||||
|
@ -1499,6 +1600,12 @@ void ModelRule::decode(Decoder &decoder,const ParamListStandard *res)
|
||||||
else {
|
else {
|
||||||
qualifier = new AndFilter(qualifiers);
|
qualifier = new AndFilter(qualifiers);
|
||||||
}
|
}
|
||||||
|
for (;;) {
|
||||||
|
AssignAction *precond = AssignAction::decodePrecondition(decoder, res);
|
||||||
|
if (precond == (AssignAction *)0)
|
||||||
|
break;
|
||||||
|
preconditions.push_back(precond);
|
||||||
|
}
|
||||||
assign = AssignAction::decodeAction(decoder, res);
|
assign = AssignAction::decodeAction(decoder, res);
|
||||||
while(decoder.peekElement() != 0) {
|
while(decoder.peekElement() != 0) {
|
||||||
sideeffects.push_back(AssignAction::decodeSideeffect(decoder,res));
|
sideeffects.push_back(AssignAction::decodeSideeffect(decoder,res));
|
||||||
|
|
|
@ -30,6 +30,8 @@ class ParamActive;
|
||||||
|
|
||||||
extern AttributeId ATTRIB_SIZES; ///< Marshaling attribute "sizes"
|
extern AttributeId ATTRIB_SIZES; ///< Marshaling attribute "sizes"
|
||||||
extern AttributeId ATTRIB_MAX_PRIMITIVES; ///< Marshaling attribute "maxprimitives"
|
extern AttributeId ATTRIB_MAX_PRIMITIVES; ///< Marshaling attribute "maxprimitives"
|
||||||
|
extern AttributeId ATTRIB_REVERSESIGNIF; ///< Marshaling attribute "reversesignif"
|
||||||
|
extern AttributeId ATTRIB_MATCHSIZE; ///< Marshaling attribute "matchsize"
|
||||||
|
|
||||||
extern ElementId ELEM_DATATYPE; ///< Marshaling element \<datatype>
|
extern ElementId ELEM_DATATYPE; ///< Marshaling element \<datatype>
|
||||||
extern ElementId ELEM_CONSUME; ///< Marshaling element \<consume>
|
extern ElementId ELEM_CONSUME; ///< Marshaling element \<consume>
|
||||||
|
@ -44,6 +46,7 @@ extern ElementId ELEM_HIDDEN_RETURN; ///< Marshaling element \<hidden_return>
|
||||||
extern ElementId ELEM_JOIN_PER_PRIMITIVE; ///< Marshaling element \<join_per_primitive>
|
extern ElementId ELEM_JOIN_PER_PRIMITIVE; ///< Marshaling element \<join_per_primitive>
|
||||||
extern ElementId ELEM_JOIN_DUAL_CLASS; ///< Marshaling element \<join_dual_class>
|
extern ElementId ELEM_JOIN_DUAL_CLASS; ///< Marshaling element \<join_dual_class>
|
||||||
extern ElementId ELEM_EXTRA_STACK; ///< Marshaling element \<extra_stack>
|
extern ElementId ELEM_EXTRA_STACK; ///< Marshaling element \<extra_stack>
|
||||||
|
extern ElementId ELEM_CONSUME_REMAINING; ///< Marshaling element \<consume_remaining>
|
||||||
|
|
||||||
/// \brief Class for extracting primitive elements of a data-type
|
/// \brief Class for extracting primitive elements of a data-type
|
||||||
///
|
///
|
||||||
|
@ -311,6 +314,7 @@ public:
|
||||||
/// \param decoder is the given stream decoder
|
/// \param decoder is the given stream decoder
|
||||||
virtual void decode(Decoder &decoder)=0;
|
virtual void decode(Decoder &decoder)=0;
|
||||||
static AssignAction *decodeAction(Decoder &decoder,const ParamListStandard *res);
|
static AssignAction *decodeAction(Decoder &decoder,const ParamListStandard *res);
|
||||||
|
static AssignAction *decodePrecondition(Decoder &decoder, const ParamListStandard *res);
|
||||||
static AssignAction *decodeSideeffect(Decoder &decoder,const ParamListStandard *res);
|
static AssignAction *decodeSideeffect(Decoder &decoder,const ParamListStandard *res);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -492,6 +496,26 @@ public:
|
||||||
virtual void decode(Decoder &decoder);
|
virtual void decode(Decoder &decoder);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// \brief Consume all the remaining registers from a given resource list
|
||||||
|
///
|
||||||
|
/// This action is a side-effect and doesn't assign an address for the current parameter.
|
||||||
|
/// The resource list, resourceType, is specified. If the side-effect is triggered, all register
|
||||||
|
/// resources from this list are consumed, until no registers remain. If all registers are already
|
||||||
|
/// consumed, no action is taken.
|
||||||
|
class ConsumeRemaining : public AssignAction {
|
||||||
|
type_class resourceType; ///< The other resource list to consume from
|
||||||
|
vector<const ParamEntry *> tiles; ///< List of registers that can be consumed
|
||||||
|
void initializeEntries(void); ///< Cache specific ParamEntry needed by the action
|
||||||
|
public:
|
||||||
|
ConsumeRemaining(const ParamListStandard *res); ///< Constructor for use with decode
|
||||||
|
ConsumeRemaining(type_class store, const ParamListStandard *res); ///< Constructor
|
||||||
|
virtual AssignAction *clone(const ParamListStandard *newResource) const {
|
||||||
|
return new ConsumeRemaining(resourceType,newResource); }
|
||||||
|
virtual uint4 assignAddress(Datatype *dt,const PrototypePieces &proto,int4 pos,TypeFactory &tlist,
|
||||||
|
vector<int4> &status,ParameterPieces &res) const;
|
||||||
|
virtual void decode(Decoder &decoder);
|
||||||
|
};
|
||||||
|
|
||||||
/// \brief A rule controlling how parameters are assigned addresses
|
/// \brief A rule controlling how parameters are assigned addresses
|
||||||
///
|
///
|
||||||
/// Rules are applied to a parameter in the context of a full function prototype.
|
/// Rules are applied to a parameter in the context of a full function prototype.
|
||||||
|
@ -502,6 +526,7 @@ class ModelRule {
|
||||||
DatatypeFilter *filter; ///< Which data-types \b this rule applies to
|
DatatypeFilter *filter; ///< Which data-types \b this rule applies to
|
||||||
QualifierFilter *qualifier; ///< Additional qualifiers for when the rule should apply (if non-null)
|
QualifierFilter *qualifier; ///< Additional qualifiers for when the rule should apply (if non-null)
|
||||||
AssignAction *assign; ///< How the Address should be assigned
|
AssignAction *assign; ///< How the Address should be assigned
|
||||||
|
vector<AssignAction *> preconditions; ///< Extra actions that happen before assignment, discarded on failure
|
||||||
vector<AssignAction *> sideeffects; ///< Extra actions that happen on success
|
vector<AssignAction *> sideeffects; ///< Extra actions that happen on success
|
||||||
public:
|
public:
|
||||||
ModelRule(void) {
|
ModelRule(void) {
|
||||||
|
|
|
@ -379,6 +379,16 @@
|
||||||
</element>
|
</element>
|
||||||
</zeroOrMore>
|
</zeroOrMore>
|
||||||
</interleave>
|
</interleave>
|
||||||
|
<zeroOrMore>
|
||||||
|
<element name="consume_extra">
|
||||||
|
<attribute name="storage"/>
|
||||||
|
<optional>
|
||||||
|
<attribute name="matchsize">
|
||||||
|
<ref name="boolean_type"/>
|
||||||
|
</attribute>
|
||||||
|
</optional>
|
||||||
|
</element>
|
||||||
|
</zeroOrMore>
|
||||||
<choice>
|
<choice>
|
||||||
<element name="consume">
|
<element name="consume">
|
||||||
<attribute name="storage"/>
|
<attribute name="storage"/>
|
||||||
|
@ -395,6 +405,11 @@
|
||||||
<ref name="boolean_type"/>
|
<ref name="boolean_type"/>
|
||||||
</attribute>
|
</attribute>
|
||||||
</optional>
|
</optional>
|
||||||
|
<optional>
|
||||||
|
<attribute name="reversesignif">
|
||||||
|
<ref name="boolean_type"/>
|
||||||
|
</attribute>
|
||||||
|
</optional>
|
||||||
<optional>
|
<optional>
|
||||||
<attribute name="align">
|
<attribute name="align">
|
||||||
<ref name="boolean_type"/>
|
<ref name="boolean_type"/>
|
||||||
|
@ -430,6 +445,11 @@
|
||||||
<ref name="boolean_type"/>
|
<ref name="boolean_type"/>
|
||||||
</attribute>
|
</attribute>
|
||||||
</optional>
|
</optional>
|
||||||
|
<optional>
|
||||||
|
<attribute name="reversesignif">
|
||||||
|
<ref name="boolean_type"/>
|
||||||
|
</attribute>
|
||||||
|
</optional>
|
||||||
<optional>
|
<optional>
|
||||||
<attribute name="storage"/>
|
<attribute name="storage"/>
|
||||||
</optional>
|
</optional>
|
||||||
|
@ -444,6 +464,16 @@
|
||||||
<zeroOrMore>
|
<zeroOrMore>
|
||||||
<element name="consume_extra">
|
<element name="consume_extra">
|
||||||
<attribute name="storage"/>
|
<attribute name="storage"/>
|
||||||
|
<optional>
|
||||||
|
<attribute name="matchsize">
|
||||||
|
<ref name="boolean_type"/>
|
||||||
|
</attribute>
|
||||||
|
</optional>
|
||||||
|
</element>
|
||||||
|
</zeroOrMore>
|
||||||
|
<zeroOrMore>
|
||||||
|
<element name="consume_remaining">
|
||||||
|
<attribute name="storage"/>
|
||||||
</element>
|
</element>
|
||||||
</zeroOrMore>
|
</zeroOrMore>
|
||||||
<zeroOrMore>
|
<zeroOrMore>
|
||||||
|
|
|
@ -177,14 +177,14 @@ public class ParamListStandard implements ParamList {
|
||||||
|
|
||||||
if (addAutoParams && res.size() == 2) { // Check for hidden parameters defined by the output list
|
if (addAutoParams && res.size() == 2) { // Check for hidden parameters defined by the output list
|
||||||
ParameterPieces last = res.get(res.size() - 1);
|
ParameterPieces last = res.get(res.size() - 1);
|
||||||
StorageClass store;
|
|
||||||
if (last.hiddenReturnPtr) {
|
if (last.hiddenReturnPtr) {
|
||||||
store = StorageClass.HIDDENRET;
|
// Need to pull from registers marked as hiddenret
|
||||||
|
assignAddressFallback(StorageClass.HIDDENRET, last.type, false, status, last);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
store = ParamEntry.getBasicTypeClass(last.type);
|
// Assign as a regular first input pointer parameter
|
||||||
|
assignAddress(last.type, proto, 0, dtManager, status, last);
|
||||||
}
|
}
|
||||||
assignAddressFallback(store, last.type, false, status, last);
|
|
||||||
last.hiddenReturnPtr = true;
|
last.hiddenReturnPtr = true;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < proto.intypes.size(); ++i) {
|
for (int i = 0; i < proto.intypes.size(); ++i) {
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -64,9 +64,10 @@ public class ParamListStandardOut extends ParamListStandard {
|
||||||
store.type = VoidDataType.dataType;
|
store.type = VoidDataType.dataType;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
assignAddressFallback(StorageClass.PTR, pointerType, false, status, store);
|
|
||||||
store.type = pointerType;
|
store.type = pointerType;
|
||||||
|
assignAddress(pointerType, proto, -1, dtManager, status, store);
|
||||||
}
|
}
|
||||||
|
|
||||||
store.isIndirect = true; // Signal that there is a hidden return
|
store.isIndirect = true; // Signal that there is a hidden return
|
||||||
if (addAutoParams) {
|
if (addAutoParams) {
|
||||||
ParameterPieces hiddenRet = new ParameterPieces();
|
ParameterPieces hiddenRet = new ParameterPieces();
|
||||||
|
|
|
@ -157,10 +157,38 @@ public abstract class AssignAction {
|
||||||
else if (nm.equals(ELEM_EXTRA_STACK.name())) {
|
else if (nm.equals(ELEM_EXTRA_STACK.name())) {
|
||||||
action = new ExtraStack(res, 0);
|
action = new ExtraStack(res, 0);
|
||||||
}
|
}
|
||||||
|
else if (nm.equals(ELEM_CONSUME_REMAINING.name())) {
|
||||||
|
action = new ConsumeRemaining(res);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
throw new XmlParseException("Unknown model rule sideeffect: " + nm);
|
throw new XmlParseException("Unknown model rule sideeffect: " + nm);
|
||||||
}
|
}
|
||||||
action.restoreXml(parser);
|
action.restoreXml(parser);
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read the next precondition element from the stream, if it exists. Return the new configured
|
||||||
|
* AssignAction object. If the next element is not a precondition, return null.
|
||||||
|
* @param parser is the stream parser
|
||||||
|
* @param res is the resource set for the new precondition
|
||||||
|
* @return the new precondition, or null if no more preconditions are in the stream
|
||||||
|
* @throws XmlParseException if the precondition XML is malformed
|
||||||
|
*/
|
||||||
|
static public AssignAction restorePreconditionXml(XmlPullParser parser, ParamListStandard res)
|
||||||
|
throws XmlParseException {
|
||||||
|
AssignAction action;
|
||||||
|
XmlElement elemId = parser.peek();
|
||||||
|
String nm = elemId.getName();
|
||||||
|
|
||||||
|
if (nm.equals(ELEM_CONSUME_EXTRA.name())) {
|
||||||
|
action = new ConsumeExtra(res);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
action.restoreXml(parser);
|
||||||
|
return action;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,12 +19,14 @@ import static ghidra.program.model.pcode.AttributeId.*;
|
||||||
import static ghidra.program.model.pcode.ElementId.*;
|
import static ghidra.program.model.pcode.ElementId.*;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
import ghidra.program.model.data.DataType;
|
import ghidra.program.model.data.DataType;
|
||||||
import ghidra.program.model.data.DataTypeManager;
|
import ghidra.program.model.data.DataTypeManager;
|
||||||
import ghidra.program.model.lang.*;
|
import ghidra.program.model.lang.*;
|
||||||
import ghidra.program.model.pcode.Encoder;
|
import ghidra.program.model.pcode.Encoder;
|
||||||
import ghidra.util.exception.InvalidInputException;
|
import ghidra.util.exception.InvalidInputException;
|
||||||
|
import ghidra.util.xml.SpecXmlUtils;
|
||||||
import ghidra.xml.*;
|
import ghidra.xml.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -119,13 +121,22 @@ public class ConsumeExtra extends AssignAction {
|
||||||
public void encode(Encoder encoder) throws IOException {
|
public void encode(Encoder encoder) throws IOException {
|
||||||
encoder.openElement(ELEM_CONSUME_EXTRA);
|
encoder.openElement(ELEM_CONSUME_EXTRA);
|
||||||
encoder.writeString(ATTRIB_STORAGE, resourceType.toString());
|
encoder.writeString(ATTRIB_STORAGE, resourceType.toString());
|
||||||
|
encoder.writeBool(ATTRIB_MATCHSIZE, matchSize);
|
||||||
encoder.closeElement(ELEM_CONSUME_EXTRA);
|
encoder.closeElement(ELEM_CONSUME_EXTRA);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void restoreXml(XmlPullParser parser) throws XmlParseException {
|
public void restoreXml(XmlPullParser parser) throws XmlParseException {
|
||||||
XmlElement elem = parser.start(ELEM_CONSUME_EXTRA.name());
|
XmlElement elem = parser.start(ELEM_CONSUME_EXTRA.name());
|
||||||
resourceType = StorageClass.getClass(elem.getAttribute(ATTRIB_STORAGE.name()));
|
for (Entry<String, String> attrib : elem.getAttributes().entrySet()) {
|
||||||
|
String name = attrib.getKey();
|
||||||
|
if (name.equals(ATTRIB_STORAGE.name())) {
|
||||||
|
resourceType = StorageClass.getClass(attrib.getValue());
|
||||||
|
}
|
||||||
|
else if (name.equals(ATTRIB_MATCHSIZE.name())) {
|
||||||
|
matchSize = SpecXmlUtils.decodeBoolean(attrib.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
parser.end(elem);
|
parser.end(elem);
|
||||||
try {
|
try {
|
||||||
initializeEntries();
|
initializeEntries();
|
||||||
|
|
|
@ -0,0 +1,128 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.program.model.lang.protorules;
|
||||||
|
|
||||||
|
import static ghidra.program.model.pcode.AttributeId.*;
|
||||||
|
import static ghidra.program.model.pcode.ElementId.*;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import ghidra.program.model.data.DataType;
|
||||||
|
import ghidra.program.model.data.DataTypeManager;
|
||||||
|
import ghidra.program.model.lang.*;
|
||||||
|
import ghidra.program.model.pcode.Encoder;
|
||||||
|
import ghidra.util.exception.InvalidInputException;
|
||||||
|
import ghidra.xml.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Consume all the remaining registers from a given resource list
|
||||||
|
*
|
||||||
|
* This action is a side-effect and doesn't assign an address for the current parameter.
|
||||||
|
* The resource list, resourceType, is specified. If the side-effect is triggered, all register
|
||||||
|
* resources from this list are consumed, until no registers remain. If all registers are already
|
||||||
|
* consumed, no action is taken.
|
||||||
|
*/
|
||||||
|
public class ConsumeRemaining extends AssignAction {
|
||||||
|
|
||||||
|
private StorageClass resourceType; // The resource list to consume from
|
||||||
|
private ParamEntry[] tiles; // Registers that can be consumed
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache specific ParamEntry needed by the action
|
||||||
|
* Find the first ParamEntry matching the resourceType
|
||||||
|
* @throws InvalidInputException if it cannot find the configured ParamEntry objects
|
||||||
|
*/
|
||||||
|
private void initializeEntries() throws InvalidInputException {
|
||||||
|
tiles = resource.extractTiles(resourceType);
|
||||||
|
if (tiles.length == 0) {
|
||||||
|
throw new InvalidInputException(
|
||||||
|
"Could not find matching resources for action: consume_remaining");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ConsumeRemaining(ParamListStandard res) {
|
||||||
|
super(res);
|
||||||
|
resourceType = StorageClass.GENERAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConsumeRemaining(StorageClass store, ParamListStandard res)
|
||||||
|
throws InvalidInputException {
|
||||||
|
super(res);
|
||||||
|
resourceType = store;
|
||||||
|
initializeEntries();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AssignAction clone(ParamListStandard newResource) throws InvalidInputException {
|
||||||
|
return new ConsumeRemaining(resourceType, newResource);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEquivalent(AssignAction op) {
|
||||||
|
if (this.getClass() != op.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ConsumeRemaining otherAction = (ConsumeRemaining) op;
|
||||||
|
if (resourceType != otherAction.resourceType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (tiles.length != otherAction.tiles.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < tiles.length; ++i) {
|
||||||
|
if (!tiles[i].isEquivalent(otherAction.tiles[i])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int assignAddress(DataType dt, PrototypePieces proto, int pos, DataTypeManager dtManager,
|
||||||
|
int[] status, ParameterPieces res) {
|
||||||
|
int iter = 0;
|
||||||
|
while (iter != tiles.length) {
|
||||||
|
ParamEntry entry = tiles[iter];
|
||||||
|
++iter;
|
||||||
|
if (status[entry.getGroup()] != 0) {
|
||||||
|
continue; // Already consumed
|
||||||
|
}
|
||||||
|
status[entry.getGroup()] = -1;
|
||||||
|
}
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void encode(Encoder encoder) throws IOException {
|
||||||
|
encoder.openElement(ELEM_CONSUME_REMAINING);
|
||||||
|
encoder.writeString(ATTRIB_STORAGE, resourceType.toString());
|
||||||
|
encoder.closeElement(ELEM_CONSUME_REMAINING);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void restoreXml(XmlPullParser parser) throws XmlParseException {
|
||||||
|
XmlElement elem = parser.start(ELEM_CONSUME_REMAINING.name());
|
||||||
|
resourceType = StorageClass.getClass(elem.getAttribute(ATTRIB_STORAGE.name()));
|
||||||
|
parser.end(elem);
|
||||||
|
try {
|
||||||
|
initializeEntries();
|
||||||
|
}
|
||||||
|
catch (InvalidInputException e) {
|
||||||
|
throw new XmlParseException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -39,6 +39,7 @@ public class ModelRule {
|
||||||
private DatatypeFilter filter; // Which data-types this rule applies to
|
private DatatypeFilter filter; // Which data-types this rule applies to
|
||||||
private QualifierFilter qualifier; // Additional qualifiers for when the rule should apply (if non-null)
|
private QualifierFilter qualifier; // Additional qualifiers for when the rule should apply (if non-null)
|
||||||
private AssignAction assign; // How the Address should be assigned
|
private AssignAction assign; // How the Address should be assigned
|
||||||
|
private AssignAction[] preconditions; // Extra actions that happen before assignment, discarded on failure
|
||||||
private AssignAction[] sideeffects; // Extra actions that happen on success
|
private AssignAction[] sideeffects; // Extra actions that happen on success
|
||||||
|
|
||||||
public ModelRule() {
|
public ModelRule() {
|
||||||
|
@ -72,6 +73,12 @@ public class ModelRule {
|
||||||
else {
|
else {
|
||||||
assign = null;
|
assign = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
preconditions = new AssignAction[op2.preconditions.length];
|
||||||
|
for (int i = 0; i < op2.preconditions.length; ++i) {
|
||||||
|
preconditions[i] = op2.preconditions[i].clone(res);
|
||||||
|
}
|
||||||
|
|
||||||
sideeffects = new AssignAction[op2.sideeffects.length];
|
sideeffects = new AssignAction[op2.sideeffects.length];
|
||||||
for (int i = 0; i < op2.sideeffects.length; ++i) {
|
for (int i = 0; i < op2.sideeffects.length; ++i) {
|
||||||
sideeffects[i] = op2.sideeffects[i].clone(res);
|
sideeffects[i] = op2.sideeffects[i].clone(res);
|
||||||
|
@ -94,6 +101,7 @@ public class ModelRule {
|
||||||
filter = typeFilter.clone();
|
filter = typeFilter.clone();
|
||||||
qualifier = null;
|
qualifier = null;
|
||||||
assign = action.clone(res);
|
assign = action.clone(res);
|
||||||
|
preconditions = new AssignAction[0];
|
||||||
sideeffects = new AssignAction[0];
|
sideeffects = new AssignAction[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,6 +139,14 @@ public class ModelRule {
|
||||||
else {
|
else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (preconditions.length != op.preconditions.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < preconditions.length; ++i) {
|
||||||
|
if (!preconditions[i].isEquivalent(op.preconditions[i])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (sideeffects.length != op.sideeffects.length) {
|
if (sideeffects.length != op.sideeffects.length) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -165,8 +181,15 @@ public class ModelRule {
|
||||||
if (qualifier != null && !qualifier.filter(proto, pos)) {
|
if (qualifier != null && !qualifier.filter(proto, pos)) {
|
||||||
return AssignAction.FAIL;
|
return AssignAction.FAIL;
|
||||||
}
|
}
|
||||||
int response = assign.assignAddress(dt, proto, pos, dtManager, status, res);
|
|
||||||
|
int[] tmpStatus = status.clone();
|
||||||
|
for (int i = 0; i < preconditions.length; ++i) {
|
||||||
|
preconditions[i].assignAddress(dt, proto, pos, dtManager, tmpStatus, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
int response = assign.assignAddress(dt, proto, pos, dtManager, tmpStatus, res);
|
||||||
if (response != AssignAction.FAIL) {
|
if (response != AssignAction.FAIL) {
|
||||||
|
System.arraycopy(tmpStatus, 0, status, 0, tmpStatus.length);
|
||||||
for (int i = 0; i < sideeffects.length; ++i) {
|
for (int i = 0; i < sideeffects.length; ++i) {
|
||||||
sideeffects[i].assignAddress(dt, proto, pos, dtManager, status, res);
|
sideeffects[i].assignAddress(dt, proto, pos, dtManager, status, res);
|
||||||
}
|
}
|
||||||
|
@ -185,6 +208,9 @@ public class ModelRule {
|
||||||
if (qualifier != null) {
|
if (qualifier != null) {
|
||||||
qualifier.encode(encoder);
|
qualifier.encode(encoder);
|
||||||
}
|
}
|
||||||
|
for (int i = 0; i < preconditions.length; ++i) {
|
||||||
|
preconditions[i].encode(encoder);
|
||||||
|
}
|
||||||
assign.encode(encoder);
|
assign.encode(encoder);
|
||||||
for (int i = 0; i < sideeffects.length; ++i) {
|
for (int i = 0; i < sideeffects.length; ++i) {
|
||||||
sideeffects[i].encode(encoder);
|
sideeffects[i].encode(encoder);
|
||||||
|
@ -222,6 +248,16 @@ public class ModelRule {
|
||||||
else {
|
else {
|
||||||
qualifier = new AndFilter(qualifierList);
|
qualifier = new AndFilter(qualifierList);
|
||||||
}
|
}
|
||||||
|
ArrayList<AssignAction> preList = new ArrayList<>();
|
||||||
|
for (;;) {
|
||||||
|
AssignAction preAction = AssignAction.restorePreconditionXml(parser, res);
|
||||||
|
if (preAction == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
preList.add(preAction);
|
||||||
|
}
|
||||||
|
preconditions = new AssignAction[preList.size()];
|
||||||
|
preList.toArray(preconditions);
|
||||||
assign = AssignAction.restoreActionXml(parser, res);
|
assign = AssignAction.restoreActionXml(parser, res);
|
||||||
ArrayList<AssignAction> sideList = new ArrayList<>();
|
ArrayList<AssignAction> sideList = new ArrayList<>();
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
|
|
@ -267,6 +267,9 @@ public class MultiSlotAssign extends AssignAction {
|
||||||
if (resource.getEntry(0).isBigEndian() != justifyRight) {
|
if (resource.getEntry(0).isBigEndian() != justifyRight) {
|
||||||
encoder.writeBool(ATTRIB_REVERSEJUSTIFY, true);
|
encoder.writeBool(ATTRIB_REVERSEJUSTIFY, true);
|
||||||
}
|
}
|
||||||
|
if (resource.getEntry(0).isBigEndian() != consumeMostSig) {
|
||||||
|
encoder.writeBool(ATTRIB_REVERSESIGNIF, true);
|
||||||
|
}
|
||||||
if (resourceType != StorageClass.GENERAL) {
|
if (resourceType != StorageClass.GENERAL) {
|
||||||
encoder.writeString(ATTRIB_STORAGE, resourceType.toString());
|
encoder.writeString(ATTRIB_STORAGE, resourceType.toString());
|
||||||
}
|
}
|
||||||
|
@ -286,6 +289,11 @@ public class MultiSlotAssign extends AssignAction {
|
||||||
justifyRight = !justifyRight;
|
justifyRight = !justifyRight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (name.equals(ATTRIB_REVERSESIGNIF.name())) {
|
||||||
|
if (SpecXmlUtils.decodeBoolean(attrib.getValue())) {
|
||||||
|
consumeMostSig = !consumeMostSig;
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (name.equals(ATTRIB_STORAGE.name())) {
|
else if (name.equals(ATTRIB_STORAGE.name())) {
|
||||||
resourceType = StorageClass.getClass(attrib.getValue());
|
resourceType = StorageClass.getClass(attrib.getValue());
|
||||||
}
|
}
|
||||||
|
|
|
@ -262,6 +262,9 @@ public class MultiSlotDualAssign extends AssignAction {
|
||||||
if (resource.getEntry(0).isBigEndian() != justifyRight) {
|
if (resource.getEntry(0).isBigEndian() != justifyRight) {
|
||||||
encoder.writeBool(ATTRIB_REVERSEJUSTIFY, true);
|
encoder.writeBool(ATTRIB_REVERSEJUSTIFY, true);
|
||||||
}
|
}
|
||||||
|
if (resource.getEntry(0).isBigEndian() != consumeMostSig) {
|
||||||
|
encoder.writeBool(ATTRIB_REVERSESIGNIF, true);
|
||||||
|
}
|
||||||
if (baseType != StorageClass.GENERAL) {
|
if (baseType != StorageClass.GENERAL) {
|
||||||
encoder.writeString(ATTRIB_STORAGE, baseType.toString());
|
encoder.writeString(ATTRIB_STORAGE, baseType.toString());
|
||||||
}
|
}
|
||||||
|
@ -281,6 +284,11 @@ public class MultiSlotDualAssign extends AssignAction {
|
||||||
justifyRight = !justifyRight;
|
justifyRight = !justifyRight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (name.equals(ATTRIB_REVERSESIGNIF.name())) {
|
||||||
|
if (SpecXmlUtils.decodeBoolean(attrib.getValue())) {
|
||||||
|
consumeMostSig = !consumeMostSig;
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (name.equals(ATTRIB_STORAGE.name()) || name.equals(ATTRIB_A.name())) {
|
else if (name.equals(ATTRIB_STORAGE.name()) || name.equals(ATTRIB_A.name())) {
|
||||||
baseType = StorageClass.getClass(attrib.getValue());
|
baseType = StorageClass.getClass(attrib.getValue());
|
||||||
}
|
}
|
||||||
|
|
|
@ -249,6 +249,8 @@ public record AttributeId(String name, int id) {
|
||||||
public static final AttributeId ATTRIB_BACKFILL = new AttributeId("backfill", 152);
|
public static final AttributeId ATTRIB_BACKFILL = new AttributeId("backfill", 152);
|
||||||
|
|
||||||
public static final AttributeId ATTRIB_MAX_PRIMITIVES = new AttributeId("maxprimitives", 153);
|
public static final AttributeId ATTRIB_MAX_PRIMITIVES = new AttributeId("maxprimitives", 153);
|
||||||
|
public static final AttributeId ATTRIB_REVERSESIGNIF = new AttributeId("reversesignif", 154);
|
||||||
|
public static final AttributeId ATTRIB_MATCHSIZE = new AttributeId("matchsize", 155);
|
||||||
|
|
||||||
public static final AttributeId ATTRIB_UNKNOWN = new AttributeId("XMLunknown", 154);
|
public static final AttributeId ATTRIB_UNKNOWN = new AttributeId("XMLunknown", 156);
|
||||||
}
|
}
|
||||||
|
|
|
@ -457,6 +457,7 @@ public record ElementId(String name, int id) {
|
||||||
new ElementId("join_per_primitive", 283);
|
new ElementId("join_per_primitive", 283);
|
||||||
public static final ElementId ELEM_JOIN_DUAL_CLASS = new ElementId("join_dual_class", 285);
|
public static final ElementId ELEM_JOIN_DUAL_CLASS = new ElementId("join_dual_class", 285);
|
||||||
public static final ElementId ELEM_EXTRA_STACK = new ElementId("extra_stack", 287);
|
public static final ElementId ELEM_EXTRA_STACK = new ElementId("extra_stack", 287);
|
||||||
|
public static final ElementId ELEM_CONSUME_REMAINING = new ElementId("consume_remaining", 288);
|
||||||
|
|
||||||
public static final ElementId ELEM_UNKNOWN = new ElementId("XMLunknown", 288);
|
public static final ElementId ELEM_UNKNOWN = new ElementId("XMLunknown", 289);
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,49 +40,140 @@
|
||||||
<default_proto>
|
<default_proto>
|
||||||
<prototype name="__stdcall" extrapop="2" stackshift="2">
|
<prototype name="__stdcall" extrapop="2" stackshift="2">
|
||||||
<input>
|
<input>
|
||||||
<pentry minsize="1" maxsize="2">
|
<pentry minsize="1" maxsize="1">
|
||||||
<register name="R25R24"/>
|
<register name="R25"/>
|
||||||
</pentry>
|
</pentry>
|
||||||
<pentry minsize="1" maxsize="2">
|
<pentry minsize="1" maxsize="1">
|
||||||
<register name="R23R22"/>
|
<register name="R24"/>
|
||||||
</pentry>
|
</pentry>
|
||||||
<pentry minsize="1" maxsize="2">
|
<pentry minsize="1" maxsize="1">
|
||||||
<register name="R21R20"/>
|
<register name="R23"/>
|
||||||
</pentry>
|
</pentry>
|
||||||
<pentry minsize="1" maxsize="2">
|
<pentry minsize="1" maxsize="1">
|
||||||
<register name="R19R18"/>
|
<register name="R22"/>
|
||||||
</pentry>
|
</pentry>
|
||||||
<pentry minsize="1" maxsize="2">
|
<pentry minsize="1" maxsize="1">
|
||||||
<register name="R17R16"/>
|
<register name="R21"/>
|
||||||
</pentry>
|
</pentry>
|
||||||
<pentry minsize="1" maxsize="2">
|
<pentry minsize="1" maxsize="1">
|
||||||
<register name="R15R14"/>
|
<register name="R20"/>
|
||||||
</pentry>
|
</pentry>
|
||||||
<pentry minsize="1" maxsize="2">
|
<pentry minsize="1" maxsize="1">
|
||||||
<register name="R13R12"/>
|
<register name="R19"/>
|
||||||
</pentry>
|
</pentry>
|
||||||
<pentry minsize="1" maxsize="2">
|
<pentry minsize="1" maxsize="1">
|
||||||
<register name="R11R10"/>
|
<register name="R18"/>
|
||||||
</pentry>
|
</pentry>
|
||||||
<pentry minsize="1" maxsize="2">
|
<pentry minsize="1" maxsize="1">
|
||||||
<register name="R9R8"/>
|
<register name="R17"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="1">
|
||||||
|
<register name="R16"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="1">
|
||||||
|
<register name="R15"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="1">
|
||||||
|
<register name="R14"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="1">
|
||||||
|
<register name="R13"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="1">
|
||||||
|
<register name="R12"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="1">
|
||||||
|
<register name="R11"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="1">
|
||||||
|
<register name="R10"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="1">
|
||||||
|
<register name="R9"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="1">
|
||||||
|
<register name="R8"/>
|
||||||
</pentry>
|
</pentry>
|
||||||
<!-- Currently messes up parameter allocation, for known data types bigger than 2 -->
|
|
||||||
<!-- strategy="packreg" planned to mitigate this problem -->
|
|
||||||
<pentry minsize="1" maxsize="500" align="1">
|
<pentry minsize="1" maxsize="500" align="1">
|
||||||
<addr offset="3" space="stack"/>
|
<addr offset="3" space="stack"/>
|
||||||
</pentry>
|
</pentry>
|
||||||
|
|
||||||
|
<!-- In a varargs function, everything is unconditionally on the stack -->
|
||||||
|
<rule>
|
||||||
|
<datatype name="any"/>
|
||||||
|
<varargs/>
|
||||||
|
<goto_stack/>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<!-- Arguments are passed entirely in registers if possible, else entirely on stack -->
|
||||||
|
<!-- Odd-sized types are rounded to the next even register number for assignment -->
|
||||||
|
<rule>
|
||||||
|
<datatype name="any" sizes="1,3,5,7,9,11,13,15,17"/>
|
||||||
|
<consume_extra storage="general" matchsize="false"/>
|
||||||
|
<join stackspill="false" reversesignif="true"/>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<rule>
|
||||||
|
<datatype name="any"/>
|
||||||
|
<join stackspill="false" reversesignif="true"/>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<!-- Once any argument is passed on the stack, do not return to register allocation -->
|
||||||
|
<rule>
|
||||||
|
<datatype name="any"/>
|
||||||
|
<goto_stack/>
|
||||||
|
<consume_remaining storage="general"/>
|
||||||
|
</rule>
|
||||||
</input>
|
</input>
|
||||||
<output>
|
<output>
|
||||||
<pentry minsize="1" maxsize="2">
|
<pentry minsize="1" maxsize="1">
|
||||||
<register name="R25R24"/>
|
<register name="R25"/>
|
||||||
</pentry>
|
</pentry>
|
||||||
<pentry minsize="3" maxsize="4">
|
<pentry minsize="1" maxsize="1">
|
||||||
<addr space="join" piece1="R25R24" piece2="R23R22"/>
|
<register name="R24"/>
|
||||||
</pentry>
|
</pentry>
|
||||||
<pentry minsize="5" maxsize="8">
|
<pentry minsize="1" maxsize="1">
|
||||||
<addr space="join" piece1="R25R24" piece2="R23R22" piece3="R21R20" piece4="R19R18"/>
|
<register name="R23"/>
|
||||||
</pentry>
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="1">
|
||||||
|
<register name="R22"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="1">
|
||||||
|
<register name="R21"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="1">
|
||||||
|
<register name="R20"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="1">
|
||||||
|
<register name="R19"/>
|
||||||
|
</pentry>
|
||||||
|
<pentry minsize="1" maxsize="1">
|
||||||
|
<register name="R18"/>
|
||||||
|
</pentry>
|
||||||
|
|
||||||
|
<!-- return value sizes are padded up to the nearest power of two -->
|
||||||
|
<rule>
|
||||||
|
<datatype name="any" sizes="1,3,7"/>
|
||||||
|
<consume_extra storage="general" matchsize="false"/>
|
||||||
|
<join reversesignif="true"/>
|
||||||
|
</rule>
|
||||||
|
<rule>
|
||||||
|
<datatype name="any" minsize="5" maxsize="5"/>
|
||||||
|
<consume_extra storage="general" matchsize="false"/>
|
||||||
|
<consume_extra storage="general" matchsize="false"/>
|
||||||
|
<consume_extra storage="general" matchsize="false"/>
|
||||||
|
<join reversesignif="true"/>
|
||||||
|
</rule>
|
||||||
|
<rule>
|
||||||
|
<datatype name="any" minsize="6" maxsize="6"/>
|
||||||
|
<consume_extra storage="general" matchsize="false"/>
|
||||||
|
<consume_extra storage="general" matchsize="false"/>
|
||||||
|
<join reversesignif="true"/>
|
||||||
|
</rule>
|
||||||
|
<rule>
|
||||||
|
<datatype name="any"/>
|
||||||
|
<join reversesignif="true"/>
|
||||||
|
</rule>
|
||||||
</output>
|
</output>
|
||||||
<unaffected>
|
<unaffected>
|
||||||
<register name="SP"/>
|
<register name="SP"/>
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -16,17 +16,18 @@
|
||||||
package ghidra.app.util.bin.format.elf.extend;
|
package ghidra.app.util.bin.format.elf.extend;
|
||||||
|
|
||||||
import ghidra.app.util.bin.format.elf.*;
|
import ghidra.app.util.bin.format.elf.*;
|
||||||
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.address.AddressSpace;
|
import ghidra.program.model.address.AddressSpace;
|
||||||
import ghidra.program.model.lang.Language;
|
import ghidra.program.model.lang.Language;
|
||||||
|
|
||||||
public class AVR8_ElfExtension extends ElfExtension {
|
public class AVR8_ElfExtension extends ElfExtension {
|
||||||
|
|
||||||
// Processor specific flag mask
|
// Processor specific flag mask
|
||||||
public static final int EF_AVR_MACH = 0x7F;
|
public static final int EF_AVR_MACH = 0x7F;
|
||||||
|
|
||||||
// bit #7 indicates elf file uses local symbols for relocations
|
// bit #7 indicates elf file uses local symbols for relocations
|
||||||
public static final int EF_AVR_LINKRELAX_PREPARED = 0x80;
|
public static final int EF_AVR_LINKRELAX_PREPARED = 0x80;
|
||||||
|
|
||||||
public static final int E_AVR_MACH_AVR1 = 1;
|
public static final int E_AVR_MACH_AVR1 = 1;
|
||||||
public static final int E_AVR_MACH_AVR2 = 2;
|
public static final int E_AVR_MACH_AVR2 = 2;
|
||||||
public static final int E_AVR_MACH_AVR25 = 25;
|
public static final int E_AVR_MACH_AVR25 = 25;
|
||||||
|
@ -74,4 +75,22 @@ public class AVR8_ElfExtension extends ElfExtension {
|
||||||
return elfOffset;
|
return elfOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Address evaluateElfSymbol(ElfLoadHelper elfLoadHelper, ElfSymbol elfSymbol,
|
||||||
|
Address address, boolean isExternal) {
|
||||||
|
if (!address.getAddressSpace().getName().equals("code")) {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isExternal) {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
// st_value should be the byte offset into the code space, not word offset
|
||||||
|
// address - (st_value * 2) is the base address of symbols in the code space
|
||||||
|
return address.getAddressSpace()
|
||||||
|
.getAddress(address.subtract(elfSymbol.getValue() << 1).getOffset() +
|
||||||
|
elfSymbol.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue