diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.cc index cafce3f7ba..434f747e63 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/fspec.cc @@ -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 Datatype *dt = res.back().type; - type_class store; - if ((res.back().flags & ParameterPieces::hiddenretparm) != 0) - store = TYPECLASS_HIDDENRET; - else - store = metatype2typeclass(dt->getMetatype()); - // Reserve first param for hidden return pointer - if (assignAddressFallback(store,dt,false,status,res.back()) == AssignAction::fail) - throw ParamUnassignedError("Cannot assign parameter address for " + res.back().type->getName()); + if ((res.back().flags & ParameterPieces::hiddenretparm) != 0) { + // Need to pull from registers marked as hiddenret + if (assignAddressFallback(TYPECLASS_HIDDENRET,dt,false,status,res.back()) == AssignAction::fail) { + throw ParamUnassignedError("Cannot assign parameter address for " + res.back().type->getName()); + } + } + else { + // 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; } for(int4 i=0;idecode(decoder); + return action; +} + /// \brief Read the next model rule sideeffect element from the stream /// /// 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) { action = new ExtraStack(res,0); } + else if (elemId == ELEM_CONSUME_REMAINING) { + action = new ConsumeRemaining(res); + } else throw DecoderError("Expecting model rule sideeffect"); action->decode(decoder); @@ -911,8 +940,12 @@ void MultiSlotAssign::decode(Decoder &decoder) if (attribId == 0) break; if (attribId == ATTRIB_REVERSEJUSTIFY) { if (decoder.readBool()) - justifyRight = !justifyRight; + justifyRight = !justifyRight; } + else if (attribId == ATTRIB_REVERSESIGNIF) { + if (decoder.readBool()) + consumeMostSig = !consumeMostSig; + } else if (attribId == ATTRIB_STORAGE) { resourceType = string2typeclass(decoder.readString()); } @@ -1216,8 +1249,12 @@ void MultiSlotDualAssign::decode(Decoder &decoder) if (attribId == 0) break; if (attribId == ATTRIB_REVERSEJUSTIFY) { 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) { baseType = string2typeclass(decoder.readString()); } @@ -1353,6 +1390,61 @@ void ConsumeExtra::decode(Decoder &decoder) { 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 &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)); decoder.closeElement(elemId); initializeEntries(); @@ -1416,6 +1508,8 @@ ModelRule::ModelRule(const ModelRule &op2,const ParamListStandard *res) assign = op2.assign->clone(res); else assign = (AssignAction *)0; + for (int4 i=0;iclone(res)); for(int4 i=0;iclone(res)); } @@ -1441,6 +1535,8 @@ ModelRule::~ModelRule(void) delete qualifier; if (assign != (AssignAction *)0) delete assign; + for(int4 i=0;ifilter(proto,pos)) { return AssignAction::fail; } - uint4 response = assign->assignAddress(dt,proto,pos,tlist,status,res); + vector tmpStatus = status; + for(int4 i =0;iassignAddress(dt,proto,pos,tlist,tmpStatus,res); + } + uint4 response = assign->assignAddress(dt,proto,pos,tlist,tmpStatus,res); if (response != AssignAction::fail) { + status = tmpStatus; for(int4 i=0;iassignAddress(dt,proto,pos,tlist,status,res); } @@ -1499,6 +1600,12 @@ void ModelRule::decode(Decoder &decoder,const ParamListStandard *res) else { 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); while(decoder.peekElement() != 0) { sideeffects.push_back(AssignAction::decodeSideeffect(decoder,res)); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/modelrules.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/modelrules.hh index e581ecc41d..c720ec8220 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/modelrules.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/modelrules.hh @@ -30,6 +30,8 @@ class ParamActive; extern AttributeId ATTRIB_SIZES; ///< Marshaling attribute "sizes" 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 \ extern ElementId ELEM_CONSUME; ///< Marshaling element \ @@ -44,6 +46,7 @@ extern ElementId ELEM_HIDDEN_RETURN; ///< Marshaling element \ extern ElementId ELEM_JOIN_PER_PRIMITIVE; ///< Marshaling element \ extern ElementId ELEM_JOIN_DUAL_CLASS; ///< Marshaling element \ extern ElementId ELEM_EXTRA_STACK; ///< Marshaling element \ +extern ElementId ELEM_CONSUME_REMAINING; ///< Marshaling element \ /// \brief Class for extracting primitive elements of a data-type /// @@ -311,6 +314,7 @@ public: /// \param decoder is the given stream decoder virtual void decode(Decoder &decoder)=0; static AssignAction *decodeAction(Decoder &decoder,const ParamListStandard *res); + static AssignAction *decodePrecondition(Decoder &decoder, const ParamListStandard *res); static AssignAction *decodeSideeffect(Decoder &decoder,const ParamListStandard *res); }; @@ -492,6 +496,26 @@ public: 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 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 &status,ParameterPieces &res) const; + virtual void decode(Decoder &decoder); +}; + /// \brief A rule controlling how parameters are assigned addresses /// /// 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 QualifierFilter *qualifier; ///< Additional qualifiers for when the rule should apply (if non-null) AssignAction *assign; ///< How the Address should be assigned + vector preconditions; ///< Extra actions that happen before assignment, discarded on failure vector sideeffects; ///< Extra actions that happen on success public: ModelRule(void) { diff --git a/Ghidra/Framework/SoftwareModeling/data/languages/compiler_spec.rxg b/Ghidra/Framework/SoftwareModeling/data/languages/compiler_spec.rxg index 8ba5b316b6..02bc2f14c8 100644 --- a/Ghidra/Framework/SoftwareModeling/data/languages/compiler_spec.rxg +++ b/Ghidra/Framework/SoftwareModeling/data/languages/compiler_spec.rxg @@ -379,6 +379,16 @@ + + + + + + + + + + @@ -395,6 +405,11 @@ + + + + + @@ -430,6 +445,11 @@ + + + + + @@ -444,6 +464,16 @@ + + + + + + + + + + diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamListStandard.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamListStandard.java index 9623df4f2d..e90a3c842b 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamListStandard.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamListStandard.java @@ -177,14 +177,14 @@ public class ParamListStandard implements ParamList { if (addAutoParams && res.size() == 2) { // Check for hidden parameters defined by the output list ParameterPieces last = res.get(res.size() - 1); - StorageClass store; if (last.hiddenReturnPtr) { - store = StorageClass.HIDDENRET; + // Need to pull from registers marked as hiddenret + assignAddressFallback(StorageClass.HIDDENRET, last.type, false, status, last); } 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; } for (int i = 0; i < proto.intypes.size(); ++i) { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamListStandardOut.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamListStandardOut.java index 35f36cfb6c..7d357a0b3f 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamListStandardOut.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/ParamListStandardOut.java @@ -4,9 +4,9 @@ * 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. @@ -64,9 +64,10 @@ public class ParamListStandardOut extends ParamListStandard { store.type = VoidDataType.dataType; } else { - assignAddressFallback(StorageClass.PTR, pointerType, false, status, store); store.type = pointerType; + assignAddress(pointerType, proto, -1, dtManager, status, store); } + store.isIndirect = true; // Signal that there is a hidden return if (addAutoParams) { ParameterPieces hiddenRet = new ParameterPieces(); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/protorules/AssignAction.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/protorules/AssignAction.java index b06784a095..2f73bc8143 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/protorules/AssignAction.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/protorules/AssignAction.java @@ -157,10 +157,38 @@ public abstract class AssignAction { else if (nm.equals(ELEM_EXTRA_STACK.name())) { action = new ExtraStack(res, 0); } + else if (nm.equals(ELEM_CONSUME_REMAINING.name())) { + action = new ConsumeRemaining(res); + } else { throw new XmlParseException("Unknown model rule sideeffect: " + nm); } action.restoreXml(parser); 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; + } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/protorules/ConsumeExtra.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/protorules/ConsumeExtra.java index 50099f17f9..b5413663ea 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/protorules/ConsumeExtra.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/protorules/ConsumeExtra.java @@ -19,12 +19,14 @@ import static ghidra.program.model.pcode.AttributeId.*; import static ghidra.program.model.pcode.ElementId.*; import java.io.IOException; +import java.util.Map.Entry; 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.util.xml.SpecXmlUtils; import ghidra.xml.*; /** @@ -119,13 +121,22 @@ public class ConsumeExtra extends AssignAction { public void encode(Encoder encoder) throws IOException { encoder.openElement(ELEM_CONSUME_EXTRA); encoder.writeString(ATTRIB_STORAGE, resourceType.toString()); + encoder.writeBool(ATTRIB_MATCHSIZE, matchSize); encoder.closeElement(ELEM_CONSUME_EXTRA); } @Override public void restoreXml(XmlPullParser parser) throws XmlParseException { XmlElement elem = parser.start(ELEM_CONSUME_EXTRA.name()); - resourceType = StorageClass.getClass(elem.getAttribute(ATTRIB_STORAGE.name())); + for (Entry 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); try { initializeEntries(); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/protorules/ConsumeRemaining.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/protorules/ConsumeRemaining.java new file mode 100644 index 0000000000..6875eb94a3 --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/protorules/ConsumeRemaining.java @@ -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()); + } + } + +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/protorules/ModelRule.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/protorules/ModelRule.java index 4f7deaa57c..ee223fba33 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/protorules/ModelRule.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/protorules/ModelRule.java @@ -4,9 +4,9 @@ * 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. @@ -39,6 +39,7 @@ public class ModelRule { 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 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 public ModelRule() { @@ -72,6 +73,12 @@ public class ModelRule { else { 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]; for (int i = 0; i < op2.sideeffects.length; ++i) { sideeffects[i] = op2.sideeffects[i].clone(res); @@ -94,6 +101,7 @@ public class ModelRule { filter = typeFilter.clone(); qualifier = null; assign = action.clone(res); + preconditions = new AssignAction[0]; sideeffects = new AssignAction[0]; } @@ -131,6 +139,14 @@ public class ModelRule { else { 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) { return false; } @@ -165,8 +181,15 @@ public class ModelRule { if (qualifier != null && !qualifier.filter(proto, pos)) { 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) { + System.arraycopy(tmpStatus, 0, status, 0, tmpStatus.length); for (int i = 0; i < sideeffects.length; ++i) { sideeffects[i].assignAddress(dt, proto, pos, dtManager, status, res); } @@ -185,6 +208,9 @@ public class ModelRule { if (qualifier != null) { qualifier.encode(encoder); } + for (int i = 0; i < preconditions.length; ++i) { + preconditions[i].encode(encoder); + } assign.encode(encoder); for (int i = 0; i < sideeffects.length; ++i) { sideeffects[i].encode(encoder); @@ -222,6 +248,16 @@ public class ModelRule { else { qualifier = new AndFilter(qualifierList); } + ArrayList 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); ArrayList sideList = new ArrayList<>(); for (;;) { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/protorules/MultiSlotAssign.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/protorules/MultiSlotAssign.java index 24c46812fa..c84b69e238 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/protorules/MultiSlotAssign.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/protorules/MultiSlotAssign.java @@ -267,6 +267,9 @@ public class MultiSlotAssign extends AssignAction { if (resource.getEntry(0).isBigEndian() != justifyRight) { encoder.writeBool(ATTRIB_REVERSEJUSTIFY, true); } + if (resource.getEntry(0).isBigEndian() != consumeMostSig) { + encoder.writeBool(ATTRIB_REVERSESIGNIF, true); + } if (resourceType != StorageClass.GENERAL) { encoder.writeString(ATTRIB_STORAGE, resourceType.toString()); } @@ -286,6 +289,11 @@ public class MultiSlotAssign extends AssignAction { justifyRight = !justifyRight; } } + else if (name.equals(ATTRIB_REVERSESIGNIF.name())) { + if (SpecXmlUtils.decodeBoolean(attrib.getValue())) { + consumeMostSig = !consumeMostSig; + } + } else if (name.equals(ATTRIB_STORAGE.name())) { resourceType = StorageClass.getClass(attrib.getValue()); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/protorules/MultiSlotDualAssign.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/protorules/MultiSlotDualAssign.java index ccb039e91f..6223a0eb8c 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/protorules/MultiSlotDualAssign.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/protorules/MultiSlotDualAssign.java @@ -262,6 +262,9 @@ public class MultiSlotDualAssign extends AssignAction { if (resource.getEntry(0).isBigEndian() != justifyRight) { encoder.writeBool(ATTRIB_REVERSEJUSTIFY, true); } + if (resource.getEntry(0).isBigEndian() != consumeMostSig) { + encoder.writeBool(ATTRIB_REVERSESIGNIF, true); + } if (baseType != StorageClass.GENERAL) { encoder.writeString(ATTRIB_STORAGE, baseType.toString()); } @@ -281,6 +284,11 @@ public class MultiSlotDualAssign extends AssignAction { 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())) { baseType = StorageClass.getClass(attrib.getValue()); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/AttributeId.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/AttributeId.java index a2eda1b9aa..16cc22e629 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/AttributeId.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/AttributeId.java @@ -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_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); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/ElementId.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/ElementId.java index 6f20a633a0..29aa805dbb 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/ElementId.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/ElementId.java @@ -457,6 +457,7 @@ public record ElementId(String name, int id) { 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_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); } diff --git a/Ghidra/Processors/Atmel/data/languages/avr8gcc.cspec b/Ghidra/Processors/Atmel/data/languages/avr8gcc.cspec index 5e35b79849..bc27355a7a 100644 --- a/Ghidra/Processors/Atmel/data/languages/avr8gcc.cspec +++ b/Ghidra/Processors/Atmel/data/languages/avr8gcc.cspec @@ -40,49 +40,140 @@ - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Ghidra/Processors/Atmel/src/main/java/ghidra/app/util/bin/format/elf/extend/AVR8_ElfExtension.java b/Ghidra/Processors/Atmel/src/main/java/ghidra/app/util/bin/format/elf/extend/AVR8_ElfExtension.java index 524a9ac645..35bf6b6f6c 100644 --- a/Ghidra/Processors/Atmel/src/main/java/ghidra/app/util/bin/format/elf/extend/AVR8_ElfExtension.java +++ b/Ghidra/Processors/Atmel/src/main/java/ghidra/app/util/bin/format/elf/extend/AVR8_ElfExtension.java @@ -4,9 +4,9 @@ * 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. @@ -16,17 +16,18 @@ package ghidra.app.util.bin.format.elf.extend; import ghidra.app.util.bin.format.elf.*; +import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressSpace; import ghidra.program.model.lang.Language; public class AVR8_ElfExtension extends ElfExtension { - + // 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 - 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_AVR2 = 2; public static final int E_AVR_MACH_AVR25 = 25; @@ -74,4 +75,22 @@ public class AVR8_ElfExtension extends ElfExtension { 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()); + } + }