mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 10:49:34 +02:00
GP-4356: fixes to avr8 cspec and elf extension, and additions to decompiler model rules
This commit is contained in:
parent
5acdc3b522
commit
991a4b440c
17 changed files with 564 additions and 63 deletions
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<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);
|
||||
try {
|
||||
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");
|
||||
* 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<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);
|
||||
ArrayList<AssignAction> sideList = new ArrayList<>();
|
||||
for (;;) {
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue