mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 10:49:34 +02:00
Merge remote-tracking branch
'origin/GP-520_James_max_unique_varnode_size'
This commit is contained in:
commit
a3f223619c
10 changed files with 196 additions and 27 deletions
|
@ -37,6 +37,7 @@ ConstTpl::ConstTpl(const_type tp,int4 ht,v_field vf)
|
||||||
type = handle;
|
type = handle;
|
||||||
value.handle_index = ht;
|
value.handle_index = ht;
|
||||||
select = vf;
|
select = vf;
|
||||||
|
value_real = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstTpl::ConstTpl(const_type tp,int4 ht,v_field vf,uintb plus)
|
ConstTpl::ConstTpl(const_type tp,int4 ht,v_field vf,uintb plus)
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
const int4 SleighBase::SLA_FORMAT_VERSION = 3;
|
const int4 SleighBase::SLA_FORMAT_VERSION = 3;
|
||||||
|
|
||||||
|
const uintb SleighBase::MAX_UNIQUE_SIZE = 128;
|
||||||
|
|
||||||
int4 SourceFileIndexer::index(const string filename){
|
int4 SourceFileIndexer::index(const string filename){
|
||||||
auto it = fileToIndex.find(filename);
|
auto it = fileToIndex.find(filename);
|
||||||
if (fileToIndex.end() != it){
|
if (fileToIndex.end() != it){
|
||||||
|
@ -57,7 +59,6 @@ void SourceFileIndexer::saveXml(ostream& s) const {
|
||||||
s << "</sourcefiles>\n";
|
s << "</sourcefiles>\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SleighBase::SleighBase(void)
|
SleighBase::SleighBase(void)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -69,6 +69,7 @@ protected:
|
||||||
void reregisterContext(void); ///< Reregister context fields for a new executable
|
void reregisterContext(void); ///< Reregister context fields for a new executable
|
||||||
void restoreXml(const Element *el); ///< Read a SLEIGH specification from XML
|
void restoreXml(const Element *el); ///< Read a SLEIGH specification from XML
|
||||||
public:
|
public:
|
||||||
|
static const uintb MAX_UNIQUE_SIZE; ///< Maximum size of a varnode in the unique space (should match value in SleighBase.java)
|
||||||
SleighBase(void); ///< Construct an uninitialized translator
|
SleighBase(void); ///< Construct an uninitialized translator
|
||||||
bool isInitialized(void) const { return (root != (SubtableSymbol *)0); } ///< Return \b true if \b this is initialized
|
bool isInitialized(void) const { return (root != (SubtableSymbol *)0); } ///< Return \b true if \b this is initialized
|
||||||
virtual ~SleighBase(void) {} ///< Destructor
|
virtual ~SleighBase(void) {} ///< Destructor
|
||||||
|
|
|
@ -183,7 +183,7 @@ SubtableSymbol *WithBlock::getCurrentSubtable(const list<WithBlock> &stack)
|
||||||
return (SubtableSymbol *)0;
|
return (SubtableSymbol *)0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConsistencyChecker::ConsistencyChecker(SleighCompile *sleigh,SubtableSymbol *rt,bool un,bool warndead)
|
ConsistencyChecker::ConsistencyChecker(SleighCompile *sleigh,SubtableSymbol *rt,bool un,bool warndead, bool warnlargetemp)
|
||||||
|
|
||||||
{
|
{
|
||||||
compiler = sleigh;
|
compiler = sleigh;
|
||||||
|
@ -191,8 +191,10 @@ ConsistencyChecker::ConsistencyChecker(SleighCompile *sleigh,SubtableSymbol *rt,
|
||||||
unnecessarypcode = 0;
|
unnecessarypcode = 0;
|
||||||
readnowrite = 0;
|
readnowrite = 0;
|
||||||
writenoread = 0;
|
writenoread = 0;
|
||||||
|
largetemp = 0; ///<Number of constructors using at least one temporary varnode larger than SleighBase::MAX_UNIQUE_SIZE
|
||||||
printextwarning = un;
|
printextwarning = un;
|
||||||
printdeadwarning = warndead;
|
printdeadwarning = warndead;
|
||||||
|
printlargetempwarning = warnlargetemp; ///< If true, prints a warning about each constructor using a temporary varnode larger than SleighBase::MAX_UNIQUE_SIZE
|
||||||
}
|
}
|
||||||
|
|
||||||
int4 ConsistencyChecker::recoverSize(const ConstTpl &sizeconst,Constructor *ct)
|
int4 ConsistencyChecker::recoverSize(const ConstTpl &sizeconst,Constructor *ct)
|
||||||
|
@ -814,6 +816,33 @@ bool ConsistencyChecker::checkConstructorSection(Constructor *ct,ConstructTpl *c
|
||||||
return testresult;
|
return testresult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns true if the output or one of the inputs of
|
||||||
|
/// op is in the unique space and larger than SleighBase::MAX_UNIQUE_SIZE
|
||||||
|
///
|
||||||
|
bool ConsistencyChecker::hasLargeTemporary(OpTpl *op){
|
||||||
|
VarnodeTpl *out = op->getOut();
|
||||||
|
if ((out != (VarnodeTpl *) 0x0) && isTemporaryAndTooBig(out)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (int4 i = 0; i < op->numInput(); ++i) {
|
||||||
|
VarnodeTpl *in = op->getIn(i);
|
||||||
|
if (isTemporaryAndTooBig(in)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns true precisely when vn is in the unique space and
|
||||||
|
/// has size larger than SleighBase::MAX_UNIQUE_SIZE
|
||||||
|
///
|
||||||
|
bool ConsistencyChecker::isTemporaryAndTooBig(VarnodeTpl *vn){
|
||||||
|
return vn->getSpace().isUniqueSpace() &&
|
||||||
|
(vn->getSize().getReal() > SleighBase::MAX_UNIQUE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
bool ConsistencyChecker::checkVarnodeTruncation(Constructor *ct,int4 slot,
|
bool ConsistencyChecker::checkVarnodeTruncation(Constructor *ct,int4 slot,
|
||||||
OpTpl *op,VarnodeTpl *vn,bool isbigendian)
|
OpTpl *op,VarnodeTpl *vn,bool isbigendian)
|
||||||
{
|
{
|
||||||
|
@ -1238,6 +1267,24 @@ void ConsistencyChecker::checkUnusedTemps(Constructor *ct,const map<uintb,Optimi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Checks the ops in ct to see whether a varnode larger than
|
||||||
|
/// SleighBase::MAX_UNIQUE_SIZE is used. Note that this method
|
||||||
|
/// returns after the first large varnode is found.
|
||||||
|
///
|
||||||
|
void ConsistencyChecker::checkLargeTemporaries(Constructor *ct){
|
||||||
|
vector<OpTpl *> ops = ct->getTempl()->getOpvec();
|
||||||
|
for (vector<OpTpl *>::iterator iter = ops.begin(); iter != ops.end(); ++iter){
|
||||||
|
if (hasLargeTemporary(*iter)){
|
||||||
|
if (printlargetempwarning){
|
||||||
|
compiler->reportWarning(compiler->getLocation(ct), "Constructor uses temporary varnode larger than " + to_string(SleighBase::MAX_UNIQUE_SIZE) + " bytes.");
|
||||||
|
}
|
||||||
|
largetemp++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ConsistencyChecker::optimize(Constructor *ct)
|
void ConsistencyChecker::optimize(Constructor *ct)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -1255,6 +1302,7 @@ void ConsistencyChecker::optimize(Constructor *ct)
|
||||||
applyOptimization(ct,*currec);
|
applyOptimization(ct,*currec);
|
||||||
} while(currec != (OptimizeRecord *)0);
|
} while(currec != (OptimizeRecord *)0);
|
||||||
checkUnusedTemps(ct,recs);
|
checkUnusedTemps(ct,recs);
|
||||||
|
checkLargeTemporaries(ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConsistencyChecker::test(void)
|
bool ConsistencyChecker::test(void)
|
||||||
|
@ -1640,7 +1688,7 @@ void SleighCompile::buildPatterns(void)
|
||||||
void SleighCompile::checkConsistency(void)
|
void SleighCompile::checkConsistency(void)
|
||||||
|
|
||||||
{
|
{
|
||||||
ConsistencyChecker checker(this, root,warnunnecessarypcode,warndeadtemps);
|
ConsistencyChecker checker(this, root,warnunnecessarypcode,warndeadtemps,largetemporarywarning);
|
||||||
|
|
||||||
if (!checker.test()) {
|
if (!checker.test()) {
|
||||||
errors += 1;
|
errors += 1;
|
||||||
|
@ -1669,6 +1717,14 @@ void SleighCompile::checkConsistency(void)
|
||||||
msg << "Use -t switch to list each individually";
|
msg << "Use -t switch to list each individually";
|
||||||
reportInfo(msg.str());
|
reportInfo(msg.str());
|
||||||
}
|
}
|
||||||
|
if ((!largetemporarywarning) && (checker.getNumLargeTemporaries() > 0)) {
|
||||||
|
ostringstream msg;
|
||||||
|
msg << dec << checker.getNumLargeTemporaries();
|
||||||
|
msg << " constructors contain temporaries larger than ";
|
||||||
|
msg << SleighBase::MAX_UNIQUE_SIZE << " bytes" << endl;
|
||||||
|
msg << "Use -o switch to list each individually.";
|
||||||
|
reportInfo(msg.str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int4 SleighCompile::findCollision(map<uintb,int4> &local2Operand,const vector<uintb> &locals,int operand)
|
int4 SleighCompile::findCollision(map<uintb,int4> &local2Operand,const vector<uintb> &locals,int operand)
|
||||||
|
@ -1857,7 +1913,7 @@ uintb SleighCompile::getUniqueAddr(void)
|
||||||
|
|
||||||
{
|
{
|
||||||
uintb base = getUniqueBase();
|
uintb base = getUniqueBase();
|
||||||
setUniqueBase(base + 16); // Should be maximum size of a unique
|
setUniqueBase(base + SleighBase::MAX_UNIQUE_SIZE);
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2876,7 +2932,7 @@ static void findSlaSpecs(vector<string> &res, const string &dir, const string &s
|
||||||
|
|
||||||
static void initCompiler(SleighCompile &compiler, map<string,string> &defines, bool enableUnnecessaryPcodeWarning,
|
static void initCompiler(SleighCompile &compiler, map<string,string> &defines, bool enableUnnecessaryPcodeWarning,
|
||||||
bool disableLenientConflict, bool enableAllCollisionWarning,
|
bool disableLenientConflict, bool enableAllCollisionWarning,
|
||||||
bool enableAllNopWarning,bool enableDeadTempWarning,bool enforceLocalKeyWord)
|
bool enableAllNopWarning,bool enableDeadTempWarning,bool enforceLocalKeyWord, bool largeTemporaryWarning)
|
||||||
|
|
||||||
{
|
{
|
||||||
map<string,string>::iterator iter = defines.begin();
|
map<string,string>::iterator iter = defines.begin();
|
||||||
|
@ -2895,6 +2951,8 @@ static void initCompiler(SleighCompile &compiler, map<string,string> &defines, b
|
||||||
compiler.setDeadTempWarning(true);
|
compiler.setDeadTempWarning(true);
|
||||||
if (enforceLocalKeyWord)
|
if (enforceLocalKeyWord)
|
||||||
compiler.setEnforceLocalKeyWord(true);
|
compiler.setEnforceLocalKeyWord(true);
|
||||||
|
if (largeTemporaryWarning)
|
||||||
|
compiler.setLargeTemporaryWarning(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void segvHandler(int sig) {
|
static void segvHandler(int sig) {
|
||||||
|
@ -2922,6 +2980,7 @@ int main(int argc,char **argv)
|
||||||
cerr << " -t print warnings for dead temporaries" << endl;
|
cerr << " -t print warnings for dead temporaries" << endl;
|
||||||
cerr << " -e enforce use of 'local' keyword for temporaries" << endl;
|
cerr << " -e enforce use of 'local' keyword for temporaries" << endl;
|
||||||
cerr << " -c print warnings for all constructors with colliding operands" << endl;
|
cerr << " -c print warnings for all constructors with colliding operands" << endl;
|
||||||
|
cerr << " -o print warnings for temporaries which are too large" << endl;
|
||||||
cerr << " -DNAME=VALUE defines a preprocessor macro NAME with value VALUE" << endl;
|
cerr << " -DNAME=VALUE defines a preprocessor macro NAME with value VALUE" << endl;
|
||||||
exit(2);
|
exit(2);
|
||||||
}
|
}
|
||||||
|
@ -2935,6 +2994,7 @@ int main(int argc,char **argv)
|
||||||
bool enableAllNopWarning = false;
|
bool enableAllNopWarning = false;
|
||||||
bool enableDeadTempWarning = false;
|
bool enableDeadTempWarning = false;
|
||||||
bool enforceLocalKeyWord = false;
|
bool enforceLocalKeyWord = false;
|
||||||
|
bool largeTemporaryWarning = false;
|
||||||
|
|
||||||
bool compileAll = false;
|
bool compileAll = false;
|
||||||
|
|
||||||
|
@ -2966,6 +3026,8 @@ int main(int argc,char **argv)
|
||||||
enableDeadTempWarning = true;
|
enableDeadTempWarning = true;
|
||||||
else if (argv[i][1] == 'e')
|
else if (argv[i][1] == 'e')
|
||||||
enforceLocalKeyWord = true;
|
enforceLocalKeyWord = true;
|
||||||
|
else if (argv[i][1] == 'o')
|
||||||
|
largeTemporaryWarning = true;
|
||||||
#ifdef YYDEBUG
|
#ifdef YYDEBUG
|
||||||
else if (argv[i][1] == 'x')
|
else if (argv[i][1] == 'x')
|
||||||
yydebug = 1; // Debug option
|
yydebug = 1; // Debug option
|
||||||
|
@ -2998,7 +3060,7 @@ int main(int argc,char **argv)
|
||||||
SleighCompile compiler;
|
SleighCompile compiler;
|
||||||
initCompiler(compiler, defines, enableUnnecessaryPcodeWarning,
|
initCompiler(compiler, defines, enableUnnecessaryPcodeWarning,
|
||||||
disableLenientConflict, enableAllCollisionWarning, enableAllNopWarning,
|
disableLenientConflict, enableAllCollisionWarning, enableAllNopWarning,
|
||||||
enableDeadTempWarning, enforceLocalKeyWord);
|
enableDeadTempWarning, enforceLocalKeyWord,largeTemporaryWarning);
|
||||||
retval = run_compilation(slaspec.c_str(),sla.c_str(),compiler);
|
retval = run_compilation(slaspec.c_str(),sla.c_str(),compiler);
|
||||||
if (retval != 0) {
|
if (retval != 0) {
|
||||||
return retval; // stop on first error
|
return retval; // stop on first error
|
||||||
|
@ -3035,7 +3097,7 @@ int main(int argc,char **argv)
|
||||||
SleighCompile compiler;
|
SleighCompile compiler;
|
||||||
initCompiler(compiler, defines, enableUnnecessaryPcodeWarning,
|
initCompiler(compiler, defines, enableUnnecessaryPcodeWarning,
|
||||||
disableLenientConflict, enableAllCollisionWarning, enableAllNopWarning,
|
disableLenientConflict, enableAllCollisionWarning, enableAllNopWarning,
|
||||||
enableDeadTempWarning, enforceLocalKeyWord);
|
enableDeadTempWarning, enforceLocalKeyWord,largeTemporaryWarning);
|
||||||
|
|
||||||
if (i < argc - 1) {
|
if (i < argc - 1) {
|
||||||
string fileoutExamine(argv[i+1]);
|
string fileoutExamine(argv[i+1]);
|
||||||
|
|
|
@ -97,8 +97,10 @@ class ConsistencyChecker {
|
||||||
int4 unnecessarypcode;
|
int4 unnecessarypcode;
|
||||||
int4 readnowrite;
|
int4 readnowrite;
|
||||||
int4 writenoread;
|
int4 writenoread;
|
||||||
|
int4 largetemp;
|
||||||
bool printextwarning;
|
bool printextwarning;
|
||||||
bool printdeadwarning;
|
bool printdeadwarning;
|
||||||
|
bool printlargetempwarning;
|
||||||
SubtableSymbol *root_symbol;
|
SubtableSymbol *root_symbol;
|
||||||
vector<SubtableSymbol *> postorder;
|
vector<SubtableSymbol *> postorder;
|
||||||
map<SubtableSymbol *,int4> sizemap; // Sizes associated with tables
|
map<SubtableSymbol *,int4> sizemap; // Sizes associated with tables
|
||||||
|
@ -109,6 +111,8 @@ class ConsistencyChecker {
|
||||||
bool checkOpMisuse(OpTpl *op,Constructor *ct);
|
bool checkOpMisuse(OpTpl *op,Constructor *ct);
|
||||||
bool sizeRestriction(OpTpl *op,Constructor *ct);
|
bool sizeRestriction(OpTpl *op,Constructor *ct);
|
||||||
bool checkConstructorSection(Constructor *ct,ConstructTpl *cttpl);
|
bool checkConstructorSection(Constructor *ct,ConstructTpl *cttpl);
|
||||||
|
bool hasLargeTemporary(OpTpl *op);
|
||||||
|
bool isTemporaryAndTooBig(VarnodeTpl *vn);
|
||||||
bool checkVarnodeTruncation(Constructor *ct,int4 slot,OpTpl *op,VarnodeTpl *vn,bool isbigendian);
|
bool checkVarnodeTruncation(Constructor *ct,int4 slot,OpTpl *op,VarnodeTpl *vn,bool isbigendian);
|
||||||
bool checkSectionTruncations(Constructor *ct,ConstructTpl *cttpl,bool isbigendian);
|
bool checkSectionTruncations(Constructor *ct,ConstructTpl *cttpl,bool isbigendian);
|
||||||
bool checkSubtable(SubtableSymbol *sym);
|
bool checkSubtable(SubtableSymbol *sym);
|
||||||
|
@ -125,15 +129,17 @@ class ConsistencyChecker {
|
||||||
OptimizeRecord *findValidRule(Constructor *ct,map<uintb,OptimizeRecord> &recs) const;
|
OptimizeRecord *findValidRule(Constructor *ct,map<uintb,OptimizeRecord> &recs) const;
|
||||||
void applyOptimization(Constructor *ct,const OptimizeRecord &rec);
|
void applyOptimization(Constructor *ct,const OptimizeRecord &rec);
|
||||||
void checkUnusedTemps(Constructor *ct,const map<uintb,OptimizeRecord> &recs);
|
void checkUnusedTemps(Constructor *ct,const map<uintb,OptimizeRecord> &recs);
|
||||||
|
void checkLargeTemporaries(Constructor *ct);
|
||||||
void optimize(Constructor *ct);
|
void optimize(Constructor *ct);
|
||||||
public:
|
public:
|
||||||
ConsistencyChecker(SleighCompile *sleigh, SubtableSymbol *rt,bool unnecessary,bool warndead);
|
ConsistencyChecker(SleighCompile *sleigh, SubtableSymbol *rt,bool unnecessary,bool warndead, bool warnlargetemp);
|
||||||
bool test(void);
|
bool test(void);
|
||||||
bool testTruncations(bool isbigendian);
|
bool testTruncations(bool isbigendian);
|
||||||
void optimizeAll(void);
|
void optimizeAll(void);
|
||||||
int4 getNumUnnecessaryPcode(void) const { return unnecessarypcode; }
|
int4 getNumUnnecessaryPcode(void) const { return unnecessarypcode; }
|
||||||
int4 getNumReadNoWrite(void) const { return readnowrite; }
|
int4 getNumReadNoWrite(void) const { return readnowrite; }
|
||||||
int4 getNumWriteNoRead(void) const { return writenoread; }
|
int4 getNumWriteNoRead(void) const { return writenoread; }
|
||||||
|
int4 getNumLargeTemporaries(void) const {return largetemp;}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FieldContext {
|
struct FieldContext {
|
||||||
|
@ -200,6 +206,7 @@ private:
|
||||||
bool warnunnecessarypcode; // True if we warn of unnecessary ZEXT or SEXT
|
bool warnunnecessarypcode; // True if we warn of unnecessary ZEXT or SEXT
|
||||||
bool warndeadtemps; // True if we warn of temporaries that are written but not read
|
bool warndeadtemps; // True if we warn of temporaries that are written but not read
|
||||||
bool lenientconflicterrors; // True if we ignore most pattern conflict errors
|
bool lenientconflicterrors; // True if we ignore most pattern conflict errors
|
||||||
|
bool largetemporarywarning; // True if we warn about temporaries larger than SleighBase::MAX_UNIQUE_SIZE
|
||||||
bool warnalllocalcollisions; // True if local export collisions generate individual warnings
|
bool warnalllocalcollisions; // True if local export collisions generate individual warnings
|
||||||
bool warnallnops; // True if pcode NOPs generate individual warnings
|
bool warnallnops; // True if pcode NOPs generate individual warnings
|
||||||
vector<string> noplist; // List of individual NOP warnings
|
vector<string> noplist; // List of individual NOP warnings
|
||||||
|
@ -244,6 +251,7 @@ public:
|
||||||
void setUnnecessaryPcodeWarning(bool val) { warnunnecessarypcode = val; }
|
void setUnnecessaryPcodeWarning(bool val) { warnunnecessarypcode = val; }
|
||||||
void setDeadTempWarning(bool val) { warndeadtemps = val; }
|
void setDeadTempWarning(bool val) { warndeadtemps = val; }
|
||||||
void setEnforceLocalKeyWord(bool val) { pcode.setEnforceLocalKey(val); }
|
void setEnforceLocalKeyWord(bool val) { pcode.setEnforceLocalKey(val); }
|
||||||
|
void setLargeTemporaryWarning (bool val) {largetemporarywarning = val;}
|
||||||
void setLenientConflict(bool val) { lenientconflicterrors = val; }
|
void setLenientConflict(bool val) { lenientconflicterrors = val; }
|
||||||
void setLocalCollisionWarning(bool val) { warnalllocalcollisions = val; }
|
void setLocalCollisionWarning(bool val) { warnalllocalcollisions = val; }
|
||||||
void setAllNopWarning(bool val) { warnallnops = val; }
|
void setAllNopWarning(bool val) { warnallnops = val; }
|
||||||
|
|
|
@ -33,6 +33,7 @@ import ghidra.app.plugin.processors.sleigh.expression.ContextField;
|
||||||
import ghidra.app.plugin.processors.sleigh.expression.PatternValue;
|
import ghidra.app.plugin.processors.sleigh.expression.PatternValue;
|
||||||
import ghidra.app.plugin.processors.sleigh.symbol.*;
|
import ghidra.app.plugin.processors.sleigh.symbol.*;
|
||||||
import ghidra.framework.Application;
|
import ghidra.framework.Application;
|
||||||
|
import ghidra.pcodeCPort.sleighbase.SleighBase;
|
||||||
import ghidra.pcodeCPort.slgh_compile.SleighCompileLauncher;
|
import ghidra.pcodeCPort.slgh_compile.SleighCompileLauncher;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.lang.*;
|
import ghidra.program.model.lang.*;
|
||||||
|
@ -42,8 +43,8 @@ import ghidra.program.model.mem.MemoryAccessException;
|
||||||
import ghidra.program.model.symbol.SourceType;
|
import ghidra.program.model.symbol.SourceType;
|
||||||
import ghidra.program.model.util.AddressLabelInfo;
|
import ghidra.program.model.util.AddressLabelInfo;
|
||||||
import ghidra.program.model.util.ProcessorSymbolType;
|
import ghidra.program.model.util.ProcessorSymbolType;
|
||||||
import ghidra.sleigh.grammar.SourceFileIndexer;
|
|
||||||
import ghidra.sleigh.grammar.SleighPreprocessor;
|
import ghidra.sleigh.grammar.SleighPreprocessor;
|
||||||
|
import ghidra.sleigh.grammar.SourceFileIndexer;
|
||||||
import ghidra.util.*;
|
import ghidra.util.*;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
import ghidra.util.xml.SpecXmlUtils;
|
import ghidra.util.xml.SpecXmlUtils;
|
||||||
|
@ -54,17 +55,14 @@ import utilities.util.FileUtilities;
|
||||||
public class SleighLanguage implements Language {
|
public class SleighLanguage implements Language {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NOTE: The value of {@link SleighLanguage#SLA_FORMAT_VERSION} must match that of
|
* SLA_FORMAT_VERSION will be incremented whenever the format of the .sla
|
||||||
* {@link ghidra.pcodeCPort.sleighbase.SleighBase#SLA_FORMAT_VERSION}!.
|
|
||||||
* <p>
|
|
||||||
* SLA_FORMAT_VERSION should be incremented whenever the format of the .sla
|
|
||||||
* files change.
|
* files change.
|
||||||
* <p>
|
* <p>
|
||||||
* Version 3: October 2020: added source file information for each constructor. <br>
|
* Version 3: January 2021: added source file information for each constructor. <br>
|
||||||
* Version 2: April 2019: Changed numbering of Overlay spaces.<br>
|
* Version 2: April 2019: Changed numbering of Overlay spaces.<br>
|
||||||
* Version 1: Initial version.<br>
|
* Version 1: Initial version.<br>
|
||||||
*/
|
*/
|
||||||
public static final int SLA_FORMAT_VERSION = 3;
|
public static final int SLA_FORMAT_VERSION = SleighBase.SLA_FORMAT_VERSION;
|
||||||
private Map<CompilerSpecID, SleighCompilerSpecDescription> compilerSpecDescriptions;
|
private Map<CompilerSpecID, SleighCompilerSpecDescription> compilerSpecDescriptions;
|
||||||
private HashMap<CompilerSpecID, BasicCompilerSpec> compilerSpecs;
|
private HashMap<CompilerSpecID, BasicCompilerSpec> compilerSpecs;
|
||||||
private List<InjectPayloadSleigh> additionalInject = null;
|
private List<InjectPayloadSleigh> additionalInject = null;
|
||||||
|
|
|
@ -35,10 +35,14 @@ public abstract class SleighBase extends Translate implements NamedSymbolProvide
|
||||||
// implementation
|
// implementation
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Note: The value of {@link SleighBase#SLA_FORMAT_VERSION} must match
|
* Note: The values of {@link #SLA_FORMAT_VERSION} and {@link #MAX_UNIQUE_SIZE}
|
||||||
* {@link ghidra.app.plugin.processors.sleigh.SleighLanguage#SLA_FORMAT_VERSION}.
|
* must match the corresponding values defined by sleighbase.cc
|
||||||
*/
|
*/
|
||||||
public static final int SLA_FORMAT_VERSION = 3;
|
public static final int SLA_FORMAT_VERSION = 3;
|
||||||
|
|
||||||
|
public static final long MAX_UNIQUE_SIZE = 128; //Maximum size of a varnode in the unique space.
|
||||||
|
//Should match value in sleighbase.cc
|
||||||
|
|
||||||
private VectorSTL<String> userop = new VectorSTL<>();
|
private VectorSTL<String> userop = new VectorSTL<>();
|
||||||
private address_set varnode_xref = new address_set(); // Cross-reference registers by address
|
private address_set varnode_xref = new address_set(); // Cross-reference registers by address
|
||||||
protected SubtableSymbol root;
|
protected SubtableSymbol root;
|
||||||
|
|
|
@ -23,16 +23,22 @@ import ghidra.pcodeCPort.opcodes.OpCode;
|
||||||
import ghidra.pcodeCPort.semantics.*;
|
import ghidra.pcodeCPort.semantics.*;
|
||||||
import ghidra.pcodeCPort.semantics.ConstTpl.const_type;
|
import ghidra.pcodeCPort.semantics.ConstTpl.const_type;
|
||||||
import ghidra.pcodeCPort.semantics.ConstTpl.v_field;
|
import ghidra.pcodeCPort.semantics.ConstTpl.v_field;
|
||||||
|
import ghidra.pcodeCPort.sleighbase.SleighBase;
|
||||||
import ghidra.pcodeCPort.slghsymbol.*;
|
import ghidra.pcodeCPort.slghsymbol.*;
|
||||||
import ghidra.pcodeCPort.space.AddrSpace;
|
import ghidra.pcodeCPort.space.AddrSpace;
|
||||||
|
import ghidra.util.Msg;
|
||||||
|
|
||||||
class ConsistencyChecker {
|
class ConsistencyChecker {
|
||||||
|
|
||||||
int unnecessarypcode;
|
int unnecessarypcode;
|
||||||
int readnowrite;
|
int readnowrite;
|
||||||
int writenoread;
|
int writenoread;
|
||||||
|
// number of constructors using a temporary varnode larger than SleighBase.MAX_UNIQUE_SIZE
|
||||||
|
int largetemp;
|
||||||
boolean printextwarning;
|
boolean printextwarning;
|
||||||
boolean printdeadwarning;
|
boolean printdeadwarning;
|
||||||
|
//if true, print information about constructors using temporary varnodes larger than SleighBase.MAX_UNIQUE_SIZE
|
||||||
|
boolean printlargetempwarning;
|
||||||
SleighCompile compiler;
|
SleighCompile compiler;
|
||||||
SubtableSymbol root_symbol;
|
SubtableSymbol root_symbol;
|
||||||
VectorSTL<SubtableSymbol> postorder = new VectorSTL<>();
|
VectorSTL<SubtableSymbol> postorder = new VectorSTL<>();
|
||||||
|
@ -98,7 +104,7 @@ class ConsistencyChecker {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
printOpError(op, ct, -1, 0, "Input and output sizes must match; " +
|
printOpError(op, ct, -1, 0, "Input and output sizes must match; " +
|
||||||
op.getIn(0).getSize() + " != " + op.getOut().getSize());
|
op.getIn(0).getSize() + " != " + op.getOut().getSize());
|
||||||
return false;
|
return false;
|
||||||
case CPUI_INT_ADD:
|
case CPUI_INT_ADD:
|
||||||
case CPUI_INT_SUB:
|
case CPUI_INT_SUB:
|
||||||
|
@ -493,9 +499,9 @@ class ConsistencyChecker {
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append("Size restriction error in table '")
|
sb.append("Size restriction error in table '")
|
||||||
.append(sym.getName())
|
.append(sym.getName())
|
||||||
.append("' in constructor at ").append(ct.location)
|
.append("' in constructor at ").append(ct.location)
|
||||||
.append("\n");
|
.append("\n");
|
||||||
|
|
||||||
|
|
||||||
sb.append(" Problem");
|
sb.append(" Problem");
|
||||||
|
@ -637,6 +643,38 @@ class ConsistencyChecker {
|
||||||
return testresult;
|
return testresult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true precisely when {@code opTpl} uses a {@link VarnodeTpl} in
|
||||||
|
* the unique space whose size is larger than {@link SleighBase#MAX_UNIQUE_SIZE}.
|
||||||
|
* Note that this method returns as soon as one large {@link VarnodeTpl} is found.
|
||||||
|
* @param opTpl the op to check
|
||||||
|
* @return true if {@code opTpl} uses a large temporary varnode
|
||||||
|
*/
|
||||||
|
boolean hasLargeTemporary(OpTpl opTpl) {
|
||||||
|
VarnodeTpl out = opTpl.getOut();
|
||||||
|
if (out != null && isTemporaryAndTooBig(out)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < opTpl.numInput(); ++i) {
|
||||||
|
VarnodeTpl in = opTpl.getIn(i);
|
||||||
|
if (isTemporaryAndTooBig(in)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true precisely when {@code vn} is in the unique space
|
||||||
|
* and has a size larger than {@link SleighBase#MAX_UNIQUE_SIZE}.
|
||||||
|
* @param vn varnode template to check
|
||||||
|
* @return true if it uses a large temporary
|
||||||
|
*/
|
||||||
|
boolean isTemporaryAndTooBig(VarnodeTpl vn) {
|
||||||
|
return vn.getSpace().isUniqueSpace() &&
|
||||||
|
vn.getSize().getReal() > SleighBase.MAX_UNIQUE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
boolean checkVarnodeTruncation(Constructor ct,int slot,OpTpl op,VarnodeTpl vn,boolean isbigendian) {
|
boolean checkVarnodeTruncation(Constructor ct,int slot,OpTpl op,VarnodeTpl vn,boolean isbigendian) {
|
||||||
ConstTpl off = vn.getOffset();
|
ConstTpl off = vn.getOffset();
|
||||||
if (off.getType() != const_type.handle) {
|
if (off.getType() != const_type.handle) {
|
||||||
|
@ -1131,6 +1169,25 @@ class ConsistencyChecker {
|
||||||
iter.increment();
|
iter.increment();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks {@code ct} to see whether it contains an {@link OpTpl} which
|
||||||
|
* uses a varnode in the unique space which is larger than {@link SleighBase#MAX_UNIQUE_SIZE}.
|
||||||
|
* @param ct constructor to check
|
||||||
|
*/
|
||||||
|
void checkLargeTemporaries(Constructor ct) {
|
||||||
|
ConstructTpl ctTpl = ct.getTempl();
|
||||||
|
VectorSTL<OpTpl> ops = ctTpl.getOpvec();
|
||||||
|
for (IteratorSTL<OpTpl> iter = ops.begin(); !iter.isEnd(); iter.increment()) {
|
||||||
|
if (hasLargeTemporary(iter.get())) {
|
||||||
|
if (printlargetempwarning) {
|
||||||
|
compiler.reportWarning(ct.location, "Constructor uses temporary varnode larger than " + SleighBase.MAX_UNIQUE_SIZE + " bytes.");
|
||||||
|
}
|
||||||
|
largetemp++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void optimize(Constructor ct) {
|
void optimize(Constructor ct) {
|
||||||
OptimizeRecord currec;
|
OptimizeRecord currec;
|
||||||
|
@ -1149,16 +1206,21 @@ class ConsistencyChecker {
|
||||||
}
|
}
|
||||||
while (currec != null);
|
while (currec != null);
|
||||||
checkUnusedTemps(ct, recs);
|
checkUnusedTemps(ct, recs);
|
||||||
|
checkLargeTemporaries(ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConsistencyChecker(SleighCompile cp, SubtableSymbol rt, boolean unnecessary, boolean warndead) {
|
ConsistencyChecker(SleighCompile cp, SubtableSymbol rt, boolean unnecessary, boolean warndead, boolean warnlargetemp) {
|
||||||
compiler = cp;
|
compiler = cp;
|
||||||
root_symbol = rt;
|
root_symbol = rt;
|
||||||
unnecessarypcode = 0;
|
unnecessarypcode = 0;
|
||||||
readnowrite = 0;
|
readnowrite = 0;
|
||||||
writenoread = 0;
|
writenoread = 0;
|
||||||
|
//number of constructors which reference a temporary varnode larger than SleighBase.MAX_UNIQUE_SIZE
|
||||||
|
largetemp = 0;
|
||||||
printextwarning = unnecessary;
|
printextwarning = unnecessary;
|
||||||
printdeadwarning = warndead;
|
printdeadwarning = warndead;
|
||||||
|
//whether to print information about constructors which reference large temporary varnodes
|
||||||
|
printlargetempwarning = warnlargetemp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Main entry point for size consistency check
|
// Main entry point for size consistency check
|
||||||
|
@ -1229,4 +1291,13 @@ class ConsistencyChecker {
|
||||||
int getNumWriteNoRead() {
|
int getNumWriteNoRead() {
|
||||||
return writenoread;
|
return writenoread;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of constructors which reference a varnode in the
|
||||||
|
* unique space with size larger than {@link SleighBase#MAX_UNIQUE_SIZE}.
|
||||||
|
* @return num constructors with large temp varnodes
|
||||||
|
*/
|
||||||
|
int getNumLargeTemporaries() {
|
||||||
|
return largetemp;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -254,6 +254,7 @@ public class SleighCompile extends SleighBase {
|
||||||
boolean warnunusedfields; // True if fields are defined but not used
|
boolean warnunusedfields; // True if fields are defined but not used
|
||||||
boolean enforcelocalkeyword; // Force slaspec to use 'local' keyword when defining temporary varnodes
|
boolean enforcelocalkeyword; // Force slaspec to use 'local' keyword when defining temporary varnodes
|
||||||
boolean lenientconflicterrors; // True if we ignore most pattern conflict errors
|
boolean lenientconflicterrors; // True if we ignore most pattern conflict errors
|
||||||
|
boolean largetemporarywarning; // True if we warn about temporaries larger than SleighBase.MAX_UNIQUE_SIZE
|
||||||
public boolean warnalllocalcollisions;
|
public boolean warnalllocalcollisions;
|
||||||
public boolean warnallnops;
|
public boolean warnallnops;
|
||||||
public VectorSTL<String> noplist = new VectorSTL<>();
|
public VectorSTL<String> noplist = new VectorSTL<>();
|
||||||
|
@ -498,7 +499,7 @@ public class SleighCompile extends SleighBase {
|
||||||
void checkConsistency() {
|
void checkConsistency() {
|
||||||
entry("checkConsistency");
|
entry("checkConsistency");
|
||||||
ConsistencyChecker checker =
|
ConsistencyChecker checker =
|
||||||
new ConsistencyChecker(this, root, warnunnecessarypcode, warndeadtemps);
|
new ConsistencyChecker(this, root, warnunnecessarypcode, warndeadtemps, largetemporarywarning);
|
||||||
|
|
||||||
if (!checker.test()) {
|
if (!checker.test()) {
|
||||||
errors += 1;
|
errors += 1;
|
||||||
|
@ -523,6 +524,11 @@ public class SleighCompile extends SleighBase {
|
||||||
" operations wrote to temporaries that were not read");
|
" operations wrote to temporaries that were not read");
|
||||||
reportWarning(null, "Use -t switch to list each individually");
|
reportWarning(null, "Use -t switch to list each individually");
|
||||||
}
|
}
|
||||||
|
if ((!largetemporarywarning) && checker.getNumLargeTemporaries() > 0) {
|
||||||
|
reportWarning(null, checker.getNumLargeTemporaries() +
|
||||||
|
" constructors contain temporaries larger than " + SleighBase.MAX_UNIQUE_SIZE + " bytes.");
|
||||||
|
reportWarning(null, "Use -o switch to list each individually.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int findCollision(Map<Long, Integer> local2Operand, ArrayList<Long> locals,
|
static int findCollision(Map<Long, Integer> local2Operand, ArrayList<Long> locals,
|
||||||
|
@ -686,7 +692,7 @@ public class SleighCompile extends SleighBase {
|
||||||
long getUniqueAddr() {
|
long getUniqueAddr() {
|
||||||
entry("getUniqueAddr");
|
entry("getUniqueAddr");
|
||||||
long base = getUniqueBase();
|
long base = getUniqueBase();
|
||||||
setUniqueBase(base + 16); // Should be maximum size of a unique
|
setUniqueBase(base + MAX_UNIQUE_SIZE);
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -710,6 +716,17 @@ public class SleighCompile extends SleighBase {
|
||||||
enforcelocalkeyword = val;
|
enforcelocalkeyword = val;
|
||||||
pcode.setEnforceLocalKey(val);
|
pcode.setEnforceLocalKey(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether or not to print out warning info about
|
||||||
|
* {@link Constructor}s which reference varnodes in the
|
||||||
|
* unique space larger than {@link SleighBase#MAX_UNIQUE_SIZE}.
|
||||||
|
* @param val whether to print info about contructors using large varnodes
|
||||||
|
*/
|
||||||
|
void setLargeTemporaryWarning(boolean val) {
|
||||||
|
entry("setLargeTemporaryWarning",val);
|
||||||
|
largetemporarywarning = val;
|
||||||
|
}
|
||||||
|
|
||||||
void setLenientConflict(boolean val) {
|
void setLenientConflict(boolean val) {
|
||||||
entry("setLenientConflict", val);
|
entry("setLenientConflict", val);
|
||||||
|
|
|
@ -49,7 +49,7 @@ public class SleighCompileLauncher implements GhidraLaunchable {
|
||||||
private static void initCompiler(SleighCompile compiler, Map<String, String> preprocs,
|
private static void initCompiler(SleighCompile compiler, Map<String, String> preprocs,
|
||||||
boolean unnecessaryPcodeWarning, boolean lenientConflict, boolean allCollisionWarning,
|
boolean unnecessaryPcodeWarning, boolean lenientConflict, boolean allCollisionWarning,
|
||||||
boolean allNopWarning, boolean deadTempWarning, boolean unusedFieldWarning,
|
boolean allNopWarning, boolean deadTempWarning, boolean unusedFieldWarning,
|
||||||
boolean enforceLocalKeyWord) {
|
boolean enforceLocalKeyWord, boolean largeTemporaryWarning) {
|
||||||
Set<Entry<String, String>> entrySet = preprocs.entrySet();
|
Set<Entry<String, String>> entrySet = preprocs.entrySet();
|
||||||
for (Entry<String, String> entry : entrySet) {
|
for (Entry<String, String> entry : entrySet) {
|
||||||
compiler.setPreprocValue(entry.getKey(), entry.getValue());
|
compiler.setPreprocValue(entry.getKey(), entry.getValue());
|
||||||
|
@ -61,6 +61,7 @@ public class SleighCompileLauncher implements GhidraLaunchable {
|
||||||
compiler.setDeadTempWarning(deadTempWarning);
|
compiler.setDeadTempWarning(deadTempWarning);
|
||||||
compiler.setUnusedFieldWarning(unusedFieldWarning);
|
compiler.setUnusedFieldWarning(unusedFieldWarning);
|
||||||
compiler.setEnforceLocalKeyWord(enforceLocalKeyWord);
|
compiler.setEnforceLocalKeyWord(enforceLocalKeyWord);
|
||||||
|
compiler.setLargeTemporaryWarning(largeTemporaryWarning);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -111,6 +112,7 @@ public class SleighCompileLauncher implements GhidraLaunchable {
|
||||||
Msg.info(SleighCompile.class, " -e enforce use of 'local' keyword for temporaries");
|
Msg.info(SleighCompile.class, " -e enforce use of 'local' keyword for temporaries");
|
||||||
Msg.info(SleighCompile.class, " -c print warnings for all constructors with colliding operands");
|
Msg.info(SleighCompile.class, " -c print warnings for all constructors with colliding operands");
|
||||||
Msg.info(SleighCompile.class, " -f print warnings for unused token fields");
|
Msg.info(SleighCompile.class, " -f print warnings for unused token fields");
|
||||||
|
Msg.info(SleighCompile.class, " -o print warnings for temporaries which are too large");
|
||||||
Msg.info(SleighCompile.class, " -DNAME=VALUE defines a preprocessor macro NAME with value VALUE (option may be repeated)");
|
Msg.info(SleighCompile.class, " -DNAME=VALUE defines a preprocessor macro NAME with value VALUE (option may be repeated)");
|
||||||
Msg.info(SleighCompile.class, " -dMODULE defines a preprocessor macro MODULE with a value of its module path (option may be repeated)");
|
Msg.info(SleighCompile.class, " -dMODULE defines a preprocessor macro MODULE with a value of its module path (option may be repeated)");
|
||||||
Msg.info(SleighCompile.class, " -i <options-file> inject options from specified file");
|
Msg.info(SleighCompile.class, " -i <options-file> inject options from specified file");
|
||||||
|
@ -125,6 +127,7 @@ public class SleighCompileLauncher implements GhidraLaunchable {
|
||||||
boolean deadTempWarning = false;
|
boolean deadTempWarning = false;
|
||||||
boolean enforceLocalKeyWord = false;
|
boolean enforceLocalKeyWord = false;
|
||||||
boolean unusedFieldWarning = false;
|
boolean unusedFieldWarning = false;
|
||||||
|
boolean largeTemporaryWarning = false;
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < args.length; ++i) {
|
for (i = 0; i < args.length; ++i) {
|
||||||
|
@ -185,6 +188,9 @@ public class SleighCompileLauncher implements GhidraLaunchable {
|
||||||
else if (args[i].charAt(1) == 'a') {
|
else if (args[i].charAt(1) == 'a') {
|
||||||
allMode = true;
|
allMode = true;
|
||||||
}
|
}
|
||||||
|
else if (args[i].charAt(1) == 'o') {
|
||||||
|
largeTemporaryWarning = true;
|
||||||
|
}
|
||||||
else if (args[i].charAt(1) == 'x') {
|
else if (args[i].charAt(1) == 'x') {
|
||||||
SleighCompile.yydebug = true; // Debug option
|
SleighCompile.yydebug = true; // Debug option
|
||||||
}
|
}
|
||||||
|
@ -219,7 +225,7 @@ public class SleighCompileLauncher implements GhidraLaunchable {
|
||||||
SleighCompile compiler = new SleighCompile();
|
SleighCompile compiler = new SleighCompile();
|
||||||
initCompiler(compiler, preprocs, unnecessaryPcodeWarning, lenientConflict,
|
initCompiler(compiler, preprocs, unnecessaryPcodeWarning, lenientConflict,
|
||||||
allCollisionWarning, allNopWarning, deadTempWarning, unusedFieldWarning,
|
allCollisionWarning, allNopWarning, deadTempWarning, unusedFieldWarning,
|
||||||
enforceLocalKeyWord);
|
enforceLocalKeyWord, largeTemporaryWarning);
|
||||||
|
|
||||||
String outname = input.getName().replace(".slaspec", ".sla");
|
String outname = input.getName().replace(".slaspec", ".sla");
|
||||||
File output = new File(input.getParent(), outname);
|
File output = new File(input.getParent(), outname);
|
||||||
|
@ -248,7 +254,7 @@ public class SleighCompileLauncher implements GhidraLaunchable {
|
||||||
SleighCompile compiler = new SleighCompile();
|
SleighCompile compiler = new SleighCompile();
|
||||||
initCompiler(compiler, preprocs, unnecessaryPcodeWarning, lenientConflict,
|
initCompiler(compiler, preprocs, unnecessaryPcodeWarning, lenientConflict,
|
||||||
allCollisionWarning, allNopWarning, deadTempWarning, unusedFieldWarning,
|
allCollisionWarning, allNopWarning, deadTempWarning, unusedFieldWarning,
|
||||||
enforceLocalKeyWord);
|
enforceLocalKeyWord, largeTemporaryWarning);
|
||||||
if (i == args.length) {
|
if (i == args.length) {
|
||||||
Msg.error(SleighCompile.class, "Missing input file name");
|
Msg.error(SleighCompile.class, "Missing input file name");
|
||||||
return 1;
|
return 1;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue