mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-25 21:51:47 +00:00
GP-1653 Allow PrototypeModel aliases
This commit is contained in:
parent
22a5950d08
commit
cb913e6a91
@ -747,6 +747,7 @@ void Architecture::parseDynamicRule(const Element *el)
|
||||
/// This handles the \<prototype> and \<resolveprototype> tags. It builds the
|
||||
/// ProtoModel object based on the tag and makes it available generally to the decompiler.
|
||||
/// \param el is the XML tag element
|
||||
/// \return the new ProtoModel object
|
||||
ProtoModel *Architecture::parseProto(const Element *el)
|
||||
|
||||
{
|
||||
@ -1100,6 +1101,26 @@ void Architecture::parseAggressiveTrim(const Element *el)
|
||||
}
|
||||
}
|
||||
|
||||
/// Clone the named ProtoModel, attaching it to another name.
|
||||
/// \param aliasName is the new name to assign
|
||||
/// \param parentName is the name of the parent model
|
||||
void Architecture::createModelAlias(const string &aliasName,const string &parentName)
|
||||
|
||||
{
|
||||
map<string,ProtoModel *>::const_iterator iter = protoModels.find(parentName);
|
||||
if (iter == protoModels.end())
|
||||
throw LowlevelError("Requesting non-existent prototype model: "+parentName);
|
||||
ProtoModel *model = (*iter).second;
|
||||
if (model->isMerged())
|
||||
throw LowlevelError("Cannot make alias of merged model: "+parentName);
|
||||
if (model->getAliasParent() != (const ProtoModel *)0)
|
||||
throw LowlevelError("Cannot make alias of an alias: "+parentName);
|
||||
iter = protoModels.find(aliasName);
|
||||
if (iter != protoModels.end())
|
||||
throw LowlevelError("Duplicate ProtoModel name: "+aliasName);
|
||||
protoModels[aliasName] = new ProtoModel(aliasName,*model);
|
||||
}
|
||||
|
||||
/// This looks for the \<processor_spec> tag and and sets configuration
|
||||
/// parameters based on it.
|
||||
/// \param store is the document store holding the tag
|
||||
@ -1215,6 +1236,12 @@ void Architecture::parseCompilerConfig(DocumentStorage &store)
|
||||
parseDeadcodeDelay(*iter);
|
||||
else if (elname == "inferptrbounds")
|
||||
parseInferPtrBounds(*iter);
|
||||
else if (elname == "modelalias") {
|
||||
const Element *el = *iter;
|
||||
string aliasName = el->getAttributeValue("name");
|
||||
string parentName = el->getAttributeValue("parent");
|
||||
createModelAlias(aliasName, parentName);
|
||||
}
|
||||
}
|
||||
|
||||
el = store.getTag("specextensions"); // Look for any user-defined configuration document
|
||||
@ -1224,7 +1251,7 @@ void Architecture::parseCompilerConfig(DocumentStorage &store)
|
||||
const string &elname( (*iter)->getName() );
|
||||
if (elname == "prototype")
|
||||
parseProto(*iter);
|
||||
else if (elname == "callfixup") {
|
||||
else if (elname == "callfixup") {
|
||||
pcodeinjectlib->restoreXmlInject(archid+" : compiler spec", (*iter)->getAttributeValue("name"),
|
||||
InjectPayload::CALLFIXUP_TYPE, *iter);
|
||||
}
|
||||
@ -1253,8 +1280,7 @@ void Architecture::parseCompilerConfig(DocumentStorage &store)
|
||||
// We must have a __thiscall calling convention
|
||||
map<string,ProtoModel *>::iterator miter = protoModels.find("__thiscall");
|
||||
if (miter == protoModels.end()) { // If __thiscall doesn't exist we clone it off of the default
|
||||
ProtoModel *thismodel = new ProtoModel("__thiscall",*defaultfp);
|
||||
protoModels["__thiscall"] = thismodel;
|
||||
createModelAlias("__thiscall",defaultfp->getName());
|
||||
}
|
||||
userops.setDefaults(this);
|
||||
initializeSegments();
|
||||
|
@ -258,6 +258,7 @@ protected:
|
||||
void fillinReadOnlyFromLoader(void); ///< Load info about read-only sections
|
||||
void initializeSegments(); ///< Set up segment resolvers
|
||||
void cacheAddrSpaceProperties(void); ///< Calculate some frequently used space properties and cache them
|
||||
void createModelAlias(const string &aliasName,const string &parentName); ///< Create name alias for a ProtoModel
|
||||
|
||||
void parseProcessorConfig(DocumentStorage &store); ///< Apply processor specific configuration
|
||||
void parseCompilerConfig(DocumentStorage &store); ///< Apply compiler specific configuration
|
||||
|
@ -672,6 +672,7 @@ public:
|
||||
virtual ~ProtoModel(void); ///< Destructor
|
||||
const string &getName(void) const { return name; } ///< Get the name of the prototype model
|
||||
Architecture *getArch(void) const { return glb; } ///< Get the owning Architecture
|
||||
const ProtoModel *getAliasParent(void) const { return compatModel; } ///< Return \e model \b this is an alias of (or null)
|
||||
uint4 hasEffect(const Address &addr,int4 size) const; ///< Determine side-effect of \b this on the given memory range
|
||||
int4 getExtraPop(void) const { return extrapop; } ///< Get the stack-pointer \e extrapop for \b this model
|
||||
void setExtraPop(int4 ep) { extrapop = ep; } ///< Set the stack-pointer \e extrapop
|
||||
|
@ -263,6 +263,13 @@
|
||||
</element>
|
||||
</zeroOrMore>
|
||||
|
||||
<zeroOrMore>
|
||||
<element name="modelalias">
|
||||
<attribute name="name"/>
|
||||
<attribute name="parent"/>
|
||||
</element>
|
||||
</zeroOrMore>
|
||||
|
||||
<optional>
|
||||
<element name="eval_current_prototype">
|
||||
<attribute name="name"/>
|
||||
|
@ -36,6 +36,7 @@ import ghidra.program.model.pcode.AddressXML;
|
||||
import ghidra.program.model.pcode.Varnode;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.SystemUtilities;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.xml.SpecXmlUtils;
|
||||
import ghidra.xml.*;
|
||||
|
||||
@ -58,7 +59,6 @@ public class BasicCompilerSpec implements CompilerSpec {
|
||||
protected PrototypeModel evalCalledModel; // Default model used to evaluate a called function
|
||||
protected PrototypeModel[] allmodels; // All models
|
||||
protected PrototypeModel[] models; // All models excluding merge models
|
||||
private boolean copiedThisModel; // true if __thiscall is copied from default model
|
||||
private Register stackPointer; // Register holding the stack pointer
|
||||
private AddressSpace stackSpace;
|
||||
private AddressSpace stackBaseSpace;
|
||||
@ -88,9 +88,11 @@ public class BasicCompilerSpec implements CompilerSpec {
|
||||
* @throws XmlParseException for badly formed XML
|
||||
* @throws SAXException for syntax errors in the XML
|
||||
* @throws IOException for errors accessing the stream
|
||||
* @throws DuplicateNameException if there exists more than one PrototypeModel with the same name
|
||||
*/
|
||||
public BasicCompilerSpec(CompilerSpecDescription description, SleighLanguage language,
|
||||
InputStream stream) throws XmlParseException, SAXException, IOException {
|
||||
InputStream stream)
|
||||
throws XmlParseException, SAXException, IOException, DuplicateNameException {
|
||||
this.description = description;
|
||||
this.language = language;
|
||||
buildInjectLibrary();
|
||||
@ -140,7 +142,7 @@ public class BasicCompilerSpec implements CompilerSpec {
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException | SAXException | XmlParseException e) {
|
||||
catch (IOException | SAXException | XmlParseException | DuplicateNameException e) {
|
||||
parseException = e;
|
||||
}
|
||||
|
||||
@ -167,7 +169,6 @@ public class BasicCompilerSpec implements CompilerSpec {
|
||||
evalCalledModel = op2.evalCalledModel;
|
||||
defaultModel = op2.defaultModel;
|
||||
allmodels = op2.allmodels;
|
||||
copiedThisModel = op2.copiedThisModel;
|
||||
globalSet = op2.globalSet; // May need to clone if \<global> tag becomes user extendable
|
||||
joinSpace = op2.joinSpace; // AddressSpace is immutable
|
||||
models = op2.models;
|
||||
@ -219,7 +220,8 @@ public class BasicCompilerSpec implements CompilerSpec {
|
||||
return errHandler;
|
||||
}
|
||||
|
||||
private void initialize(String srcName, XmlPullParser parser) throws XmlParseException {
|
||||
private void initialize(String srcName, XmlPullParser parser)
|
||||
throws XmlParseException, DuplicateNameException {
|
||||
this.sourceName = srcName;
|
||||
spaceBases = null;
|
||||
extraRanges = null;
|
||||
@ -236,7 +238,6 @@ public class BasicCompilerSpec implements CompilerSpec {
|
||||
funcPtrAlign = 0;
|
||||
deadCodeDelay = null;
|
||||
inferPtrBounds = null;
|
||||
copiedThisModel = false;
|
||||
|
||||
restoreXml(parser);
|
||||
}
|
||||
@ -280,28 +281,6 @@ public class BasicCompilerSpec implements CompilerSpec {
|
||||
}
|
||||
}
|
||||
|
||||
private void addThisCallConventionIfMissing(List<PrototypeModel> modelList,
|
||||
String defaultName) {
|
||||
if (defaultName == null) {
|
||||
return;
|
||||
}
|
||||
boolean foundThisCall = false;
|
||||
PrototypeModel defModel = null;
|
||||
for (PrototypeModel model : modelList) {
|
||||
if (CALLING_CONVENTION_thiscall.equals(model.name)) {
|
||||
foundThisCall = true;
|
||||
}
|
||||
if (defaultName.equals(model.name)) {
|
||||
defModel = model;
|
||||
}
|
||||
}
|
||||
if (defModel != null && !foundThisCall) {
|
||||
PrototypeModel thisModel = new PrototypeModel(CALLING_CONVENTION_thiscall, defModel);
|
||||
modelList.add(thisModel);
|
||||
copiedThisModel = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyContextSettings(DefaultProgramContext programContext) {
|
||||
for (ContextSetting cs : ctxsetting) {
|
||||
@ -467,21 +446,28 @@ public class BasicCompilerSpec implements CompilerSpec {
|
||||
|
||||
/**
|
||||
* Establish cross referencing to prototype models.
|
||||
* All xrefs are regenerated from a single complete list of PrototypeModels
|
||||
* All xrefs are regenerated from a single complete list of PrototypeModels.
|
||||
* If there are PrototypeModels with duplicate names, return an example name.
|
||||
* Return null otherwise
|
||||
*
|
||||
* @param modelList is the complete list of models
|
||||
* @param defaultName is the name to use for the default model (or null)
|
||||
* @param evalCurrent is the name to use for evaluating the current function (or null)
|
||||
* @param evalCalled is the name to use for evaluating called functions (or null)
|
||||
* @return a PrototypeModel name that was duplicated or null
|
||||
*/
|
||||
protected void modelXrefs(List<PrototypeModel> modelList, String defaultName,
|
||||
protected String modelXrefs(List<PrototypeModel> modelList, String defaultName,
|
||||
String evalCurrent, String evalCalled) {
|
||||
String foundDuplicate = null;
|
||||
buildModelArrays(modelList);
|
||||
callingConventionMap = new HashMap<>();
|
||||
for (PrototypeModel model : models) {
|
||||
String name = model.getName();
|
||||
if (name != null) {
|
||||
callingConventionMap.put(name, model);
|
||||
PrototypeModel previous = callingConventionMap.put(name, model);
|
||||
if (previous != null) {
|
||||
foundDuplicate = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -500,6 +486,7 @@ public class BasicCompilerSpec implements CompilerSpec {
|
||||
evalCalledModel = evalmodel;
|
||||
}
|
||||
}
|
||||
return foundDuplicate;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -538,10 +525,6 @@ public class BasicCompilerSpec implements CompilerSpec {
|
||||
if (model == defaultModel) {
|
||||
continue; // Already emitted
|
||||
}
|
||||
if (copiedThisModel && model.hasThisPointer() &&
|
||||
model.name.equals(CALLING_CONVENTION_thiscall)) {
|
||||
continue; // Don't need to emit the copy
|
||||
}
|
||||
model.saveXml(buffer, pcodeInject);
|
||||
}
|
||||
if (evalCurrentModel != null && evalCurrentModel != defaultModel) {
|
||||
@ -571,10 +554,12 @@ public class BasicCompilerSpec implements CompilerSpec {
|
||||
* Initialize this object from an XML stream. A single \<compiler_spec> tag is expected.
|
||||
* @param parser is the XML stream
|
||||
* @throws XmlParseException for badly formed XML
|
||||
* @throws DuplicateNameException if we parse more than one PrototypeModel with the same name
|
||||
*/
|
||||
private void restoreXml(XmlPullParser parser) throws XmlParseException {
|
||||
private void restoreXml(XmlPullParser parser) throws XmlParseException, DuplicateNameException {
|
||||
List<PrototypeModel> modelList = new ArrayList<>();
|
||||
boolean seenDefault = false;
|
||||
boolean seenThisCall = false;
|
||||
String defaultName = null;
|
||||
String evalCurrentPrototype = null;
|
||||
String evalCalledPrototype = null;
|
||||
@ -617,12 +602,28 @@ public class BasicCompilerSpec implements CompilerSpec {
|
||||
defaultName = model.name;
|
||||
seenDefault = true;
|
||||
}
|
||||
if (model.getName().equals(CALLING_CONVENTION_thiscall)) {
|
||||
seenThisCall = true;
|
||||
}
|
||||
}
|
||||
else if (name.equals("prototype")) {
|
||||
PrototypeModel model = addPrototypeModel(modelList, parser);
|
||||
if (defaultName == null) {
|
||||
defaultName = model.name;
|
||||
}
|
||||
if (model.getName().equals(CALLING_CONVENTION_thiscall)) {
|
||||
seenThisCall = true;
|
||||
}
|
||||
}
|
||||
else if (name.equals("modelalias")) {
|
||||
XmlElement el = parser.start();
|
||||
String aliasName = el.getAttribute("name");
|
||||
String parentName = el.getAttribute("parent");
|
||||
parser.end(el);
|
||||
createModelAlias(aliasName, parentName, modelList);
|
||||
if (aliasName.equals(CALLING_CONVENTION_thiscall)) {
|
||||
seenThisCall = true;
|
||||
}
|
||||
}
|
||||
else if (name.equals("resolveprototype")) {
|
||||
addPrototypeModel(modelList, parser);
|
||||
@ -683,8 +684,14 @@ public class BasicCompilerSpec implements CompilerSpec {
|
||||
language.getDefaultSpace().getSize(),
|
||||
language.getDefaultSpace().getAddressableUnitSize(), AddressSpace.TYPE_STACK, 0);
|
||||
}
|
||||
addThisCallConventionIfMissing(modelList, defaultName);
|
||||
modelXrefs(modelList, defaultName, evalCurrentPrototype, evalCalledPrototype);
|
||||
if (!seenThisCall) {
|
||||
createModelAlias(CALLING_CONVENTION_thiscall, defaultName, modelList);
|
||||
}
|
||||
String dupName =
|
||||
modelXrefs(modelList, defaultName, evalCurrentPrototype, evalCalledPrototype);
|
||||
if (dupName != null) {
|
||||
throw new DuplicateNameException("Multiple prototype models with the name: " + dupName);
|
||||
}
|
||||
}
|
||||
|
||||
private void saveProperties(StringBuilder buffer) {
|
||||
@ -995,6 +1002,35 @@ public class BasicCompilerSpec implements CompilerSpec {
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* Clone the named PrototypeModel, attaching it to another name.
|
||||
* @param aliasName is the new name
|
||||
* @param parentName is the name of the PrototypeModel to clone
|
||||
* @param modelList is the container
|
||||
* @throws XmlParseException if the parent model cannot be established
|
||||
*/
|
||||
private void createModelAlias(String aliasName, String parentName,
|
||||
List<PrototypeModel> modelList) throws XmlParseException {
|
||||
PrototypeModel parentModel = null;
|
||||
for (PrototypeModel model : modelList) {
|
||||
if (parentName.equals(model.getName())) {
|
||||
parentModel = model;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (parentModel == null) {
|
||||
throw new XmlParseException("Parent for model alias does not exist: " + parentName);
|
||||
}
|
||||
if (parentModel.isMerged()) {
|
||||
throw new XmlParseException("Cannot make alias of merged model: " + parentName);
|
||||
}
|
||||
if (parentModel.getAliasParent() != null) {
|
||||
throw new XmlParseException("Cannot make alias of an alias: " + parentName);
|
||||
}
|
||||
PrototypeModel newModel = new PrototypeModel(aliasName, parentModel);
|
||||
modelList.add(newModel);
|
||||
}
|
||||
|
||||
private PrototypeModel addPrototypeModel(List<PrototypeModel> modelList, XmlPullParser parser)
|
||||
throws XmlParseException {
|
||||
PrototypeModel model;
|
||||
@ -1116,7 +1152,7 @@ public class BasicCompilerSpec implements CompilerSpec {
|
||||
return false;
|
||||
}
|
||||
BasicCompilerSpec other = (BasicCompilerSpec) obj;
|
||||
if (aggressiveTrim != other.aggressiveTrim || copiedThisModel != other.copiedThisModel) {
|
||||
if (aggressiveTrim != other.aggressiveTrim) {
|
||||
return false;
|
||||
}
|
||||
if (!dataOrganization.isEquivalent(other.dataOrganization)) {
|
||||
|
@ -17,6 +17,7 @@ package ghidra.program.model.lang;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import ghidra.program.database.SpecExtension;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
@ -31,9 +32,6 @@ import ghidra.xml.*;
|
||||
* A function calling convention model.
|
||||
* Formal specification of how a compiler passes
|
||||
* arguments between functions.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class PrototypeModel {
|
||||
public static final int UNKNOWN_EXTRAPOP = 0x8000;
|
||||
@ -50,6 +48,7 @@ public class PrototypeModel {
|
||||
private Varnode[] killedbycall; // Memory ranges definitely affected by calls
|
||||
private Varnode[] returnaddress; // Memory used to store the return address
|
||||
private Varnode[] likelytrash; // Memory likely to be meaningless on input
|
||||
private PrototypeModel compatModel; // The model this is an alias of
|
||||
private AddressSet localRange; // Range on the stack considered for local storage
|
||||
private AddressSet paramRange; // Range on the stack considered for parameter storage
|
||||
private InputListType inputListType = InputListType.STANDARD;
|
||||
@ -59,6 +58,16 @@ public class PrototypeModel {
|
||||
private boolean hasUponEntry; // Does this have an uponentry injection
|
||||
private boolean hasUponReturn; // Does this have an uponreturn injection
|
||||
|
||||
/**
|
||||
* Create a named alias of another PrototypeModel.
|
||||
* All elements of the original model are copied except:
|
||||
* 1) The name
|
||||
* 2) The generic calling convention (which is based on name)
|
||||
* 3) The hasThis property (which allows __thiscall to alias something else)
|
||||
* 4) The "fact of" the model being an alias
|
||||
* @param name is the name of the alias
|
||||
* @param model is the other PrototypeModel
|
||||
*/
|
||||
public PrototypeModel(String name, PrototypeModel model) {
|
||||
this.name = name;
|
||||
isExtension = false;
|
||||
@ -71,6 +80,7 @@ public class PrototypeModel {
|
||||
killedbycall = model.killedbycall;
|
||||
returnaddress = model.returnaddress;
|
||||
likelytrash = model.likelytrash;
|
||||
compatModel = model;
|
||||
localRange = new AddressSet(model.localRange);
|
||||
paramRange = new AddressSet(model.paramRange);
|
||||
hasThis = model.hasThis || name.equals(CompilerSpec.CALLING_CONVENTION_thiscall);
|
||||
@ -91,6 +101,7 @@ public class PrototypeModel {
|
||||
killedbycall = null;
|
||||
returnaddress = null;
|
||||
likelytrash = null;
|
||||
compatModel = null;
|
||||
localRange = null;
|
||||
paramRange = null;
|
||||
genericCallingConvention = GenericCallingConvention.unknown;
|
||||
@ -100,6 +111,10 @@ public class PrototypeModel {
|
||||
hasUponReturn = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the generic calling convention enum associated with this
|
||||
* @return the enum
|
||||
*/
|
||||
public GenericCallingConvention getGenericCallingConvention() {
|
||||
return genericCallingConvention;
|
||||
}
|
||||
@ -144,6 +159,12 @@ public class PrototypeModel {
|
||||
return returnaddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this returns true, it indicates this model is an artificial merge of other models.
|
||||
* A merged model can be used as part of the analysis process when attempting to distinguish
|
||||
* between different possible models for an unknown function.
|
||||
* @return true if this model is an artificial merge of other models
|
||||
*/
|
||||
public boolean isMerged() {
|
||||
return false;
|
||||
}
|
||||
@ -155,30 +176,58 @@ public class PrototypeModel {
|
||||
return isExtension;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the formal name of the model
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of extra bytes popped from the stack when a function that uses
|
||||
* this model returns to its caller. This is usually just the number of bytes used to
|
||||
* store the return value, but some conventions may do additional clean up of stack parameters.
|
||||
* A special value of UNKNOWN_EXTRAPOP indicates that the number of bytes is unknown.
|
||||
* @return the number of extra bytes popped
|
||||
*/
|
||||
public int getExtrapop() {
|
||||
return extrapop;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the number of bytes on the stack used, by this model, to store the return value
|
||||
*/
|
||||
public int getStackshift() {
|
||||
return stackshift;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if this model has an implied "this" parameter for referencing class data
|
||||
*/
|
||||
public boolean hasThisPointer() {
|
||||
return hasThis;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if this model is used specifically for class constructors
|
||||
*/
|
||||
public boolean isConstructor() {
|
||||
return isConstruct;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the allocation strategy for this model
|
||||
*/
|
||||
public InputListType getInputListType() {
|
||||
return inputListType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this model has specific p-code injections associated with it
|
||||
* (either an "uponentry" or "uponreturn" payload),
|
||||
* which are used to decompile functions with this model.
|
||||
* @return true if this model uses p-code injections
|
||||
*/
|
||||
public boolean hasInjection() {
|
||||
return hasUponEntry || hasUponReturn;
|
||||
}
|
||||
@ -334,6 +383,14 @@ public class PrototypeModel {
|
||||
return finalres;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this is an alias of another model, return that model. Otherwise null is returned.
|
||||
* @return the parent model or null
|
||||
*/
|
||||
public PrototypeModel getAliasParent() {
|
||||
return compatModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* If a PrototypeModel fails to parse (from XML) a substitute model may be provided, in which
|
||||
* case this method returns true. In all other cases this method returns false;
|
||||
@ -359,7 +416,19 @@ public class PrototypeModel {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marshal this object as XML to an output buffer
|
||||
* @param buffer is the output buffer
|
||||
* @param injectLibrary is a library containing any inject payloads associated with the model
|
||||
*/
|
||||
public void saveXml(StringBuilder buffer, PcodeInjectLibrary injectLibrary) {
|
||||
if (compatModel != null) {
|
||||
buffer.append("<modelalias");
|
||||
SpecXmlUtils.encodeStringAttribute(buffer, "name", name);
|
||||
SpecXmlUtils.encodeStringAttribute(buffer, "parent", compatModel.name);
|
||||
buffer.append("/>\n");
|
||||
return;
|
||||
}
|
||||
buffer.append("<prototype");
|
||||
SpecXmlUtils.encodeStringAttribute(buffer, "name", name);
|
||||
if (extrapop != PrototypeModel.UNKNOWN_EXTRAPOP) {
|
||||
@ -516,11 +585,20 @@ public class PrototypeModel {
|
||||
return name + "@@inject_uponreturn";
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the model from an XML stream.
|
||||
* @param parser is the XML parser (initialized to the start of the stream)
|
||||
* @param cspec is the parent compiler specification owning the model
|
||||
* @throws XmlParseException is there are problems parsing the XML
|
||||
*/
|
||||
public void restoreXml(XmlPullParser parser, CompilerSpec cspec) throws XmlParseException {
|
||||
inputParams = null;
|
||||
outputParams = null;
|
||||
XmlElement protoElement = parser.start();
|
||||
name = protoElement.getAttribute("name");
|
||||
if (!SpecExtension.isValidFormalName(name)) {
|
||||
throw new XmlParseException("Prototype name uses illegal characters");
|
||||
}
|
||||
extrapop = PrototypeModel.UNKNOWN_EXTRAPOP;
|
||||
String extpopStr = protoElement.getAttribute("extrapop");
|
||||
if (!extpopStr.equals("unknown")) {
|
||||
@ -597,22 +675,57 @@ public class PrototypeModel {
|
||||
parser.end(protoElement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given address range is possible input parameter storage for this model.
|
||||
* If it is, "true" is returned, and additional information about the parameter's
|
||||
* position is passed back in the provided record.
|
||||
* @param loc is the starting address of the range
|
||||
* @param size is the size of the range in bytes
|
||||
* @param res is the pass-back record
|
||||
* @return true if the range is a possible parameter
|
||||
*/
|
||||
public boolean possibleInputParamWithSlot(Address loc, int size, ParamList.WithSlotRec res) {
|
||||
return inputParams.possibleParamWithSlot(loc, size, res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given address range is possible return value storage for this model.
|
||||
* If it is, "true" is returned, and additional information about the storage
|
||||
* position is passed back in the provided record.
|
||||
* @param loc is the starting address of the range
|
||||
* @param size is the size of the range in bytes
|
||||
* @param res is the pass-back record
|
||||
* @return true if the range is possible return value storage
|
||||
*/
|
||||
public boolean possibleOutputParamWithSlot(Address loc, int size, ParamList.WithSlotRec res) {
|
||||
return outputParams.possibleParamWithSlot(loc, size, res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assuming the model allows open ended storage of parameters on the stack,
|
||||
* return the byte alignment required for individual stack parameters.
|
||||
* @return the stack alignment in bytes
|
||||
*/
|
||||
public int getStackParameterAlignment() {
|
||||
return inputParams.getStackParameterAlignment();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the byte offset where the first input parameter on the stack is allocated.
|
||||
* The value is relative to the incoming stack pointer of the called function.
|
||||
* For normal stacks, this is the offset of the first byte in the first parameter.
|
||||
* For reverse stacks, this is the offset immediately after the last byte of the parameter.
|
||||
* @return the byte offset of the first param
|
||||
*/
|
||||
public Long getStackParameterOffset() {
|
||||
return inputParams.getStackParameterOffset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all input storage locations consisting of a single register
|
||||
* @param prog is the current Program
|
||||
* @return a VariableStorage ojbect for each register
|
||||
*/
|
||||
public VariableStorage[] getPotentialInputRegisterStorage(Program prog) {
|
||||
return inputParams.getPotentialRegisterStorage(prog);
|
||||
}
|
||||
@ -659,6 +772,11 @@ public class PrototypeModel {
|
||||
if (!SystemUtilities.isArrayEqual(likelytrash, obj.likelytrash)) {
|
||||
return false;
|
||||
}
|
||||
String compatName = (compatModel != null) ? compatModel.getName() : "";
|
||||
String compatNameOp2 = (obj.compatModel != null) ? obj.compatModel.getName() : "";
|
||||
if (!compatName.equals(compatNameOp2)) {
|
||||
return false;
|
||||
}
|
||||
if (!SystemUtilities.isEqual(localRange, obj.localRange)) {
|
||||
return false;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user