mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
GP-5256 ExtraStack, sizes attribute, merge join sequence
This commit is contained in:
parent
acbda8b076
commit
00f9789116
40 changed files with 1015 additions and 411 deletions
|
@ -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.
|
||||
|
@ -81,6 +81,11 @@ public interface ParamList {
|
|||
*/
|
||||
public boolean possibleParamWithSlot(Address loc, int size, WithSlotRec res);
|
||||
|
||||
/**
|
||||
* @return the associated Language
|
||||
*/
|
||||
public Language getLanguage();
|
||||
|
||||
/**
|
||||
* Get the address space associated with any stack based parameters in this list.
|
||||
*
|
||||
|
|
|
@ -39,7 +39,8 @@ import ghidra.xml.*;
|
|||
*/
|
||||
public class ParamListStandard implements ParamList {
|
||||
|
||||
protected int numgroup; // Number of "groups" in this parameter convention
|
||||
protected Language language; // The language associate with this convention
|
||||
protected int numgroup; // Number of "groups" in this parameter convention
|
||||
// protected int maxdelay;
|
||||
protected boolean thisbeforeret; // Do hidden return pointers usurp the storage of the this pointer
|
||||
protected boolean autoKilledByCall; // Is storage in this list automatically "killed by call"
|
||||
|
@ -326,6 +327,7 @@ public class ParamListStandard implements ParamList {
|
|||
public void restoreXml(XmlPullParser parser, CompilerSpec cspec) throws XmlParseException {
|
||||
ArrayList<ParamEntry> pe = new ArrayList<>();
|
||||
numgroup = 0;
|
||||
language = cspec.getLanguage();
|
||||
spacebase = null;
|
||||
int pointermax = 0;
|
||||
thisbeforeret = false;
|
||||
|
@ -453,6 +455,11 @@ public class ParamListStandard implements ParamList {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Language getLanguage() {
|
||||
return language;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddressSpace getSpacebase() {
|
||||
return spacebase;
|
||||
|
@ -499,4 +506,38 @@ public class ParamListStandard implements ParamList {
|
|||
public boolean isThisBeforeRetPointer() {
|
||||
return thisbeforeret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract all ParamEntry that have the given storage class and are single registers.
|
||||
* @param resType is the given storage class
|
||||
* @return the array of registers
|
||||
*/
|
||||
public ParamEntry[] extractTiles(StorageClass resType) {
|
||||
ArrayList<ParamEntry> buffer = new ArrayList<>();
|
||||
for (int i = 0; i < entry.length; ++i) {
|
||||
ParamEntry pentry = entry[i];
|
||||
if (!pentry.isExclusion() || pentry.getAllGroups().length != 1 ||
|
||||
pentry.getType() != resType) {
|
||||
continue;
|
||||
}
|
||||
buffer.add(pentry);
|
||||
}
|
||||
ParamEntry[] res = new ParamEntry[buffer.size()];
|
||||
buffer.toArray(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* If there is a ParamEntry corresponding to the stack resource in this list, return it.
|
||||
* @return the stack ParamEntry or null
|
||||
*/
|
||||
public ParamEntry extractStack() {
|
||||
for (int i = entry.length - 1; i >= 0; --i) {
|
||||
ParamEntry pentry = entry[i];
|
||||
if (!pentry.isExclusion() && pentry.getSpace().isStackSpace()) {
|
||||
return pentry;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
@ -15,6 +15,8 @@
|
|||
*/
|
||||
package ghidra.program.model.lang;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.VoidDataType;
|
||||
|
@ -109,4 +111,81 @@ public class ParameterPieces {
|
|||
}
|
||||
return store;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assuming the given list of Varnodes go from most significant to least significant,
|
||||
* merge any contiguous elements in the list. Merges in a register space are only allowed
|
||||
* if the bigger Varnode exists as a formal register.
|
||||
* @param seq is the given list of Varnodes
|
||||
* @param language is the Language associated with the calling convention.
|
||||
* @return the merged list (which may be the original list)
|
||||
*/
|
||||
public static ArrayList<Varnode> mergeSequence(ArrayList<Varnode> seq, Language language) {
|
||||
int i = 1;
|
||||
boolean bigEndian = language.isBigEndian();
|
||||
while (i < seq.size()) {
|
||||
Varnode hi = seq.get(i - 1);
|
||||
Varnode lo = seq.get(i);
|
||||
if (hi.isContiguous(lo, bigEndian))
|
||||
break;
|
||||
i += 1;
|
||||
}
|
||||
if (i >= seq.size())
|
||||
return seq;
|
||||
ArrayList<Varnode> buffer = new ArrayList<>();
|
||||
i = 1;
|
||||
buffer.add(seq.getFirst());
|
||||
boolean lastIsInformal = false;
|
||||
while (i < seq.size()) {
|
||||
Varnode hi = buffer.getLast();
|
||||
Varnode lo = seq.get(i);
|
||||
if (hi.isContiguous(lo, bigEndian)) {
|
||||
long off = bigEndian ? hi.getOffset() : lo.getOffset();
|
||||
int sz = hi.getSize() + lo.getSize();
|
||||
Varnode newVn = new Varnode(hi.getAddress().getAddressSpace().getAddress(off), sz);
|
||||
buffer.removeLast();
|
||||
buffer.add(newVn);
|
||||
// Test if new Varnode is a formal register
|
||||
if (!newVn.getAddress().isStackAddress()) {
|
||||
lastIsInformal =
|
||||
language.getRegister(newVn.getAddress(), newVn.getSize()) == null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (lastIsInformal)
|
||||
break;
|
||||
buffer.add(lo);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
if (lastIsInformal) // If the merge contains an informal register
|
||||
return seq; // throw it out and keep original sequence
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a parameter address given the list of Varnodes making up the parameter.
|
||||
* @param pieces is the given list of Varnodes
|
||||
* @param mostToLeast is true if the list is ordered most significant to least
|
||||
* @param onePieceJoin is true if the address should be considered a join of one piece
|
||||
* @param language is the Language associated with the calling convention
|
||||
*/
|
||||
public void assignAddressFromPieces(ArrayList<Varnode> pieces, boolean mostToLeast,
|
||||
boolean onePieceJoin, Language language) {
|
||||
if (!mostToLeast && pieces.size() > 1) {
|
||||
ArrayList<Varnode> reverse = new ArrayList<Varnode>();
|
||||
for (int i = pieces.size() - 1; i >= 0; --i) {
|
||||
reverse.add(pieces.get(i));
|
||||
}
|
||||
pieces = reverse;
|
||||
}
|
||||
pieces = mergeSequence(pieces, language);
|
||||
if (pieces.size() == 1 && !onePieceJoin) {
|
||||
address = pieces.get(0).getAddress();
|
||||
return;
|
||||
}
|
||||
joinPieces = new Varnode[pieces.size()];
|
||||
pieces.toArray(joinPieces);
|
||||
address = Address.NO_ADDRESS; // Placeholder for join space address
|
||||
}
|
||||
}
|
||||
|
|
|
@ -627,44 +627,44 @@ public class PrototypeModel {
|
|||
inputParams = null;
|
||||
outputParams = null;
|
||||
XmlElement protoElement = parser.start();
|
||||
name = protoElement.getAttribute("name");
|
||||
name = protoElement.getAttribute(ATTRIB_NAME.name());
|
||||
if (!SpecExtension.isValidFormalName(name)) {
|
||||
throw new XmlParseException("Prototype name uses illegal characters");
|
||||
}
|
||||
extrapop = PrototypeModel.UNKNOWN_EXTRAPOP;
|
||||
String extpopStr = protoElement.getAttribute("extrapop");
|
||||
String extpopStr = protoElement.getAttribute(ATTRIB_EXTRAPOP.name());
|
||||
if (!extpopStr.equals("unknown")) {
|
||||
extrapop = SpecXmlUtils.decodeInt(extpopStr);
|
||||
}
|
||||
stackshift = SpecXmlUtils.decodeInt(protoElement.getAttribute("stackshift"));
|
||||
stackshift = SpecXmlUtils.decodeInt(protoElement.getAttribute(ATTRIB_STACKSHIFT.name()));
|
||||
hasThis = false;
|
||||
isConstruct = false;
|
||||
String thisString = protoElement.getAttribute("hasthis");
|
||||
String thisString = protoElement.getAttribute(ATTRIB_HASTHIS.name());
|
||||
if (thisString != null) {
|
||||
hasThis = SpecXmlUtils.decodeBoolean(thisString);
|
||||
}
|
||||
else {
|
||||
hasThis = name.equals(CompilerSpec.CALLING_CONVENTION_thiscall);
|
||||
}
|
||||
String constructString = protoElement.getAttribute("constructor");
|
||||
String constructString = protoElement.getAttribute(ATTRIB_CONSTRUCTOR.name());
|
||||
if (constructString != null) {
|
||||
isConstruct = SpecXmlUtils.decodeBoolean(constructString);
|
||||
}
|
||||
|
||||
buildParamList(protoElement.getAttribute("strategy"));
|
||||
buildParamList(protoElement.getAttribute(ATTRIB_STRATEGY.name()));
|
||||
while (parser.peek().isStart()) {
|
||||
XmlElement subel = parser.peek();
|
||||
String elName = subel.getName();
|
||||
if (elName.equals("input")) {
|
||||
if (elName.equals(ELEM_INPUT.name())) {
|
||||
inputParams.restoreXml(parser, cspec);
|
||||
}
|
||||
else if (elName.equals("output")) {
|
||||
else if (elName.equals(ELEM_OUTPUT.name())) {
|
||||
outputParams.restoreXml(parser, cspec);
|
||||
}
|
||||
else if (elName.equals("pcode")) {
|
||||
else if (elName.equals(ELEM_PCODE.name())) {
|
||||
XmlElement el = parser.peek();
|
||||
String source = "Compiler spec=" + cspec.getCompilerSpecID().getIdAsString();
|
||||
if (el.getAttribute("inject").equals("uponentry")) {
|
||||
if (el.getAttribute(ATTRIB_INJECT.name()).equals("uponentry")) {
|
||||
hasUponEntry = true;
|
||||
}
|
||||
else {
|
||||
|
@ -674,25 +674,25 @@ public class PrototypeModel {
|
|||
.restoreXmlInject(source, getInjectName(), InjectPayload.CALLMECHANISM_TYPE,
|
||||
parser);
|
||||
}
|
||||
else if (elName.equals("unaffected")) {
|
||||
else if (elName.equals(ELEM_UNAFFECTED.name())) {
|
||||
unaffected = readVarnodes(parser, cspec);
|
||||
}
|
||||
else if (elName.equals("killedbycall")) {
|
||||
else if (elName.equals(ELEM_KILLEDBYCALL.name())) {
|
||||
killedbycall = readVarnodes(parser, cspec);
|
||||
}
|
||||
else if (elName.equals("returnaddress")) {
|
||||
else if (elName.equals(ELEM_RETURNADDRESS.name())) {
|
||||
returnaddress = readVarnodes(parser, cspec);
|
||||
}
|
||||
else if (elName.equals("likelytrash")) {
|
||||
else if (elName.equals(ELEM_LIKELYTRASH.name())) {
|
||||
likelytrash = readVarnodes(parser, cspec);
|
||||
}
|
||||
else if (elName.equals("internal_storage")) {
|
||||
else if (elName.equals(ELEM_INTERNAL_STORAGE.name())) {
|
||||
internalstorage = readVarnodes(parser, cspec);
|
||||
}
|
||||
else if (elName.equals("localrange")) {
|
||||
else if (elName.equals(ELEM_LOCALRANGE.name())) {
|
||||
localRange = readAddressSet(parser, cspec);
|
||||
}
|
||||
else if (elName.equals("paramrange")) {
|
||||
else if (elName.equals(ELEM_PARAMRANGE.name())) {
|
||||
paramRange = readAddressSet(parser, cspec);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -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.
|
||||
|
@ -154,11 +154,13 @@ public abstract class AssignAction {
|
|||
if (nm.equals(ELEM_CONSUME_EXTRA.name())) {
|
||||
action = new ConsumeExtra(res);
|
||||
}
|
||||
else if (nm.equals(ELEM_EXTRA_STACK.name())) {
|
||||
action = new ExtraStack(res, 0);
|
||||
}
|
||||
else {
|
||||
throw new XmlParseException("Unknown model rule sideeffect: " + nm);
|
||||
}
|
||||
action.restoreXml(parser);
|
||||
return action;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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,8 +39,8 @@ import ghidra.xml.*;
|
|||
public class ConsumeExtra extends AssignAction {
|
||||
|
||||
private StorageClass resourceType; // The other resource list to consume from
|
||||
private int firstIter; // Iterator to first element in the resource list
|
||||
private boolean matchSize; // false, if side-effect only consumes a single register
|
||||
private ParamEntry[] tiles; // Registers that can be consumed
|
||||
|
||||
/**
|
||||
* Cache specific ParamEntry needed by the action.
|
||||
|
@ -48,18 +48,10 @@ public class ConsumeExtra extends AssignAction {
|
|||
* @throws InvalidInputException if it cannot find the configured ParamEntry objects
|
||||
*/
|
||||
private void initializeEntries() throws InvalidInputException {
|
||||
firstIter = -1;
|
||||
for (int i = 0; i < resource.getNumParamEntry(); ++i) {
|
||||
ParamEntry entry = resource.getEntry(i);
|
||||
if (entry.isExclusion() && entry.getType() == resourceType &&
|
||||
entry.getAllGroups().length == 1) {
|
||||
firstIter = i; // First matching resource size
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (firstIter == -1) {
|
||||
tiles = resource.extractTiles(resourceType);
|
||||
if (tiles.length == 0) {
|
||||
throw new InvalidInputException(
|
||||
"Could not find matching resources for action: consumeextra");
|
||||
"Could not find matching resources for action: consume_extra");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,28 +80,29 @@ public class ConsumeExtra extends AssignAction {
|
|||
return false;
|
||||
}
|
||||
ConsumeExtra otherAction = (ConsumeExtra) op;
|
||||
if (firstIter != otherAction.firstIter || matchSize != otherAction.matchSize ||
|
||||
if (matchSize != otherAction.matchSize ||
|
||||
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 = firstIter;
|
||||
int endIter = resource.getNumParamEntry();
|
||||
int iter = 0;
|
||||
int sizeLeft = dt.getLength();
|
||||
while (sizeLeft > 0 && iter != endIter) {
|
||||
ParamEntry entry = resource.getEntry(iter);
|
||||
while (sizeLeft > 0 && iter != tiles.length) {
|
||||
ParamEntry entry = tiles[iter];
|
||||
++iter;
|
||||
if (!entry.isExclusion()) {
|
||||
break; // Reached end of resource list
|
||||
}
|
||||
if (entry.getType() != resourceType || entry.getAllGroups().length != 1) {
|
||||
continue; // Not a single register in desired list
|
||||
}
|
||||
if (status[entry.getGroup()] != 0) {
|
||||
continue; // Already consumed
|
||||
}
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
/* ###
|
||||
* 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.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 stack resources as a side-effect
|
||||
*
|
||||
* This action is a side-effect and doesn't assign an address for the current parameter.
|
||||
* If the current parameter has been assigned a address that is not on the stack, this action consumes
|
||||
* stack resources as if the parameter were allocated to the stack. If the current parameter was
|
||||
* already assigned a stack address, no additional action is taken.
|
||||
*/
|
||||
public class ExtraStack extends AssignAction {
|
||||
|
||||
private ParamEntry stackEntry; // Parameter entry corresponding to the stack
|
||||
|
||||
/**
|
||||
* Find stack entry in resource list
|
||||
* @throws InvalidInputException if there is no stack entry
|
||||
*/
|
||||
private void initializeEntry() throws InvalidInputException {
|
||||
for (int i = 0; i < resource.getNumParamEntry(); ++i) {
|
||||
ParamEntry entry = resource.getEntry(i);
|
||||
if (!entry.isExclusion() && entry.getSpace().isStackSpace()) {
|
||||
stackEntry = entry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (stackEntry == null) {
|
||||
throw new InvalidInputException(
|
||||
"Cannot find matching <pentry> for action: extra_stack");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for use with restoreXml
|
||||
* @param res is the resource list
|
||||
* @param val is a dummy variable
|
||||
*/
|
||||
public ExtraStack(ParamListStandard res, int val) {
|
||||
super(res);
|
||||
stackEntry = null;
|
||||
}
|
||||
|
||||
public ExtraStack(ParamListStandard res) throws InvalidInputException {
|
||||
super(res);
|
||||
stackEntry = null;
|
||||
initializeEntry();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AssignAction clone(ParamListStandard newResource) throws InvalidInputException {
|
||||
return new ExtraStack(newResource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEquivalent(AssignAction op) {
|
||||
if (this.getClass() != op.getClass()) {
|
||||
return false;
|
||||
}
|
||||
ExtraStack otherAction = (ExtraStack) op;
|
||||
return stackEntry.isEquivalent(otherAction.stackEntry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int assignAddress(DataType dt, PrototypePieces proto, int pos, DataTypeManager dtManager,
|
||||
int[] status, ParameterPieces res) {
|
||||
if (res.address.getAddressSpace() == stackEntry.getSpace()) {
|
||||
return SUCCESS; // Parameter was already assigned to the stack
|
||||
}
|
||||
int grp = stackEntry.getGroup();
|
||||
// We assign the stack address (but ignore the actual address) updating the status for the stack,
|
||||
// which consumes the stack resources.
|
||||
ParameterPieces unused = new ParameterPieces();
|
||||
status[grp] =
|
||||
stackEntry.getAddrBySlot(status[grp], dt.getLength(), dt.getAlignment(), unused);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void encode(Encoder encoder) throws IOException {
|
||||
encoder.openElement(ELEM_EXTRA_STACK);
|
||||
encoder.closeElement(ELEM_EXTRA_STACK);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreXml(XmlPullParser parser) throws XmlParseException {
|
||||
XmlElement elem = parser.start(ELEM_EXTRA_STACK.name());
|
||||
parser.end(elem);
|
||||
try {
|
||||
initializeEntry();
|
||||
}
|
||||
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.
|
||||
|
@ -42,7 +42,7 @@ public class GotoStack extends AssignAction {
|
|||
}
|
||||
}
|
||||
if (stackEntry == null) {
|
||||
throw new InvalidInputException("Cannot find matching <pentry> for action: gotostack");
|
||||
throw new InvalidInputException("Cannot find matching <pentry> for action: goto_stack");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
@ -55,9 +55,20 @@ public class HomogeneousAggregate extends SizeRestrictedFilter {
|
|||
maxPrimitives = maxPrim;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor
|
||||
* @param op2 is the filter to copy
|
||||
*/
|
||||
public HomogeneousAggregate(HomogeneousAggregate op2) {
|
||||
super(op2);
|
||||
name = op2.name;
|
||||
metaType = op2.metaType;
|
||||
maxPrimitives = op2.maxPrimitives;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DatatypeFilter clone() {
|
||||
return new HomogeneousAggregate(name, metaType, maxPrimitives, minSize, maxSize);
|
||||
return new HomogeneousAggregate(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -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.
|
||||
|
@ -52,6 +52,15 @@ public class MetaTypeFilter extends SizeRestrictedFilter {
|
|||
metaType = meta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor
|
||||
* @param op2 is the filter to copy
|
||||
*/
|
||||
public MetaTypeFilter(MetaTypeFilter op2) {
|
||||
super(op2);
|
||||
metaType = op2.metaType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEquivalent(DatatypeFilter op) {
|
||||
if (!super.isEquivalent(op)) {
|
||||
|
@ -69,7 +78,7 @@ public class MetaTypeFilter extends SizeRestrictedFilter {
|
|||
|
||||
@Override
|
||||
public DatatypeFilter clone() {
|
||||
return new MetaTypeFilter(metaType, minSize, maxSize);
|
||||
return new MetaTypeFilter(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -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.
|
||||
|
@ -21,7 +21,6 @@ import static ghidra.program.model.pcode.ElementId.*;
|
|||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.lang.*;
|
||||
|
@ -94,22 +93,7 @@ public class MultiMemberAssign extends AssignAction {
|
|||
|
||||
System.arraycopy(tmpStatus, 0, status, 0, tmpStatus.length); // Commit resource usage for all the pieces
|
||||
res.type = dt;
|
||||
if (pieces.size() == 1) {
|
||||
res.address = pieces.get(0).getAddress();
|
||||
return SUCCESS;
|
||||
}
|
||||
res.joinPieces = new Varnode[pieces.size()];
|
||||
if (!consumeMostSig) {
|
||||
for (int i = 0; i < res.joinPieces.length; ++i) {
|
||||
res.joinPieces[i] = pieces.get(pieces.size() - 1 - i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < pieces.size(); ++i) {
|
||||
res.joinPieces[i] = pieces.get(i);
|
||||
}
|
||||
}
|
||||
res.address = Address.NO_ADDRESS; // Placeholder for join space address
|
||||
res.assignAddressFromPieces(pieces, consumeMostSig, false, resource.getLanguage());
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -45,8 +45,10 @@ public class MultiSlotAssign extends AssignAction {
|
|||
private boolean consumeMostSig; // True if resources are consumed starting with most significant bytes
|
||||
private boolean enforceAlignment; // True if register resources are discarded to match alignment
|
||||
private boolean justifyRight; // True if initial bytes are padding for odd data-type sizes
|
||||
private boolean adjacentEntries; // True if an assignment should only consume adjacent entries in the list
|
||||
private boolean allowBackfill; // True if entries skipped for alignment can be reused for later params
|
||||
private ParamEntry[] tiles; // Registers that can be joined
|
||||
private ParamEntry stackEntry; // The stack resource
|
||||
private int firstIter; // Iterator to first element in the resource list
|
||||
|
||||
/**
|
||||
* Cache specific ParamEntry needed by the action
|
||||
|
@ -56,19 +58,9 @@ public class MultiSlotAssign extends AssignAction {
|
|||
* @throws InvalidInputException if the required elements are not available in the resource list
|
||||
*/
|
||||
private void initializeEntries() throws InvalidInputException {
|
||||
firstIter = -1;
|
||||
for (int i = 0; i < resource.getNumParamEntry(); ++i) {
|
||||
ParamEntry entry = resource.getEntry(i);
|
||||
if (firstIter == -1 && entry.isExclusion() && entry.getType() == resourceType &&
|
||||
entry.getAllGroups().length == 1) {
|
||||
firstIter = i; // First matching resource size
|
||||
}
|
||||
if (!entry.isExclusion() && entry.getSpace().isStackSpace()) {
|
||||
stackEntry = entry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (firstIter == -1) {
|
||||
tiles = resource.extractTiles(resourceType);
|
||||
stackEntry = resource.extractStack();
|
||||
if (tiles.length == 0) {
|
||||
throw new InvalidInputException("Could not find matching resources for action: join");
|
||||
}
|
||||
if (consumeFromStack && stackEntry == null) {
|
||||
|
@ -87,6 +79,8 @@ public class MultiSlotAssign extends AssignAction {
|
|||
consumeMostSig = false;
|
||||
enforceAlignment = false;
|
||||
justifyRight = false;
|
||||
adjacentEntries = true;
|
||||
allowBackfill = false;
|
||||
if (res.getEntry(0).isBigEndian()) {
|
||||
consumeMostSig = true;
|
||||
justifyRight = true;
|
||||
|
@ -95,13 +89,16 @@ public class MultiSlotAssign extends AssignAction {
|
|||
}
|
||||
|
||||
public MultiSlotAssign(StorageClass store, boolean stack, boolean mostSig, boolean align,
|
||||
boolean justRight, ParamListStandard res) throws InvalidInputException {
|
||||
boolean justRight, boolean backfill, ParamListStandard res)
|
||||
throws InvalidInputException {
|
||||
super(res);
|
||||
resourceType = store;
|
||||
consumeFromStack = stack;
|
||||
consumeMostSig = mostSig;
|
||||
enforceAlignment = align;
|
||||
justifyRight = justRight;
|
||||
adjacentEntries = true;
|
||||
allowBackfill = backfill;
|
||||
stackEntry = null;
|
||||
initializeEntries();
|
||||
}
|
||||
|
@ -109,7 +106,7 @@ public class MultiSlotAssign extends AssignAction {
|
|||
@Override
|
||||
public AssignAction clone(ParamListStandard newResource) throws InvalidInputException {
|
||||
return new MultiSlotAssign(resourceType, consumeFromStack, consumeMostSig, enforceAlignment,
|
||||
justifyRight, newResource);
|
||||
justifyRight, allowBackfill, newResource);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -120,15 +117,23 @@ public class MultiSlotAssign extends AssignAction {
|
|||
MultiSlotAssign otherAction = (MultiSlotAssign) op;
|
||||
if (consumeFromStack != otherAction.consumeFromStack ||
|
||||
consumeMostSig != otherAction.consumeMostSig ||
|
||||
enforceAlignment != otherAction.enforceAlignment) {
|
||||
return false;
|
||||
}
|
||||
if (firstIter != otherAction.firstIter || justifyRight != otherAction.justifyRight) {
|
||||
enforceAlignment != otherAction.enforceAlignment ||
|
||||
justifyRight != otherAction.justifyRight ||
|
||||
adjacentEntries != otherAction.adjacentEntries ||
|
||||
allowBackfill != otherAction.allowBackfill) {
|
||||
return false;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (stackEntry == null && otherAction.stackEntry == null) {
|
||||
// Nothing to compare
|
||||
}
|
||||
|
@ -143,6 +148,44 @@ public class MultiSlotAssign extends AssignAction {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if a data-type of the given size will fit starting at a particular entry within
|
||||
* the resource list. If necessary, check
|
||||
* 1) If the type will be properly aligned
|
||||
* 2) If there are enough remaining registers, up to the end of the resource list, to
|
||||
* cover the data-type and that have not been consumed.
|
||||
* @param iter is the first resource entry to use for the data-type
|
||||
* @param sizeLeft initially holds the size of the data-type to cover in bytes
|
||||
* @param align is the alignment requirement for the data-type
|
||||
* @param resourcesConsumed is the number of bytes in resources already consumed/skipped
|
||||
* @param tmpStatus is the current consumption status for the resource list
|
||||
* @return true if the data-type will fit
|
||||
*/
|
||||
private boolean checkFit(int iter, int sizeLeft, int align, int resourcesConsumed,
|
||||
int[] tmpStatus) {
|
||||
ParamEntry entry = tiles[iter];
|
||||
if (tmpStatus[entry.getGroup()] != 0) {
|
||||
return false;
|
||||
}
|
||||
if (enforceAlignment) {
|
||||
int regSize = entry.getSize();
|
||||
if (align > regSize && (resourcesConsumed % align) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!adjacentEntries) {
|
||||
return true;
|
||||
}
|
||||
while (iter != tiles.length && sizeLeft > 0) {
|
||||
entry = tiles[iter];
|
||||
if (tmpStatus[entry.getGroup()] != 0) {
|
||||
return false;
|
||||
}
|
||||
sizeLeft -= entry.getSize();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int assignAddress(DataType dt, PrototypePieces proto, int pos, DataTypeManager dtManager,
|
||||
int[] status, ParameterPieces res) {
|
||||
|
@ -151,37 +194,22 @@ public class MultiSlotAssign extends AssignAction {
|
|||
ParameterPieces param = new ParameterPieces();
|
||||
int sizeLeft = dt.getLength();
|
||||
int align = dt.getAlignment();
|
||||
int iter = firstIter;
|
||||
int endIter = resource.getNumParamEntry();
|
||||
if (enforceAlignment) {
|
||||
int resourcesConsumed = 0;
|
||||
while (iter != endIter) {
|
||||
ParamEntry entry = resource.getEntry(iter);
|
||||
if (!entry.isExclusion()) {
|
||||
break;
|
||||
} // Reached end of resource list
|
||||
if (entry.getType() == resourceType && entry.getAllGroups().length == 1) { // Single register
|
||||
if (tmpStatus[entry.getGroup()] == 0) { // Not consumed
|
||||
int regSize = entry.getSize();
|
||||
if (align <= regSize || (resourcesConsumed % align) == 0) {
|
||||
break;
|
||||
}
|
||||
tmpStatus[entry.getGroup()] = -1; // Consume unaligned register
|
||||
}
|
||||
resourcesConsumed += entry.getSize();
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
while (sizeLeft > 0 && iter != endIter) {
|
||||
ParamEntry entry = resource.getEntry(iter);
|
||||
++iter;
|
||||
if (!entry.isExclusion()) {
|
||||
int iter = 0;
|
||||
int resourcesConsumed = 0;
|
||||
while (iter != tiles.length) {
|
||||
if (checkFit(iter, sizeLeft, align, resourcesConsumed, tmpStatus)) {
|
||||
break;
|
||||
} // Reached end of resource list
|
||||
if (entry.getType() != resourceType || entry.getAllGroups().length != 1) {
|
||||
continue;
|
||||
} // Not a single register from desired resource list
|
||||
}
|
||||
ParamEntry entry = tiles[iter];
|
||||
if (!allowBackfill) {
|
||||
tmpStatus[entry.getGroup()] = -1; // Consume unaligned register
|
||||
}
|
||||
resourcesConsumed += entry.getSize();
|
||||
++iter;
|
||||
}
|
||||
while (sizeLeft > 0 && iter != tiles.length) {
|
||||
ParamEntry entry = tiles[iter];
|
||||
++iter;
|
||||
if (tmpStatus[entry.getGroup()] != 0) {
|
||||
continue;
|
||||
} // Already consumed
|
||||
|
@ -229,22 +257,7 @@ public class MultiSlotAssign extends AssignAction {
|
|||
}
|
||||
System.arraycopy(tmpStatus, 0, status, 0, tmpStatus.length); // Commit resource usage for all the pieces
|
||||
res.type = dt;
|
||||
if (pieces.size() == 1 && !onePieceJoin) {
|
||||
res.address = pieces.get(0).getAddress();
|
||||
return SUCCESS;
|
||||
}
|
||||
res.joinPieces = new Varnode[pieces.size()];
|
||||
if (!consumeMostSig) {
|
||||
for (int i = 0; i < res.joinPieces.length; ++i) {
|
||||
res.joinPieces[i] = pieces.get(pieces.size() - 1 - i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < pieces.size(); ++i) {
|
||||
res.joinPieces[i] = pieces.get(i);
|
||||
}
|
||||
}
|
||||
res.address = Address.NO_ADDRESS; // Placeholder for join space address
|
||||
res.assignAddressFromPieces(pieces, consumeMostSig, onePieceJoin, resource.getLanguage());
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -259,6 +272,7 @@ public class MultiSlotAssign extends AssignAction {
|
|||
}
|
||||
encoder.writeBool(ATTRIB_ALIGN, enforceAlignment);
|
||||
encoder.writeBool(ATTRIB_STACKSPILL, consumeFromStack);
|
||||
encoder.writeBool(ATTRIB_BACKFILL, allowBackfill);
|
||||
encoder.closeElement(ELEM_JOIN);
|
||||
}
|
||||
|
||||
|
@ -281,6 +295,9 @@ public class MultiSlotAssign extends AssignAction {
|
|||
else if (name.equals(ATTRIB_STACKSPILL.name())) {
|
||||
consumeFromStack = SpecXmlUtils.decodeBoolean(attrib.getValue());
|
||||
}
|
||||
else if (name.equals(ATTRIB_BACKFILL.name())) {
|
||||
allowBackfill = SpecXmlUtils.decodeBoolean(attrib.getValue());
|
||||
}
|
||||
}
|
||||
parser.end(elem);
|
||||
try {
|
||||
|
|
|
@ -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.
|
||||
|
@ -45,61 +45,43 @@ public class MultiSlotDualAssign extends AssignAction {
|
|||
private boolean consumeMostSig; // True if resources are consumed starting with most significant bytes
|
||||
private boolean justifyRight; // True if initial bytes are padding for odd data-type sizes
|
||||
private int tileSize; // Number of bytes in a tile
|
||||
private int baseIter; // Iterator to first element in the base resource list
|
||||
private int altIter; // Iterator to first element in alternate resource list
|
||||
private ParamEntry[] baseTiles; // General registers for joining
|
||||
private ParamEntry[] altTiles; // Alternate registers for joininig
|
||||
|
||||
/**
|
||||
* Find the first ParamEntry matching the baseType, and the first matching altType.
|
||||
* @throws InvalidInputException if the required elements are not available in the resource list
|
||||
*/
|
||||
private void initializeEntries() throws InvalidInputException {
|
||||
baseIter = -1;
|
||||
altIter = -1;
|
||||
for (int i = 0; i < resource.getNumParamEntry(); ++i) {
|
||||
ParamEntry entry = resource.getEntry(i);
|
||||
if (baseIter == -1 && entry.isExclusion() && entry.getType() == baseType &&
|
||||
entry.getAllGroups().length == 1) {
|
||||
baseIter = i; // First matching base resource type
|
||||
}
|
||||
if (altIter == -1 && entry.isExclusion() && entry.getType() == altType &&
|
||||
entry.getAllGroups().length == 1) {
|
||||
altIter = i; // First matching alt resource type
|
||||
}
|
||||
}
|
||||
if (baseIter == -1 || altIter == -1) {
|
||||
baseTiles = resource.extractTiles(baseType);
|
||||
altTiles = resource.extractTiles(altType);
|
||||
if (baseTiles.length == 0 || altTiles.length == 0) {
|
||||
throw new InvalidInputException(
|
||||
"Could not find matching resources for action: join_dual_class");
|
||||
}
|
||||
tileSize = resource.getEntry(baseIter).getSize();
|
||||
if (tileSize != resource.getEntry(altIter).getSize()) {
|
||||
tileSize = baseTiles[0].getSize();
|
||||
if (tileSize != altTiles[0].getSize()) {
|
||||
throw new InvalidInputException(
|
||||
"Storage class register sizes do not match for action: join_dual_class");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first unused ParamEntry that matches the given storage class
|
||||
* Get the first unused ParamEntry within a given tileset
|
||||
* @param iter points to the starting entry to search
|
||||
* @param storage is the given storage class to match
|
||||
* @param tiles is the given tileset
|
||||
* @param status is the usage information for the entries
|
||||
* @return the iterator to the unused ParamEntry
|
||||
*/
|
||||
private int getFirstUnused(int iter, StorageClass storage, int[] status) {
|
||||
int endIter = resource.getNumParamEntry();
|
||||
for (; iter != endIter; ++iter) {
|
||||
ParamEntry entry = resource.getEntry(iter);
|
||||
if (!entry.isExclusion()) {
|
||||
break; // Reached end of resource list
|
||||
}
|
||||
if (entry.getType() != storage || entry.getAllGroups().length != 1) {
|
||||
continue; // Not a single register from desired resource
|
||||
}
|
||||
private int getFirstUnused(int iter, ParamEntry[] tiles, int[] status) {
|
||||
for (; iter != tiles.length; ++iter) {
|
||||
ParamEntry entry = tiles[iter];
|
||||
if (status[entry.getGroup()] != 0) {
|
||||
continue; // Already consumed
|
||||
}
|
||||
return iter;
|
||||
}
|
||||
return endIter;
|
||||
return tiles.length;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -186,12 +168,25 @@ public class MultiSlotDualAssign extends AssignAction {
|
|||
justifyRight != otherAction.justifyRight) {
|
||||
return false;
|
||||
}
|
||||
if (baseIter != otherAction.baseIter || altIter != otherAction.altIter) {
|
||||
return false;
|
||||
}
|
||||
if (baseType != otherAction.baseType || altType != otherAction.altType) {
|
||||
return false;
|
||||
}
|
||||
if (baseTiles.length != otherAction.baseTiles.length) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < baseTiles.length; ++i) {
|
||||
if (!baseTiles[i].isEquivalent(otherAction.baseTiles[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (altTiles.length != otherAction.altTiles.length) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < altTiles.length; ++i) {
|
||||
if (!altTiles[i].isEquivalent(otherAction.altTiles[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -209,25 +204,28 @@ public class MultiSlotDualAssign extends AssignAction {
|
|||
ArrayList<Varnode> pieces = new ArrayList<>();
|
||||
int typeSize = dt.getLength();
|
||||
int sizeLeft = typeSize;
|
||||
int iterBase = baseIter;
|
||||
int iterAlt = altIter;
|
||||
int endIter = resource.getNumParamEntry();
|
||||
int iterBase = 0;
|
||||
int iterAlt = 0;
|
||||
while (sizeLeft > 0) {
|
||||
int iter;
|
||||
int iterType = getTileClass(primitives, typeSize - sizeLeft, primitiveIndex);
|
||||
if (iterType < 0) {
|
||||
return FAIL;
|
||||
}
|
||||
ParamEntry entry;
|
||||
if (iterType == 0) {
|
||||
iter = iterBase = getFirstUnused(iterBase, baseType, tmpStatus);
|
||||
iterBase = getFirstUnused(iterBase, baseTiles, tmpStatus);
|
||||
if (iterBase == baseTiles.length) {
|
||||
return FAIL; // Out of general registers
|
||||
}
|
||||
entry = baseTiles[iterBase];
|
||||
}
|
||||
else {
|
||||
iter = iterAlt = getFirstUnused(iterAlt, altType, tmpStatus);
|
||||
iterAlt = getFirstUnused(iterAlt, altTiles, tmpStatus);
|
||||
if (iterAlt == altTiles.length) {
|
||||
return FAIL; // Out of alternate registers
|
||||
}
|
||||
entry = altTiles[iterAlt];
|
||||
}
|
||||
if (iter == endIter) {
|
||||
return FAIL; // Out of the particular resource
|
||||
}
|
||||
ParamEntry entry = resource.getEntry(iter);
|
||||
int trialSize = entry.getSize();
|
||||
entry.getAddrBySlot(tmpStatus[entry.getGroup()], trialSize, 1, param);
|
||||
tmpStatus[entry.getGroup()] = -1; // Consume the register
|
||||
|
@ -254,22 +252,7 @@ public class MultiSlotDualAssign extends AssignAction {
|
|||
}
|
||||
System.arraycopy(tmpStatus, 0, status, 0, tmpStatus.length); // Commit resource usage for all the pieces
|
||||
res.type = dt;
|
||||
if (pieces.size() == 1) {
|
||||
res.address = pieces.get(0).getAddress();
|
||||
return SUCCESS;
|
||||
}
|
||||
res.joinPieces = new Varnode[pieces.size()];
|
||||
if (!consumeMostSig) {
|
||||
for (int i = 0; i < res.joinPieces.length; ++i) {
|
||||
res.joinPieces[i] = pieces.get(pieces.size() - 1 - i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < pieces.size(); ++i) {
|
||||
res.joinPieces[i] = pieces.get(i);
|
||||
}
|
||||
}
|
||||
res.address = Address.NO_ADDRESS;
|
||||
res.assignAddressFromPieces(pieces, consumeMostSig, false, resource.getLanguage());
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
@ -19,6 +19,7 @@ import static ghidra.program.model.pcode.AttributeId.*;
|
|||
import static ghidra.program.model.pcode.ElementId.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
|
@ -28,8 +29,8 @@ import ghidra.util.xml.SpecXmlUtils;
|
|||
import ghidra.xml.*;
|
||||
|
||||
/**
|
||||
* A common base class for data-type filters that tests for a size range.
|
||||
* Any filter that inherits from this, can use ATTRIB_MINSIZE and ATTRIB_MAXSIZE
|
||||
* A base class for data-type filters that tests either for either a range or an enumerated list of sizes.
|
||||
* Any filter that inherits from this, can use ATTRIB_MINSIZE, ATTRIB_MAXSIZE, or ATTRIB_SIZES
|
||||
* to place bounds on the possible sizes of data-types. The bounds are enforced
|
||||
* by calling filterOnSize() within the inheriting classes filter() method.
|
||||
*/
|
||||
|
@ -39,6 +40,7 @@ public class SizeRestrictedFilter implements DatatypeFilter {
|
|||
|
||||
protected int minSize; // Minimum size of the data-type in bytes
|
||||
protected int maxSize; // Maximum size of the data-type in bytes
|
||||
protected HashSet<Integer> sizes = null;
|
||||
|
||||
public SizeRestrictedFilter() {
|
||||
minSize = 0;
|
||||
|
@ -54,10 +56,57 @@ public class SizeRestrictedFilter implements DatatypeFilter {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor
|
||||
* @param op2 is the filter to copy
|
||||
*/
|
||||
public SizeRestrictedFilter(SizeRestrictedFilter op2) {
|
||||
minSize = op2.minSize;
|
||||
maxSize = op2.maxSize;
|
||||
if (op2.sizes != null) {
|
||||
sizes = new HashSet<Integer>(op2.sizes);
|
||||
}
|
||||
else {
|
||||
sizes = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the given string as a comma or space separated list of decimal integers,
|
||||
* populating the sizes set.
|
||||
* @param str is the given string to parse
|
||||
* @throws XmlParseException if the string does not valid (positive) integers
|
||||
*/
|
||||
protected void initFromSizeList(String str) throws XmlParseException {
|
||||
String[] numStrings = str.split(" +|,");
|
||||
sizes = new HashSet<Integer>();
|
||||
minSize = Integer.MAX_VALUE;
|
||||
maxSize = 0;
|
||||
for (String valString : numStrings) {
|
||||
int val = Integer.parseInt(valString);
|
||||
if (val <= 0) {
|
||||
throw new XmlParseException("Bad filter size");
|
||||
}
|
||||
sizes.add(val);
|
||||
if (val < minSize) {
|
||||
minSize = val;
|
||||
}
|
||||
if (val > maxSize) {
|
||||
maxSize = val;
|
||||
}
|
||||
}
|
||||
if (sizes.isEmpty()) {
|
||||
sizes = null;
|
||||
minSize = 0;
|
||||
maxSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enforce any size bounds on a given data-type.
|
||||
* If \b maxSize is not zero, the data-type is checked to see if its size in bytes
|
||||
* falls between \b minSize and \b maxSize inclusive.
|
||||
* falls between \b minSize and \b maxSize inclusive. If enumerated sizes are present,
|
||||
* also check that the particular size is in the enumerated set.
|
||||
* @param dt is the data-type to test
|
||||
* @return true if the data-type meets the size restrictions
|
||||
*/
|
||||
|
@ -65,12 +114,15 @@ public class SizeRestrictedFilter implements DatatypeFilter {
|
|||
if (maxSize == 0) {
|
||||
return true; // maxSize of 0 means no size filtering is performed
|
||||
}
|
||||
if (sizes != null) {
|
||||
return sizes.contains(Integer.valueOf(dt.getLength()));
|
||||
}
|
||||
return (dt.getLength() >= minSize && dt.getLength() <= maxSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DatatypeFilter clone() {
|
||||
return new SizeRestrictedFilter(minSize, maxSize);
|
||||
return new SizeRestrictedFilter(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -82,6 +134,13 @@ public class SizeRestrictedFilter implements DatatypeFilter {
|
|||
if (maxSize != otherFilter.maxSize || minSize != otherFilter.minSize) {
|
||||
return false;
|
||||
}
|
||||
if (sizes != null && otherFilter.sizes != null) {
|
||||
if (!sizes.equals(otherFilter.sizes))
|
||||
return false;
|
||||
}
|
||||
else if (sizes != null || otherFilter.sizes != null) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -91,21 +150,49 @@ public class SizeRestrictedFilter implements DatatypeFilter {
|
|||
}
|
||||
|
||||
protected void encodeAttributes(Encoder encoder) throws IOException {
|
||||
encoder.writeUnsignedInteger(ATTRIB_MINSIZE, minSize);
|
||||
encoder.writeUnsignedInteger(ATTRIB_MAXSIZE, maxSize);
|
||||
if (sizes != null) {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
Iterator<Integer> iter = sizes.iterator();
|
||||
buffer.append(iter.next().intValue());
|
||||
while (iter.hasNext()) {
|
||||
buffer.append(',');
|
||||
buffer.append(iter.next().intValue());
|
||||
}
|
||||
encoder.writeString(ATTRIB_SIZES, buffer.toString());
|
||||
}
|
||||
else {
|
||||
encoder.writeUnsignedInteger(ATTRIB_MINSIZE, minSize);
|
||||
encoder.writeUnsignedInteger(ATTRIB_MAXSIZE, maxSize);
|
||||
}
|
||||
}
|
||||
|
||||
protected void restoreAttributesXml(XmlElement el) {
|
||||
protected void restoreAttributesXml(XmlElement el) throws XmlParseException {
|
||||
Iterator<Entry<String, String>> iter = el.getAttributes().entrySet().iterator();
|
||||
while (iter.hasNext()) {
|
||||
Entry<String, String> attrib = iter.next();
|
||||
String nm = attrib.getKey();
|
||||
if (nm.equals(ATTRIB_MINSIZE.name())) {
|
||||
if (sizes != null) {
|
||||
throw new XmlParseException(
|
||||
"Mixing \"sizes\" with \"minsize\" and \"maxsize\"");
|
||||
}
|
||||
minSize = SpecXmlUtils.decodeInt(attrib.getValue());
|
||||
}
|
||||
else if (nm.equals(ATTRIB_MAXSIZE.name())) {
|
||||
if (sizes != null) {
|
||||
throw new XmlParseException(
|
||||
"Mixing \"sizes\" with \"minsize\" and \"maxsize\"");
|
||||
}
|
||||
maxSize = SpecXmlUtils.decodeInt(attrib.getValue());
|
||||
}
|
||||
else if (nm.equals(ATTRIB_SIZES.name())) {
|
||||
if (minSize != 0 || maxSize != 0) {
|
||||
throw new XmlParseException(
|
||||
"Mixing \"sizes\" with \"minsize\" and \"maxsize\"");
|
||||
}
|
||||
String sizeList = attrib.getValue();
|
||||
initFromSizeList(sizeList);
|
||||
}
|
||||
}
|
||||
if (maxSize == 0 && minSize >= 0) {
|
||||
// If no ATTRIB_MAXSIZE is given, assume there is no upper bound on size
|
||||
|
|
|
@ -244,5 +244,9 @@ public record AttributeId(String name, int id) {
|
|||
public static final AttributeId ATTRIB_STORAGE = new AttributeId("storage", 149);
|
||||
public static final AttributeId ATTRIB_STACKSPILL = new AttributeId("stackspill", 150);
|
||||
|
||||
public static final AttributeId ATTRIB_UNKNOWN = new AttributeId("XMLunknown", 151);
|
||||
// modelrules
|
||||
public static final AttributeId ATTRIB_SIZES = new AttributeId("sizes", 151);
|
||||
public static final AttributeId ATTRIB_BACKFILL = new AttributeId("backfill", 152);
|
||||
|
||||
public static final AttributeId ATTRIB_UNKNOWN = new AttributeId("XMLunknown", 153);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
@ -456,6 +456,7 @@ public record ElementId(String name, int id) {
|
|||
public static final ElementId ELEM_JOIN_PER_PRIMITIVE =
|
||||
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_UNKNOWN = new ElementId("XMLunknown", 287);
|
||||
public static final ElementId ELEM_UNKNOWN = new ElementId("XMLunknown", 288);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
@ -175,6 +175,29 @@ public class Varnode {
|
|||
return rangeIntersects(varnode.offset, endOtherOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this contiguous (as the most significant piece) with the given Varnode
|
||||
* @param lo is the other Varnode to compare with
|
||||
* @param bigEndian is true for big endian significance ordering
|
||||
* @return true if the two byte ranges are contiguous and in order
|
||||
*/
|
||||
public boolean isContiguous(Varnode lo, boolean bigEndian) {
|
||||
AddressSpace spc = address.getAddressSpace();
|
||||
if (spc != lo.address.getAddressSpace())
|
||||
return false;
|
||||
if (bigEndian) {
|
||||
long nextoff = spc.truncateOffset(offset + size);
|
||||
if (nextoff == lo.offset)
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
long nextoff = spc.truncateOffset(lo.offset + lo.size);
|
||||
if (nextoff == offset)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean rangeIntersects(long otherOffset, long otherEndOffset) {
|
||||
long endOffset = offset;
|
||||
if (size > 0) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue