mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
GP-2793 Better support for metatype="ptr" pentry tags
This commit is contained in:
parent
ba0b42dc82
commit
52d97329b9
5 changed files with 762 additions and 58 deletions
|
@ -553,7 +553,7 @@ ParamListStandard::ParamListStandard(const ParamListStandard &op2)
|
||||||
maxdelay = op2.maxdelay;
|
maxdelay = op2.maxdelay;
|
||||||
pointermax = op2.pointermax;
|
pointermax = op2.pointermax;
|
||||||
thisbeforeret = op2.thisbeforeret;
|
thisbeforeret = op2.thisbeforeret;
|
||||||
resourceTwoStart = op2.resourceTwoStart;
|
resourceStart = op2.resourceStart;
|
||||||
populateResolver();
|
populateResolver();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -686,13 +686,14 @@ void ParamListStandard::assignMap(const vector<Datatype *> &proto,TypeFactory &t
|
||||||
res.back().type = pointertp;
|
res.back().type = pointertp;
|
||||||
res.back().flags = ParameterPieces::indirectstorage;
|
res.back().flags = ParameterPieces::indirectstorage;
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
res.back().addr = assignAddress(proto[i],status);
|
res.back().addr = assignAddress(proto[i],status);
|
||||||
if (res.back().addr.isInvalid())
|
|
||||||
throw ParamUnassignedError("Cannot assign parameter address for " + proto[i]->getName());
|
|
||||||
res.back().type = proto[i];
|
res.back().type = proto[i];
|
||||||
res.back().flags = 0;
|
res.back().flags = 0;
|
||||||
}
|
}
|
||||||
|
if (res.back().addr.isInvalid())
|
||||||
|
throw ParamUnassignedError("Cannot assign parameter address for " + proto[i]->getName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// From among the ParamEntrys matching the given \e group, return the one that best matches
|
/// From among the ParamEntrys matching the given \e group, return the one that best matches
|
||||||
|
@ -818,39 +819,33 @@ void ParamListStandard::buildTrialMap(ParamActive *active) const
|
||||||
active->sortTrials();
|
active->sortTrials();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Calculate the range of trials in each of the two resource sections
|
/// \brief Calculate the range of trials in each resource sections
|
||||||
///
|
///
|
||||||
/// The trials must already be mapped, which should put them in group order. The sections
|
/// The trials must already be mapped, which should put them in group order. The sections
|
||||||
/// split at the group given by \b resourceTwoStart. We pass back the range of trial indices
|
/// split at the groups given by \b resourceStart. We pass back the starting index for
|
||||||
/// for each section. If \b resourceTwoStart is 0, then there is really only one section, and
|
/// each range of trials.
|
||||||
/// the empty range [0,0] is passed back for the second section.
|
|
||||||
/// \param active is the given set of parameter trials
|
/// \param active is the given set of parameter trials
|
||||||
/// \param oneStart will pass back the index of the first trial in the first section
|
/// \param trialStart will hold the starting index for each range of trials
|
||||||
/// \param oneStop will pass back the index (+1) of the last trial in the first section
|
void ParamListStandard::separateSections(ParamActive *active,vector<int4> &trialStart) const
|
||||||
/// \param twoStart will pass back the index of the first trial in the second section
|
|
||||||
/// \param twoStop will pass back the index (+1) of the last trial in the second section
|
|
||||||
void ParamListStandard::separateSections(ParamActive *active,int4 &oneStart,int4 &oneStop,int4 &twoStart,int4 &twoStop) const
|
|
||||||
|
|
||||||
{
|
{
|
||||||
int4 numtrials = active->getNumTrials();
|
int4 numtrials = active->getNumTrials();
|
||||||
if (resourceTwoStart == 0) {
|
int4 currentTrial = 0;
|
||||||
// Only one section
|
int4 nextGroup = resourceStart[1];
|
||||||
oneStart = 0;
|
int4 nextSection = 2;
|
||||||
oneStop = numtrials;
|
trialStart.push_back(currentTrial);
|
||||||
twoStart = 0;
|
for(;currentTrial<numtrials;++currentTrial) {
|
||||||
twoStop = 0;
|
ParamTrial &curtrial(active->getTrial(currentTrial));
|
||||||
return;
|
|
||||||
}
|
|
||||||
int4 i=0;
|
|
||||||
for(;i<numtrials;++i) {
|
|
||||||
ParamTrial &curtrial(active->getTrial(i));
|
|
||||||
if (curtrial.getEntry()==(const ParamEntry *)0) continue;
|
if (curtrial.getEntry()==(const ParamEntry *)0) continue;
|
||||||
if (curtrial.getEntry()->getGroup() >= resourceTwoStart) break;
|
if (curtrial.getEntry()->getGroup() >= nextGroup) {
|
||||||
|
if (nextSection > resourceStart.size())
|
||||||
|
throw LowlevelError("Missing next resource start");
|
||||||
|
nextGroup = resourceStart[nextSection];
|
||||||
|
nextSection += 1;
|
||||||
|
trialStart.push_back(currentTrial);
|
||||||
}
|
}
|
||||||
oneStart = 0;
|
}
|
||||||
oneStop = i;
|
trialStart.push_back(numtrials);
|
||||||
twoStart = i;
|
|
||||||
twoStop = numtrials;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Mark all the trials within the indicated groups as \e not \e used, except for one specified index
|
/// \brief Mark all the trials within the indicated groups as \e not \e used, except for one specified index
|
||||||
|
@ -1116,15 +1111,19 @@ void ParamListStandard::populateResolver(void)
|
||||||
void ParamListStandard::parsePentry(Decoder &decoder,vector<EffectRecord> &effectlist,
|
void ParamListStandard::parsePentry(Decoder &decoder,vector<EffectRecord> &effectlist,
|
||||||
int4 groupid,bool normalstack,bool autokill,bool splitFloat,bool grouped)
|
int4 groupid,bool normalstack,bool autokill,bool splitFloat,bool grouped)
|
||||||
{
|
{
|
||||||
|
type_metatype lastMeta = TYPE_UNION;
|
||||||
|
if (!entry.empty()) {
|
||||||
|
lastMeta = entry.back().isGrouped() ? TYPE_UNKNOWN : entry.back().getType();
|
||||||
|
}
|
||||||
entry.emplace_back(groupid);
|
entry.emplace_back(groupid);
|
||||||
entry.back().decode(decoder,normalstack,grouped,entry);
|
entry.back().decode(decoder,normalstack,grouped,entry);
|
||||||
if (splitFloat) {
|
if (splitFloat) {
|
||||||
if (!grouped && entry.back().getType() == TYPE_FLOAT) {
|
type_metatype currentMeta = grouped ? TYPE_UNKNOWN : entry.back().getType();
|
||||||
if (resourceTwoStart >= 0)
|
if (lastMeta != currentMeta) {
|
||||||
throw LowlevelError("parameter list floating-point entries must come first");
|
if (lastMeta > currentMeta)
|
||||||
|
throw LowlevelError("parameter list entries must be ordered by metatype");
|
||||||
|
resourceStart.push_back(groupid);
|
||||||
}
|
}
|
||||||
else if (resourceTwoStart < 0)
|
|
||||||
resourceTwoStart = groupid; // First time we have seen an integer slot
|
|
||||||
}
|
}
|
||||||
AddrSpace *spc = entry.back().getSpace();
|
AddrSpace *spc = entry.back().getSpace();
|
||||||
if (spc->getType() == IPTR_SPACEBASE)
|
if (spc->getType() == IPTR_SPACEBASE)
|
||||||
|
@ -1173,16 +1172,23 @@ void ParamListStandard::fillinMap(ParamActive *active) const
|
||||||
|
|
||||||
{
|
{
|
||||||
if (active->getNumTrials() == 0) return; // No trials to check
|
if (active->getNumTrials() == 0) return; // No trials to check
|
||||||
|
if (entry.empty())
|
||||||
|
throw LowlevelError("Cannot derive parameter storage for prototype model without parameter entries");
|
||||||
|
|
||||||
buildTrialMap(active); // Associate varnodes with sorted list of parameter locations
|
buildTrialMap(active); // Associate varnodes with sorted list of parameter locations
|
||||||
|
|
||||||
forceExclusionGroup(active);
|
forceExclusionGroup(active);
|
||||||
int4 oneStart,oneStop,twoStart,twoStop;
|
vector<int4> trialStart;
|
||||||
separateSections(active,oneStart,oneStop,twoStart,twoStop);
|
separateSections(active,trialStart);
|
||||||
forceNoUse(active,oneStart,oneStop);
|
int4 numSection = trialStart.size() - 1;
|
||||||
forceNoUse(active,twoStart,twoStop); // Definitely not used -- overrides active
|
for(int4 i=0;i<numSection;++i) {
|
||||||
forceInactiveChain(active,2,oneStart,oneStop,0); // Chains of inactivity override later actives
|
// Definitely not used -- overrides active
|
||||||
forceInactiveChain(active,2,twoStart,twoStop,resourceTwoStart);
|
forceNoUse(active,trialStart[i],trialStart[i+1]);
|
||||||
|
}
|
||||||
|
for(int4 i=0;i<numSection;++i) {
|
||||||
|
// Chains of inactivity override later actives
|
||||||
|
forceInactiveChain(active,2,trialStart[i],trialStart[i+1],resourceStart[i]);
|
||||||
|
}
|
||||||
|
|
||||||
// Mark every active trial as used
|
// Mark every active trial as used
|
||||||
for(int4 i=0;i<active->getNumTrials();++i) {
|
for(int4 i=0;i<active->getNumTrials();++i) {
|
||||||
|
@ -1354,7 +1360,6 @@ void ParamListStandard::decode(Decoder &decoder,vector<EffectRecord> &effectlist
|
||||||
splitFloat = decoder.readBool();
|
splitFloat = decoder.readBool();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resourceTwoStart = splitFloat ? -1 : 0;
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
uint4 subId = decoder.peekElement();
|
uint4 subId = decoder.peekElement();
|
||||||
if (subId == 0) break;
|
if (subId == 0) break;
|
||||||
|
@ -1366,6 +1371,7 @@ void ParamListStandard::decode(Decoder &decoder,vector<EffectRecord> &effectlist
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
decoder.closeElement(elemId);
|
decoder.closeElement(elemId);
|
||||||
|
resourceStart.push_back(numgroup);
|
||||||
calcDelay();
|
calcDelay();
|
||||||
populateResolver();
|
populateResolver();
|
||||||
}
|
}
|
||||||
|
|
|
@ -284,7 +284,7 @@ class ParamActive {
|
||||||
bool needsfinalcheck; ///< Should a final pass be made on trials (to take into account control-flow changes)
|
bool needsfinalcheck; ///< Should a final pass be made on trials (to take into account control-flow changes)
|
||||||
bool recoversubcall; ///< True if \b this is being used to recover prototypes of a sub-function call
|
bool recoversubcall; ///< True if \b this is being used to recover prototypes of a sub-function call
|
||||||
public:
|
public:
|
||||||
ParamActive(bool recoversub); ///< Constructor an empty container
|
ParamActive(bool recoversub); ///< Construct an empty container
|
||||||
void clear(void); ///< Reset to an empty container
|
void clear(void); ///< Reset to an empty container
|
||||||
void registerTrial(const Address &addr,int4 sz); ///< Add a new trial to the container
|
void registerTrial(const Address &addr,int4 sz); ///< Add a new trial to the container
|
||||||
int4 getNumTrials(void) const { return trial.size(); } ///< Get the number of trials in \b this container
|
int4 getNumTrials(void) const { return trial.size(); } ///< Get the number of trials in \b this container
|
||||||
|
@ -558,7 +558,7 @@ protected:
|
||||||
int4 maxdelay; ///< Maximum heritage delay across all parameters
|
int4 maxdelay; ///< Maximum heritage delay across all parameters
|
||||||
int4 pointermax; ///< If non-zero, maximum size of a data-type before converting to a pointer
|
int4 pointermax; ///< If non-zero, maximum size of a data-type before converting to a pointer
|
||||||
bool thisbeforeret; ///< Does a \b this parameter come before a hidden return parameter
|
bool thisbeforeret; ///< Does a \b this parameter come before a hidden return parameter
|
||||||
int4 resourceTwoStart; ///< If there are two resource sections, the group of the first entry in the second section
|
vector<int4> resourceStart; ///< The starting group for each resource section
|
||||||
list<ParamEntry> entry; ///< The ordered list of parameter entries
|
list<ParamEntry> entry; ///< The ordered list of parameter entries
|
||||||
vector<ParamEntryResolver *> resolverMap; ///< Map from space id to resolver
|
vector<ParamEntryResolver *> resolverMap; ///< Map from space id to resolver
|
||||||
AddrSpace *spacebase; ///< Address space containing relative offset parameters
|
AddrSpace *spacebase; ///< Address space containing relative offset parameters
|
||||||
|
@ -566,7 +566,7 @@ protected:
|
||||||
Address assignAddress(const Datatype *tp,vector<int4> &status) const; ///< Assign storage for given parameter data-type
|
Address assignAddress(const Datatype *tp,vector<int4> &status) const; ///< Assign storage for given parameter data-type
|
||||||
const ParamEntry *selectUnreferenceEntry(int4 grp,type_metatype prefType) const; ///< Select entry to fill an unreferenced param
|
const ParamEntry *selectUnreferenceEntry(int4 grp,type_metatype prefType) const; ///< Select entry to fill an unreferenced param
|
||||||
void buildTrialMap(ParamActive *active) const; ///< Build map from parameter trials to model ParamEntrys
|
void buildTrialMap(ParamActive *active) const; ///< Build map from parameter trials to model ParamEntrys
|
||||||
void separateSections(ParamActive *active,int4 &oneStart,int4 &oneStop,int4 &twoStart,int4 &twoStop) const;
|
void separateSections(ParamActive *active,vector<int4> &trialStart) const;
|
||||||
static void markGroupNoUse(ParamActive *active,int4 groupUpper,int4 groupStart,int4 index);
|
static void markGroupNoUse(ParamActive *active,int4 groupUpper,int4 groupStart,int4 index);
|
||||||
static void markBestInactive(ParamActive *active,int4 group,int4 groupStart,type_metatype prefType);
|
static void markBestInactive(ParamActive *active,int4 group,int4 groupStart,type_metatype prefType);
|
||||||
static void forceExclusionGroup(ParamActive *active);
|
static void forceExclusionGroup(ParamActive *active);
|
||||||
|
|
|
@ -0,0 +1,686 @@
|
||||||
|
/* ###
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#include "architecture.hh"
|
||||||
|
#include "grammar.hh"
|
||||||
|
#include "test.hh"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
class FuncProtoTestEnvironment {
|
||||||
|
Architecture *g;
|
||||||
|
ProtoModel *mod1;
|
||||||
|
public:
|
||||||
|
FuncProtoTestEnvironment(void);
|
||||||
|
~FuncProtoTestEnvironment(void);
|
||||||
|
static void build(void);
|
||||||
|
static void registerModel1(ostream &s);
|
||||||
|
static void registerModel2(ostream &s);
|
||||||
|
static void registerModel3(ostream &s);
|
||||||
|
};
|
||||||
|
|
||||||
|
static FuncProtoTestEnvironment theEnviron;
|
||||||
|
|
||||||
|
static Architecture *glb;
|
||||||
|
|
||||||
|
FuncProtoTestEnvironment::FuncProtoTestEnvironment(void)
|
||||||
|
|
||||||
|
{
|
||||||
|
g = (Architecture *)0;
|
||||||
|
mod1 = (ProtoModel *)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FuncProtoTestEnvironment::build(void)
|
||||||
|
|
||||||
|
{
|
||||||
|
if (theEnviron.g != (Architecture *)0) return;
|
||||||
|
ArchitectureCapability *xmlCapability = ArchitectureCapability::getCapability("xml");
|
||||||
|
istringstream s(
|
||||||
|
"<binaryimage arch=\"Toy:LE:32:default:default\"></binaryimage>"
|
||||||
|
);
|
||||||
|
DocumentStorage store;
|
||||||
|
Document *doc = store.parseDocument(s);
|
||||||
|
store.registerTag(doc->getRoot());
|
||||||
|
|
||||||
|
ostringstream s2;
|
||||||
|
s2 << "<specextensions> ";
|
||||||
|
registerModel1(s2);
|
||||||
|
registerModel2(s2);
|
||||||
|
registerModel3(s2);
|
||||||
|
s2 << "</specextensions>\n";
|
||||||
|
istringstream s3(s2.str());
|
||||||
|
doc = store.parseDocument(s3);
|
||||||
|
store.registerTag(doc->getRoot());
|
||||||
|
theEnviron.g = xmlCapability->buildArchitecture("", "", &cout);
|
||||||
|
theEnviron.g->init(store);
|
||||||
|
|
||||||
|
glb = theEnviron.g;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FuncProtoTestEnvironment::registerModel1(ostream &s)
|
||||||
|
|
||||||
|
{
|
||||||
|
const char *text =
|
||||||
|
"<prototype name=\"__model1\" extrapop=\"unknown\" stackshift=\"4\">"
|
||||||
|
"<input pointermax=\"4\">"
|
||||||
|
"<pentry minsize=\"1\" maxsize=\"4\">"
|
||||||
|
"<register name=\"r12\"/>"
|
||||||
|
"</pentry>"
|
||||||
|
"<pentry minsize=\"1\" maxsize=\"4\">"
|
||||||
|
"<register name=\"r11\"/>"
|
||||||
|
"</pentry>"
|
||||||
|
"<pentry minsize=\"1\" maxsize=\"4\">"
|
||||||
|
"<register name=\"r10\"/>"
|
||||||
|
"</pentry>"
|
||||||
|
"<pentry minsize=\"1\" maxsize=\"4\">"
|
||||||
|
"<register name=\"r9\"/>"
|
||||||
|
"</pentry>"
|
||||||
|
"<pentry minsize=\"1\" maxsize=\"4\">"
|
||||||
|
"<register name=\"r8\"/>"
|
||||||
|
"</pentry>"
|
||||||
|
"<pentry minsize=\"1\" maxsize=\"500\" align=\"4\">"
|
||||||
|
"<addr offset=\"0\" space=\"stack\"/>"
|
||||||
|
"</pentry>"
|
||||||
|
"</input>"
|
||||||
|
"<output>"
|
||||||
|
"<pentry minsize=\"1\" maxsize=\"4\">"
|
||||||
|
"<register name=\"r12\"/>"
|
||||||
|
"</pentry>"
|
||||||
|
"</output>"
|
||||||
|
"</prototype>";
|
||||||
|
s << text << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FuncProtoTestEnvironment::registerModel2(ostream &s)
|
||||||
|
|
||||||
|
{
|
||||||
|
const char *text =
|
||||||
|
"<prototype name=\"__model2\" extrapop=\"unknown\" stackshift=\"4\">"
|
||||||
|
"<input>"
|
||||||
|
"<pentry minsize=\"1\" maxsize=\"4\" metatype=\"ptr\"><register name=\"r1\"/>"
|
||||||
|
"</pentry>"
|
||||||
|
"<pentry minsize=\"1\" maxsize=\"4\" metatype=\"ptr\"><register name=\"r2\"/>"
|
||||||
|
"</pentry>"
|
||||||
|
"<pentry minsize=\"1\" maxsize=\"4\" metatype=\"float\" extension=\"float\"><register name=\"r3\"/>"
|
||||||
|
"</pentry>"
|
||||||
|
"<pentry minsize=\"1\" maxsize=\"4\" metatype=\"float\" extension=\"float\"><register name=\"r4\"/>"
|
||||||
|
"</pentry>"
|
||||||
|
"<pentry minsize=\"1\" maxsize=\"4\" metatype=\"float\" extension=\"float\"><register name=\"r5\"/>"
|
||||||
|
"</pentry>"
|
||||||
|
"<pentry minsize=\"1\" maxsize=\"4\">"
|
||||||
|
"<register name=\"r10\"/>"
|
||||||
|
"</pentry>"
|
||||||
|
"<pentry minsize=\"1\" maxsize=\"4\">"
|
||||||
|
"<register name=\"r9\"/>"
|
||||||
|
"</pentry>"
|
||||||
|
"<pentry minsize=\"1\" maxsize=\"4\">"
|
||||||
|
"<register name=\"r8\"/>"
|
||||||
|
"</pentry>"
|
||||||
|
"<pentry minsize=\"5\" maxsize=\"8\">"
|
||||||
|
"<addr space=\"join\" piece1=\"r10\" piece2=\"r9\"/>"
|
||||||
|
"</pentry>"
|
||||||
|
"<pentry minsize=\"1\" maxsize=\"500\" align=\"4\">"
|
||||||
|
"<addr offset=\"0\" space=\"stack\"/>"
|
||||||
|
"</pentry>"
|
||||||
|
"</input>"
|
||||||
|
"<output>"
|
||||||
|
"<pentry minsize=\"1\" maxsize=\"4\">"
|
||||||
|
"<register name=\"r12\"/>"
|
||||||
|
"</pentry>"
|
||||||
|
"</output>"
|
||||||
|
"</prototype>";
|
||||||
|
s << text << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FuncProtoTestEnvironment::registerModel3(ostream &s)
|
||||||
|
|
||||||
|
{
|
||||||
|
const char *text =
|
||||||
|
"<prototype name=\"__model3\" extrapop=\"unknown\" stackshift=\"4\">"
|
||||||
|
"<input>"
|
||||||
|
"<group>"
|
||||||
|
"<pentry minsize=\"1\" maxsize=\"4\" metatype=\"float\" extension=\"float\"><register name=\"r3\"/>"
|
||||||
|
"</pentry>"
|
||||||
|
"<pentry minsize=\"1\" maxsize=\"4\"> "
|
||||||
|
"<register name=\"r10\"/> "
|
||||||
|
"</pentry> "
|
||||||
|
"</group> "
|
||||||
|
"<group>"
|
||||||
|
"<pentry minsize=\"1\" maxsize=\"4\" metatype=\"float\" extension=\"float\"><register name=\"r4\"/>"
|
||||||
|
"</pentry>"
|
||||||
|
"<pentry minsize=\"1\" maxsize=\"4\"> "
|
||||||
|
"<register name=\"r9\"/> "
|
||||||
|
"</pentry> "
|
||||||
|
"</group>"
|
||||||
|
"<group>"
|
||||||
|
"<pentry minsize=\"1\" maxsize=\"4\" metatype=\"float\" extension=\"float\"><register name=\"r5\"/>"
|
||||||
|
"</pentry>"
|
||||||
|
"<pentry minsize=\"1\" maxsize=\"4\"> "
|
||||||
|
"<register name=\"r8\"/> "
|
||||||
|
"</pentry> "
|
||||||
|
"</group> "
|
||||||
|
"<pentry minsize=\"1\" maxsize=\"500\" align=\"4\"> "
|
||||||
|
"<addr offset=\"0\" space=\"stack\"/> "
|
||||||
|
"</pentry> "
|
||||||
|
"</input>"
|
||||||
|
"<output>"
|
||||||
|
"<pentry minsize=\"1\" maxsize=\"4\">"
|
||||||
|
"<register name=\"r12\"/>"
|
||||||
|
"</pentry>"
|
||||||
|
"</output>"
|
||||||
|
"</prototype>";
|
||||||
|
s << text << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProtoModel *getModel(const string &nm)
|
||||||
|
|
||||||
|
{
|
||||||
|
FuncProtoTestEnvironment::build();
|
||||||
|
return glb->protoModels[nm];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool register_equal(ParameterPieces &piece,const string &nm)
|
||||||
|
|
||||||
|
{
|
||||||
|
VarnodeData vData = glb->translate->getRegister(nm);
|
||||||
|
if (vData.space != piece.addr.getSpace())
|
||||||
|
return false;
|
||||||
|
if (vData.offset != piece.addr.getOffset())
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
FuncProtoTestEnvironment::~FuncProtoTestEnvironment(void)
|
||||||
|
|
||||||
|
{
|
||||||
|
if (g != (Architecture *)0)
|
||||||
|
delete g;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(funcproto_register) {
|
||||||
|
ProtoModel *model = getModel("__model1");
|
||||||
|
istringstream s("void func(int4 a,int4 b);");
|
||||||
|
PrototypePieces pieces;
|
||||||
|
parse_protopieces(pieces,s,glb);
|
||||||
|
pieces.intypes.insert(pieces.intypes.begin(),pieces.outtype);
|
||||||
|
vector<ParameterPieces> res;
|
||||||
|
model->assignParameterStorage(pieces.intypes, res, false);
|
||||||
|
ASSERT_EQUALS(res.size(),3);
|
||||||
|
ASSERT(res[0].addr.isInvalid()); // Placeholder for void return value
|
||||||
|
ASSERT(register_equal(res[1],"r12"));
|
||||||
|
ASSERT(register_equal(res[2],"r11"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(funcproto_smallregister) {
|
||||||
|
ProtoModel *model = getModel("__model1");
|
||||||
|
istringstream s("int4 func(char a,int4 b,int2 c,int4 d);");
|
||||||
|
PrototypePieces pieces;
|
||||||
|
parse_protopieces(pieces,s,glb);
|
||||||
|
pieces.intypes.insert(pieces.intypes.begin(),pieces.outtype);
|
||||||
|
vector<ParameterPieces> res;
|
||||||
|
model->assignParameterStorage(pieces.intypes, res, false);
|
||||||
|
ASSERT_EQUALS(res.size(),5);
|
||||||
|
ASSERT(register_equal(res[0],"r12")); // output register
|
||||||
|
ASSERT_EQUALS(res[0].type->getName(),"int4");
|
||||||
|
ASSERT(register_equal(res[1],"r12"));
|
||||||
|
ASSERT_EQUALS(res[1].type->getName(),"char");
|
||||||
|
ASSERT(register_equal(res[2],"r11"));
|
||||||
|
ASSERT_EQUALS(res[2].type->getName(),"int4");
|
||||||
|
ASSERT(register_equal(res[3],"r10"));
|
||||||
|
ASSERT_EQUALS(res[3].type->getName(),"int2");
|
||||||
|
ASSERT(register_equal(res[4],"r9"));
|
||||||
|
ASSERT_EQUALS(res[4].type->getName(),"int4");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(funcproto_stackalign) {
|
||||||
|
ProtoModel *model = getModel("__model1");
|
||||||
|
istringstream s("int4 func(int4 a,int4 b,int4 c,int4 d,int4 e,int2 f,int1 *g);");
|
||||||
|
PrototypePieces pieces;
|
||||||
|
parse_protopieces(pieces,s,glb);
|
||||||
|
pieces.intypes.insert(pieces.intypes.begin(),pieces.outtype);
|
||||||
|
vector<ParameterPieces> res;
|
||||||
|
model->assignParameterStorage(pieces.intypes, res, false);
|
||||||
|
ASSERT_EQUALS(res.size(),8);
|
||||||
|
ASSERT(register_equal(res[0],"r12")); // output register
|
||||||
|
ASSERT_EQUALS(res[0].type->getName(),"int4");
|
||||||
|
ASSERT(register_equal(res[1],"r12"));
|
||||||
|
ASSERT_EQUALS(res[1].type,res[0].type);
|
||||||
|
ASSERT(register_equal(res[2],"r11"));
|
||||||
|
ASSERT_EQUALS(res[2].type,res[0].type);
|
||||||
|
ASSERT(register_equal(res[3],"r10"));
|
||||||
|
ASSERT_EQUALS(res[3].type,res[0].type);
|
||||||
|
ASSERT(register_equal(res[4],"r9"));
|
||||||
|
ASSERT_EQUALS(res[4].type,res[0].type);
|
||||||
|
ASSERT(register_equal(res[5],"r8"));
|
||||||
|
ASSERT_EQUALS(res[5].type,res[0].type);
|
||||||
|
ASSERT_EQUALS(res[6].addr.getSpace(),glb->getStackSpace());
|
||||||
|
ASSERT_EQUALS(res[6].addr.getOffset(),0x0);
|
||||||
|
ASSERT_EQUALS(res[6].type->getName(),"int2");
|
||||||
|
ASSERT_EQUALS(res[7].addr.getSpace(),glb->getStackSpace());
|
||||||
|
ASSERT_EQUALS(res[7].addr.getOffset(),0x4);
|
||||||
|
ASSERT_EQUALS(res[7].type->getMetatype(),TYPE_PTR);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(funcproto_pointeroverflow) {
|
||||||
|
ProtoModel *model = getModel("__model1");
|
||||||
|
istringstream s("int2 func(int4 a,int8 b,int4 c);");
|
||||||
|
PrototypePieces pieces;
|
||||||
|
parse_protopieces(pieces,s,glb);
|
||||||
|
pieces.intypes.insert(pieces.intypes.begin(),pieces.outtype);
|
||||||
|
vector<ParameterPieces> res;
|
||||||
|
model->assignParameterStorage(pieces.intypes, res, false);
|
||||||
|
ASSERT_EQUALS(res.size(),4);
|
||||||
|
ASSERT(register_equal(res[0],"r12")); // output register
|
||||||
|
ASSERT_EQUALS(res[0].type->getName(),"int2");
|
||||||
|
ASSERT(register_equal(res[1],"r12"));
|
||||||
|
ASSERT_EQUALS(res[1].type->getName(),"int4");
|
||||||
|
ASSERT(register_equal(res[2],"r11"));
|
||||||
|
ASSERT_EQUALS(res[2].type->getMetatype(),TYPE_PTR);
|
||||||
|
ASSERT_EQUALS(((TypePointer *)res[2].type)->getPtrTo()->getName(),"int8");
|
||||||
|
ASSERT_EQUALS(res[2].flags,ParameterPieces::indirectstorage);
|
||||||
|
ASSERT(register_equal(res[3],"r10"));
|
||||||
|
ASSERT_EQUALS(res[3].type->getName(),"int4");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(funcproto_stackoverflow) {
|
||||||
|
ProtoModel *model = getModel("__model2");
|
||||||
|
istringstream s("char func(int4 a,int8 b,int4 c);");
|
||||||
|
PrototypePieces pieces;
|
||||||
|
parse_protopieces(pieces,s,glb);
|
||||||
|
pieces.intypes.insert(pieces.intypes.begin(),pieces.outtype);
|
||||||
|
vector<ParameterPieces> res;
|
||||||
|
model->assignParameterStorage(pieces.intypes, res, false);
|
||||||
|
ASSERT_EQUALS(res.size(),4);
|
||||||
|
ASSERT(register_equal(res[0],"r12")); // output register
|
||||||
|
ASSERT_EQUALS(res[0].type->getName(),"char");
|
||||||
|
ASSERT(register_equal(res[1],"r10"));
|
||||||
|
ASSERT_EQUALS(res[1].type->getName(),"int4");
|
||||||
|
ASSERT_EQUALS(res[2].addr.getSpace(),glb->getStackSpace());
|
||||||
|
ASSERT_EQUALS(res[2].addr.getOffset(),0x0); // Should overflow to stack
|
||||||
|
ASSERT_EQUALS(res[2].type->getName(),"int8");
|
||||||
|
ASSERT(register_equal(res[3],"r9")); // Should resume with next register
|
||||||
|
ASSERT_EQUALS(res[3].type->getName(),"int4");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(funcproto_floatreg) {
|
||||||
|
ProtoModel *model = getModel("__model2");
|
||||||
|
istringstream s("void func(int4 a,float4 b,float4 c,int4 d,float4 d);");
|
||||||
|
PrototypePieces pieces;
|
||||||
|
parse_protopieces(pieces,s,glb);
|
||||||
|
pieces.intypes.insert(pieces.intypes.begin(),pieces.outtype);
|
||||||
|
vector<ParameterPieces> res;
|
||||||
|
model->assignParameterStorage(pieces.intypes, res, false);
|
||||||
|
ASSERT_EQUALS(res.size(),6);
|
||||||
|
ASSERT(res[0].addr.isInvalid());
|
||||||
|
ASSERT(register_equal(res[1],"r10"));
|
||||||
|
ASSERT(register_equal(res[2],"r3"));
|
||||||
|
ASSERT_EQUALS(res[2].type->getName(),"float4");
|
||||||
|
ASSERT(register_equal(res[3],"r4"));
|
||||||
|
ASSERT_EQUALS(res[3].type->getName(),"float4");
|
||||||
|
ASSERT(register_equal(res[4],"r9"));
|
||||||
|
ASSERT(register_equal(res[5],"r5"));
|
||||||
|
ASSERT_EQUALS(res[5].type->getName(),"float4");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(funcproto_floattogeneric) {
|
||||||
|
ProtoModel *model = getModel("__model2");
|
||||||
|
istringstream s("float4 func(int4 a,float4 b,float4 c,float4 d,float4 e,float4 f);");
|
||||||
|
PrototypePieces pieces;
|
||||||
|
parse_protopieces(pieces,s,glb);
|
||||||
|
pieces.intypes.insert(pieces.intypes.begin(),pieces.outtype);
|
||||||
|
vector<ParameterPieces> res;
|
||||||
|
model->assignParameterStorage(pieces.intypes, res, false);
|
||||||
|
ASSERT_EQUALS(res.size(),7);
|
||||||
|
ASSERT(register_equal(res[0],"r12"));
|
||||||
|
ASSERT_EQUALS(res[0].type->getName(),"float4");
|
||||||
|
ASSERT(register_equal(res[1],"r10"));
|
||||||
|
ASSERT(register_equal(res[2],"r3"));
|
||||||
|
ASSERT_EQUALS(res[2].type->getName(),"float4");
|
||||||
|
ASSERT(register_equal(res[3],"r4"));
|
||||||
|
ASSERT_EQUALS(res[3].type->getName(),"float4");
|
||||||
|
ASSERT(register_equal(res[4],"r5"));
|
||||||
|
ASSERT_EQUALS(res[4].type->getName(),"float4");
|
||||||
|
ASSERT(register_equal(res[5],"r9")); // If float registers are exhausted, it should pick up with generic registers
|
||||||
|
ASSERT_EQUALS(res[5].type->getName(),"float4");
|
||||||
|
ASSERT(register_equal(res[6],"r8"));
|
||||||
|
ASSERT_EQUALS(res[6].type->getName(),"float4");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(funcproto_grouped) {
|
||||||
|
ProtoModel *model = getModel("__model3");
|
||||||
|
istringstream s("float4 func(int4 a,float4 b,float4 c,int4 d,float4 e);");
|
||||||
|
PrototypePieces pieces;
|
||||||
|
parse_protopieces(pieces,s,glb);
|
||||||
|
pieces.intypes.insert(pieces.intypes.begin(),pieces.outtype);
|
||||||
|
vector<ParameterPieces> res;
|
||||||
|
model->assignParameterStorage(pieces.intypes, res, false);
|
||||||
|
ASSERT_EQUALS(res.size(),6);
|
||||||
|
ASSERT(register_equal(res[0],"r12"));
|
||||||
|
ASSERT_EQUALS(res[0].type->getName(),"float4");
|
||||||
|
ASSERT(register_equal(res[1],"r10"));
|
||||||
|
ASSERT_EQUALS(res[1].type->getName(),"int4");
|
||||||
|
ASSERT(register_equal(res[2],"r4"));
|
||||||
|
ASSERT_EQUALS(res[2].type->getName(),"float4");
|
||||||
|
ASSERT(register_equal(res[3],"r5"));
|
||||||
|
ASSERT_EQUALS(res[3].type->getName(),"float4");
|
||||||
|
ASSERT_EQUALS(res[4].addr.getSpace(),glb->getStackSpace());
|
||||||
|
ASSERT_EQUALS(res[4].addr.getOffset(),0x0);
|
||||||
|
ASSERT_EQUALS(res[4].type->getName(),"int4");
|
||||||
|
ASSERT_EQUALS(res[5].addr.getSpace(),glb->getStackSpace());
|
||||||
|
ASSERT_EQUALS(res[5].addr.getOffset(),0x4);
|
||||||
|
ASSERT_EQUALS(res[5].type->getName(),"float4");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(funcproto_join) {
|
||||||
|
ProtoModel *model = getModel("__model2");
|
||||||
|
istringstream s("int2 func(int8 a,int4 b,int4 c);");
|
||||||
|
PrototypePieces pieces;
|
||||||
|
parse_protopieces(pieces,s,glb);
|
||||||
|
pieces.intypes.insert(pieces.intypes.begin(),pieces.outtype);
|
||||||
|
vector<ParameterPieces> res;
|
||||||
|
model->assignParameterStorage(pieces.intypes, res, false);
|
||||||
|
ASSERT_EQUALS(res.size(),4);
|
||||||
|
ASSERT(register_equal(res[0],"r12"));
|
||||||
|
ASSERT_EQUALS(res[0].type->getName(),"int2");
|
||||||
|
ASSERT_EQUALS(res[1].addr.getSpace(),glb->getJoinSpace());
|
||||||
|
ASSERT_EQUALS(res[1].type->getName(),"int8");
|
||||||
|
ASSERT(register_equal(res[2],"r8")); // r10 and r9 are consumed, should pick up with r8
|
||||||
|
ASSERT_EQUALS(res[2].type->getName(),"int4");
|
||||||
|
ASSERT_EQUALS(res[3].addr.getSpace(),glb->getStackSpace());
|
||||||
|
ASSERT_EQUALS(res[3].addr.getOffset(),0);
|
||||||
|
ASSERT_EQUALS(res[3].type->getName(),"int4");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(funcproto_nojoin) {
|
||||||
|
ProtoModel *model = getModel("__model2");
|
||||||
|
istringstream s("int4 func(int4 a,int8 b,int4 c);");
|
||||||
|
PrototypePieces pieces;
|
||||||
|
parse_protopieces(pieces,s,glb);
|
||||||
|
pieces.intypes.insert(pieces.intypes.begin(),pieces.outtype);
|
||||||
|
vector<ParameterPieces> res;
|
||||||
|
model->assignParameterStorage(pieces.intypes, res, false);
|
||||||
|
ASSERT_EQUALS(res.size(),4);
|
||||||
|
ASSERT(register_equal(res[0],"r12"));
|
||||||
|
ASSERT_EQUALS(res[0].type->getName(),"int4");
|
||||||
|
ASSERT(register_equal(res[1],"r10")); // r10 consumed by first parameter
|
||||||
|
ASSERT_EQUALS(res[1].type->getName(),"int4");
|
||||||
|
ASSERT_EQUALS(res[2].addr.getSpace(),glb->getStackSpace()); // Big param must go to stack, can't use join
|
||||||
|
ASSERT_EQUALS(res[2].addr.getOffset(),0);
|
||||||
|
ASSERT_EQUALS(res[2].type->getName(),"int8");
|
||||||
|
ASSERT(register_equal(res[3],"r9")); // Next param can go back to register
|
||||||
|
ASSERT_EQUALS(res[3].type->getName(),"int4");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(funcproto_hiddenreturn) {
|
||||||
|
ProtoModel *model = getModel("__model1");
|
||||||
|
istringstream s("int8 func(int4 a,int4 b);");
|
||||||
|
PrototypePieces pieces;
|
||||||
|
parse_protopieces(pieces,s,glb);
|
||||||
|
pieces.intypes.insert(pieces.intypes.begin(),pieces.outtype);
|
||||||
|
vector<ParameterPieces> res;
|
||||||
|
model->assignParameterStorage(pieces.intypes, res, false);
|
||||||
|
ASSERT_EQUALS(res.size(),4);
|
||||||
|
ASSERT(register_equal(res[0],"r12")); // Pointer to actual return value
|
||||||
|
ASSERT_EQUALS(res[0].type->getMetatype(),TYPE_PTR);
|
||||||
|
ASSERT_EQUALS(((TypePointer *)res[0].type)->getPtrTo()->getName(),"int8");
|
||||||
|
ASSERT(register_equal(res[1],"r12")); // Hidden return value pointer
|
||||||
|
ASSERT_EQUALS(res[1].flags,ParameterPieces::hiddenretparm);
|
||||||
|
ASSERT_EQUALS(res[1].type->getMetatype(),TYPE_PTR);
|
||||||
|
ASSERT_EQUALS(((TypePointer *)res[1].type)->getPtrTo()->getName(),"int8");
|
||||||
|
ASSERT(register_equal(res[2],"r11")); // First formal parameter pushed to second slot
|
||||||
|
ASSERT_EQUALS(res[2].type->getName(),"int4");
|
||||||
|
ASSERT(register_equal(res[3],"r10"));
|
||||||
|
ASSERT_EQUALS(res[3].type->getName(),"int4");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(funcproto_mixedmeta) {
|
||||||
|
ProtoModel *model = getModel("__model2");
|
||||||
|
istringstream s("int4 func(char *a,int4 b,float4 c,int4 *d);");
|
||||||
|
PrototypePieces pieces;
|
||||||
|
parse_protopieces(pieces,s,glb);
|
||||||
|
pieces.intypes.insert(pieces.intypes.begin(),pieces.outtype);
|
||||||
|
vector<ParameterPieces> res;
|
||||||
|
model->assignParameterStorage(pieces.intypes, res, false);
|
||||||
|
ASSERT_EQUALS(res.size(),5);
|
||||||
|
ASSERT(register_equal(res[0],"r12"));
|
||||||
|
ASSERT(register_equal(res[1],"r1"));
|
||||||
|
ASSERT_EQUALS(res[1].type->getMetatype(),TYPE_PTR);
|
||||||
|
ASSERT(register_equal(res[2],"r10"));
|
||||||
|
ASSERT(register_equal(res[3],"r3"));
|
||||||
|
ASSERT(register_equal(res[4],"r2"));
|
||||||
|
ASSERT_EQUALS(res[4].type->getMetatype(),TYPE_PTR);
|
||||||
|
}
|
||||||
|
|
||||||
|
void registerActive(ParamActive ¶mActive,const string &nm,int4 sz)
|
||||||
|
|
||||||
|
{
|
||||||
|
paramActive.registerTrial(glb->translate->getRegister(nm).getAddr(),sz);
|
||||||
|
int4 num = paramActive.getNumTrials();
|
||||||
|
paramActive.getTrial(num-1).markActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
void stackActive(ParamActive ¶mActive,uintb off,int4 sz)
|
||||||
|
|
||||||
|
{
|
||||||
|
paramActive.registerTrial(Address(glb->getStackSpace(),off),sz);
|
||||||
|
int4 num = paramActive.getNumTrials();
|
||||||
|
paramActive.getTrial(num-1).markActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool register_used(ParamTrial &trial,const string &nm)
|
||||||
|
|
||||||
|
{
|
||||||
|
if (!trial.isUsed()) return false;
|
||||||
|
VarnodeData vData = glb->translate->getRegister(nm);
|
||||||
|
if (trial.getAddress() != vData.getAddr())
|
||||||
|
return false;
|
||||||
|
if (trial.getSize() != vData.size)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool stack_used(ParamTrial &trial,uintb off,int4 sz)
|
||||||
|
|
||||||
|
{
|
||||||
|
if (!trial.isUsed()) return false;
|
||||||
|
Address addr(glb->getStackSpace(),off);
|
||||||
|
if (trial.getAddress() != addr)
|
||||||
|
return false;
|
||||||
|
if (trial.getSize() != sz)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(funcproto_recoverbasic)
|
||||||
|
|
||||||
|
{
|
||||||
|
ProtoModel *model = getModel("__model1");
|
||||||
|
ParamActive paramActive(false);
|
||||||
|
registerActive(paramActive,"r11",4);
|
||||||
|
registerActive(paramActive,"r10",4);
|
||||||
|
registerActive(paramActive,"r12",4);
|
||||||
|
model->deriveInputMap(¶mActive);
|
||||||
|
ASSERT_EQUALS(paramActive.getNumTrials(),3);
|
||||||
|
ASSERT(register_used(paramActive.getTrial(0),"r12"));
|
||||||
|
ASSERT(register_used(paramActive.getTrial(1),"r11"));
|
||||||
|
ASSERT(register_used(paramActive.getTrial(2),"r10"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(funcproto_recoversmallreg)
|
||||||
|
|
||||||
|
{
|
||||||
|
ProtoModel *model = getModel("__model1");
|
||||||
|
ParamActive paramActive(false);
|
||||||
|
registerActive(paramActive,"r11",4);
|
||||||
|
registerActive(paramActive,"r12l",2);
|
||||||
|
registerActive(paramActive,"r10l",2);
|
||||||
|
model->deriveInputMap(¶mActive);
|
||||||
|
ASSERT_EQUALS(paramActive.getNumTrials(),3);
|
||||||
|
ASSERT(register_used(paramActive.getTrial(0),"r12l"));
|
||||||
|
ASSERT(register_used(paramActive.getTrial(1),"r11"));
|
||||||
|
ASSERT(register_used(paramActive.getTrial(2),"r10l"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(funcproto_recoverstack)
|
||||||
|
|
||||||
|
{
|
||||||
|
ProtoModel *model = getModel("__model2");
|
||||||
|
ParamActive paramActive(false);
|
||||||
|
registerActive(paramActive,"r10",4);
|
||||||
|
stackActive(paramActive, 0, 2);
|
||||||
|
registerActive(paramActive,"r8",4);
|
||||||
|
stackActive(paramActive, 4, 4);
|
||||||
|
registerActive(paramActive,"r9",4);
|
||||||
|
model->deriveInputMap(¶mActive);
|
||||||
|
ASSERT_EQUALS(paramActive.getNumTrials(),10);
|
||||||
|
ASSERT(paramActive.getTrial(0).isUnref());
|
||||||
|
ASSERT(paramActive.getTrial(1).isUnref());
|
||||||
|
ASSERT(paramActive.getTrial(2).isUnref());
|
||||||
|
ASSERT(paramActive.getTrial(3).isUnref());
|
||||||
|
ASSERT(paramActive.getTrial(4).isUnref());
|
||||||
|
ASSERT(!paramActive.getTrial(0).isUsed());
|
||||||
|
ASSERT(!paramActive.getTrial(1).isUsed());
|
||||||
|
ASSERT(!paramActive.getTrial(2).isUsed());
|
||||||
|
ASSERT(!paramActive.getTrial(3).isUsed());
|
||||||
|
ASSERT(!paramActive.getTrial(4).isUsed());
|
||||||
|
ASSERT(register_used(paramActive.getTrial(5),"r10"));
|
||||||
|
ASSERT(register_used(paramActive.getTrial(6),"r9"));
|
||||||
|
ASSERT(register_used(paramActive.getTrial(7),"r8"));
|
||||||
|
ASSERT(stack_used(paramActive.getTrial(8),0,2));
|
||||||
|
ASSERT(stack_used(paramActive.getTrial(9),4,4));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(funcproto_recoverunrefregister)
|
||||||
|
|
||||||
|
{
|
||||||
|
ProtoModel *model = getModel("__model1");
|
||||||
|
ParamActive paramActive(false);
|
||||||
|
registerActive(paramActive,"r12",4);
|
||||||
|
registerActive(paramActive,"r10",4);
|
||||||
|
model->deriveInputMap(¶mActive);
|
||||||
|
ASSERT_EQUALS(paramActive.getNumTrials(),3);
|
||||||
|
ASSERT(register_used(paramActive.getTrial(0),"r12"));
|
||||||
|
ASSERT(register_used(paramActive.getTrial(1),"r11"));
|
||||||
|
ASSERT(paramActive.getTrial(1).isUnref());
|
||||||
|
ASSERT(register_used(paramActive.getTrial(2),"r10"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(funcproto_recoverunrefstack)
|
||||||
|
|
||||||
|
{
|
||||||
|
ProtoModel *model = getModel("__model2");
|
||||||
|
ParamActive paramActive(false);
|
||||||
|
stackActive(paramActive,4,4);
|
||||||
|
stackActive(paramActive,12,4);
|
||||||
|
registerActive(paramActive,"r8",4);
|
||||||
|
registerActive(paramActive,"r9",4);
|
||||||
|
registerActive(paramActive,"r10",4);
|
||||||
|
model->deriveInputMap(¶mActive);
|
||||||
|
ASSERT_EQUALS(paramActive.getNumTrials(),12);
|
||||||
|
ASSERT(paramActive.getTrial(0).isUnref());
|
||||||
|
ASSERT(paramActive.getTrial(1).isUnref());
|
||||||
|
ASSERT(paramActive.getTrial(2).isUnref());
|
||||||
|
ASSERT(paramActive.getTrial(3).isUnref());
|
||||||
|
ASSERT(paramActive.getTrial(4).isUnref());
|
||||||
|
ASSERT(!paramActive.getTrial(0).isUsed());
|
||||||
|
ASSERT(!paramActive.getTrial(1).isUsed());
|
||||||
|
ASSERT(!paramActive.getTrial(2).isUsed());
|
||||||
|
ASSERT(!paramActive.getTrial(3).isUsed());
|
||||||
|
ASSERT(!paramActive.getTrial(4).isUsed());
|
||||||
|
ASSERT(register_used(paramActive.getTrial(5),"r10"));
|
||||||
|
ASSERT(register_used(paramActive.getTrial(6),"r9"));
|
||||||
|
ASSERT(register_used(paramActive.getTrial(7),"r8"));
|
||||||
|
ASSERT(stack_used(paramActive.getTrial(8),0,4));
|
||||||
|
ASSERT(paramActive.getTrial(8).isUnref());
|
||||||
|
ASSERT(stack_used(paramActive.getTrial(9),4,4));
|
||||||
|
ASSERT(stack_used(paramActive.getTrial(10),8,4));
|
||||||
|
ASSERT(paramActive.getTrial(10).isUnref());
|
||||||
|
ASSERT(stack_used(paramActive.getTrial(11),12,4));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(funcproto_recovergroups)
|
||||||
|
|
||||||
|
{
|
||||||
|
ProtoModel *model = getModel("__model3");
|
||||||
|
ParamActive paramActive(false);
|
||||||
|
registerActive(paramActive,"r3",4);
|
||||||
|
registerActive(paramActive,"r5",4);
|
||||||
|
registerActive(paramActive,"r9",4);
|
||||||
|
model->deriveInputMap(¶mActive);
|
||||||
|
ASSERT_EQUALS(paramActive.getNumTrials(),3);
|
||||||
|
ASSERT(register_used(paramActive.getTrial(0),"r3"));
|
||||||
|
ASSERT(register_used(paramActive.getTrial(1),"r9"));
|
||||||
|
ASSERT(register_used(paramActive.getTrial(2),"r5"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(funcproto_recoverholes)
|
||||||
|
|
||||||
|
{
|
||||||
|
ProtoModel *model = getModel("__model1");
|
||||||
|
ParamActive paramActive(false);
|
||||||
|
registerActive(paramActive,"r8",4);
|
||||||
|
registerActive(paramActive,"r12",4);
|
||||||
|
stackActive(paramActive,0,4);
|
||||||
|
model->deriveInputMap(¶mActive);
|
||||||
|
ASSERT_EQUALS(paramActive.getNumTrials(),6);
|
||||||
|
ASSERT(register_used(paramActive.getTrial(0),"r12"));
|
||||||
|
ASSERT(!paramActive.getTrial(1).isUsed());
|
||||||
|
ASSERT(paramActive.getTrial(1).isUnref());
|
||||||
|
ASSERT(!paramActive.getTrial(2).isUsed());
|
||||||
|
ASSERT(paramActive.getTrial(2).isUnref());
|
||||||
|
ASSERT(!paramActive.getTrial(3).isUsed());
|
||||||
|
ASSERT(paramActive.getTrial(3).isUnref());
|
||||||
|
ASSERT(!paramActive.getTrial(4).isUsed());
|
||||||
|
ASSERT(!paramActive.getTrial(5).isUsed());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(funcproto_recoverfloat)
|
||||||
|
|
||||||
|
{
|
||||||
|
ProtoModel *model = getModel("__model2");
|
||||||
|
ParamActive paramActive(false);
|
||||||
|
registerActive(paramActive,"r10",4);
|
||||||
|
registerActive(paramActive,"r5",4);
|
||||||
|
registerActive(paramActive,"r3",4);
|
||||||
|
model->deriveInputMap(¶mActive);
|
||||||
|
ASSERT_EQUALS(paramActive.getNumTrials(),6);
|
||||||
|
ASSERT(paramActive.getTrial(0).isUnref());
|
||||||
|
ASSERT(paramActive.getTrial(1).isUnref());
|
||||||
|
ASSERT(!paramActive.getTrial(0).isUsed());
|
||||||
|
ASSERT(!paramActive.getTrial(1).isUsed());
|
||||||
|
ASSERT(register_used(paramActive.getTrial(2),"r3"));
|
||||||
|
ASSERT(register_used(paramActive.getTrial(3),"r4"));
|
||||||
|
ASSERT(register_used(paramActive.getTrial(4),"r5"));
|
||||||
|
ASSERT(register_used(paramActive.getTrial(5),"r10"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(funcproto_recovermixedmeta)
|
||||||
|
|
||||||
|
{
|
||||||
|
ProtoModel *model = getModel("__model2");
|
||||||
|
ParamActive paramActive(false);
|
||||||
|
registerActive(paramActive,"r10",4);
|
||||||
|
registerActive(paramActive,"r4",4);
|
||||||
|
registerActive(paramActive,"r1",4);
|
||||||
|
model->deriveInputMap(¶mActive);
|
||||||
|
ASSERT_EQUALS(paramActive.getNumTrials(),6);
|
||||||
|
ASSERT(register_used(paramActive.getTrial(0),"r1"));
|
||||||
|
ASSERT(paramActive.getTrial(1).isUnref());
|
||||||
|
ASSERT(!paramActive.getTrial(1).isUsed());
|
||||||
|
ASSERT(register_used(paramActive.getTrial(2),"r3"));
|
||||||
|
ASSERT(register_used(paramActive.getTrial(3),"r4"));
|
||||||
|
ASSERT(paramActive.getTrial(4).isUnref());
|
||||||
|
ASSERT(!paramActive.getTrial(4).isUsed());
|
||||||
|
ASSERT(register_used(paramActive.getTrial(5),"r10"))
|
||||||
|
}
|
|
@ -38,7 +38,7 @@ public interface ParamList {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a list of datatypes, calculate the storage locations used for passing those datatypes
|
* Given a list of datatypes, calculate the storage locations used for passing those datatypes
|
||||||
* @param prog is the active progra
|
* @param prog is the active program
|
||||||
* @param proto is the list of datatypes
|
* @param proto is the list of datatypes
|
||||||
* @param res is the vector for holding the VariableStorage corresponding to datatypes
|
* @param res is the vector for holding the VariableStorage corresponding to datatypes
|
||||||
* @param addAutoParams if true add/process auto-parameters
|
* @param addAutoParams if true add/process auto-parameters
|
||||||
|
|
|
@ -43,7 +43,8 @@ public class ParamListStandard implements ParamList {
|
||||||
// protected int maxdelay;
|
// protected int maxdelay;
|
||||||
protected int pointermax; // If non-zero, maximum size of a datatype before converting to a pointer
|
protected int pointermax; // If non-zero, maximum size of a datatype before converting to a pointer
|
||||||
protected boolean thisbeforeret; // Do hidden return pointers usurp the storage of the this pointer
|
protected boolean thisbeforeret; // Do hidden return pointers usurp the storage of the this pointer
|
||||||
protected int resourceTwoStart; // Group id starting the section resource section (or 0 if only one section)
|
protected boolean splitMetatype; // Are metatyped entries in separate resource sections
|
||||||
|
// protected int[] resourceStart; // The starting group for each resource section
|
||||||
protected ParamEntry[] entry;
|
protected ParamEntry[] entry;
|
||||||
protected AddressSpace spacebase; // Space containing relative offset parameters
|
protected AddressSpace spacebase; // Space containing relative offset parameters
|
||||||
|
|
||||||
|
@ -212,7 +213,7 @@ public class ParamListStandard implements ParamList {
|
||||||
if (thisbeforeret) {
|
if (thisbeforeret) {
|
||||||
encoder.writeBool(ATTRIB_THISBEFORERETPOINTER, true);
|
encoder.writeBool(ATTRIB_THISBEFORERETPOINTER, true);
|
||||||
}
|
}
|
||||||
if (isInput && resourceTwoStart == 0) {
|
if (isInput && !splitMetatype) {
|
||||||
encoder.writeBool(ATTRIB_SEPARATEFLOAT, false);
|
encoder.writeBool(ATTRIB_SEPARATEFLOAT, false);
|
||||||
}
|
}
|
||||||
int curgroup = -1;
|
int curgroup = -1;
|
||||||
|
@ -239,18 +240,25 @@ public class ParamListStandard implements ParamList {
|
||||||
|
|
||||||
private void parsePentry(XmlPullParser parser, CompilerSpec cspec, ArrayList<ParamEntry> pe,
|
private void parsePentry(XmlPullParser parser, CompilerSpec cspec, ArrayList<ParamEntry> pe,
|
||||||
int groupid, boolean splitFloat, boolean grouped) throws XmlParseException {
|
int groupid, boolean splitFloat, boolean grouped) throws XmlParseException {
|
||||||
|
int lastMeta = -1; // Smaller than any real metatype
|
||||||
|
if (!pe.isEmpty()) {
|
||||||
|
ParamEntry lastEntry = pe.get(pe.size() - 1);
|
||||||
|
lastMeta = lastEntry.isGrouped() ? ParamEntry.TYPE_UNKNOWN : lastEntry.getType();
|
||||||
|
}
|
||||||
ParamEntry pentry = new ParamEntry(groupid);
|
ParamEntry pentry = new ParamEntry(groupid);
|
||||||
pe.add(pentry);
|
pe.add(pentry);
|
||||||
pentry.restoreXml(parser, cspec, pe, grouped);
|
pentry.restoreXml(parser, cspec, pe, grouped);
|
||||||
if (splitFloat) {
|
if (splitFloat) {
|
||||||
if (!grouped && pentry.getType() == ParamEntry.TYPE_FLOAT) {
|
int currentMeta = grouped ? ParamEntry.TYPE_UNKNOWN : pentry.getType();
|
||||||
if (resourceTwoStart >= 0) {
|
if (lastMeta != currentMeta) {
|
||||||
|
if (lastMeta > currentMeta) {
|
||||||
throw new XmlParseException(
|
throw new XmlParseException(
|
||||||
"parameter list floating-point entries must come first");
|
"parameter list entries must be ordered by metatype");
|
||||||
}
|
}
|
||||||
}
|
// int[] newResourceStart = new int[resourceStart.length + 1];
|
||||||
else if (resourceTwoStart < 0) {
|
// System.arraycopy(resourceStart, 0, newResourceStart, 0, resourceStart.length);
|
||||||
resourceTwoStart = groupid; // First time we have seen an integer slot
|
// newResourceStart[resourceStart.length] = groupid;
|
||||||
|
// resourceStart = newResourceStart;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pentry.getSpace().isStackSpace()) {
|
if (pentry.getSpace().isStackSpace()) {
|
||||||
|
@ -293,7 +301,7 @@ public class ParamListStandard implements ParamList {
|
||||||
spacebase = null;
|
spacebase = null;
|
||||||
pointermax = 0;
|
pointermax = 0;
|
||||||
thisbeforeret = false;
|
thisbeforeret = false;
|
||||||
boolean splitFloat = true;
|
splitMetatype = true;
|
||||||
XmlElement mainel = parser.start();
|
XmlElement mainel = parser.start();
|
||||||
String attribute = mainel.getAttribute("pointermax");
|
String attribute = mainel.getAttribute("pointermax");
|
||||||
if (attribute != null) {
|
if (attribute != null) {
|
||||||
|
@ -305,24 +313,28 @@ public class ParamListStandard implements ParamList {
|
||||||
}
|
}
|
||||||
attribute = mainel.getAttribute("separatefloat");
|
attribute = mainel.getAttribute("separatefloat");
|
||||||
if (attribute != null) {
|
if (attribute != null) {
|
||||||
splitFloat = SpecXmlUtils.decodeBoolean(attribute);
|
splitMetatype = SpecXmlUtils.decodeBoolean(attribute);
|
||||||
}
|
}
|
||||||
resourceTwoStart = splitFloat ? -1 : 0;
|
// resourceStart = new int[0];
|
||||||
for (;;) {
|
for (;;) {
|
||||||
XmlElement el = parser.peek();
|
XmlElement el = parser.peek();
|
||||||
if (!el.isStart()) {
|
if (!el.isStart()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (el.getName().equals("pentry")) {
|
if (el.getName().equals("pentry")) {
|
||||||
parsePentry(parser, cspec, pe, numgroup, splitFloat, false);
|
parsePentry(parser, cspec, pe, numgroup, splitMetatype, false);
|
||||||
}
|
}
|
||||||
else if (el.getName().equals("group")) {
|
else if (el.getName().equals("group")) {
|
||||||
parseGroup(parser, cspec, pe, numgroup, splitFloat);
|
parseGroup(parser, cspec, pe, numgroup, splitMetatype);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
parser.end(mainel);
|
parser.end(mainel);
|
||||||
entry = new ParamEntry[pe.size()];
|
entry = new ParamEntry[pe.size()];
|
||||||
pe.toArray(entry);
|
pe.toArray(entry);
|
||||||
|
// int[] newResourceStart = new int[resourceStart.length + 1];
|
||||||
|
// System.arraycopy(resourceStart, 0, newResourceStart, 0, resourceStart.length);
|
||||||
|
// newResourceStart[resourceStart.length] = numgroup;
|
||||||
|
// resourceStart = newResourceStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue