Check for case sensitivity in register names

This commit is contained in:
caheckman 2021-05-24 18:49:03 -04:00
parent fca4fd4844
commit faf2909910
14 changed files with 1607 additions and 808 deletions

View file

@ -457,7 +457,7 @@ RECURSIVE = NO
# excluded from the INPUT source files. This way you can easily exclude a
# subdirectory from a directory tree whose root is specified with the INPUT tag.
EXCLUDE = unify.hh unify.cc rulecompile.hh rulecompile.cc slgh_compile.hh slgh_compile.cc slghparse.cc slghparse.hh slghscan.cc slghpattern.hh slghpattern.cc slghpatexpress.hh slghpatexpress.cc slghsymbol.hh slghsymbol.cc codedata.hh codedata.cc semantics.hh semantics.cc grammar.hh grammar.cc callgraph.hh callgraph.cc filemanage.hh filemanage.cc graph.hh graph.cc loadimage_bfd.hh loadimage_bfd.cc pcodecompile.cc pcodecompile.hh pcodeparse.hh pcodeparse.cc inject_sleigh.hh inject_sleigh.cc context.hh context.cc consolemain.cc sleighexample.cc xml.cc double.hh double.cc paramid.hh paramid.cc prefersplit.hh prefersplit.cc
EXCLUDE = unify.hh unify.cc rulecompile.hh rulecompile.cc slghparse.cc slghparse.hh slghscan.cc slghpattern.hh slghpattern.cc slghpatexpress.hh slghpatexpress.cc slghsymbol.hh slghsymbol.cc codedata.hh codedata.cc semantics.hh semantics.cc grammar.hh grammar.cc callgraph.hh callgraph.cc filemanage.hh filemanage.cc graph.hh graph.cc loadimage_bfd.hh loadimage_bfd.cc pcodecompile.cc pcodecompile.hh pcodeparse.hh pcodeparse.cc inject_sleigh.hh inject_sleigh.cc context.hh context.cc consolemain.cc sleighexample.cc xml.cc double.hh double.cc paramid.hh paramid.cc prefersplit.hh prefersplit.cc
# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
# directories that are symbolic links (a Unix filesystem feature) are excluded

View file

@ -41,8 +41,6 @@ public:
GhidraTranslate(ArchitectureGhidra *g) { glb = g; } ///< Constructor
virtual void initialize(DocumentStorage &store);
virtual void addRegister(const string &nm,AddrSpace *base,uintb offset,int4 size) {
throw LowlevelError("Cannot add register name into GHIDRA through this interface"); }
virtual const VarnodeData &getRegister(const string &nm) const;
virtual string getRegisterName(AddrSpace *base,uintb off,int4 size) const;
virtual void getAllRegisters(map<VarnodeData,string> &reglist) const {

View file

@ -61,7 +61,6 @@ public:
class DummyTranslate : public Translate {
public:
virtual void initialize(DocumentStorage &store) {}
virtual void addRegister(const string &nm,AddrSpace *base,uintb offset,int4 size) {}
virtual const VarnodeData &getRegister(const string &nm) const { throw LowlevelError("Cannot add register to DummyTranslate"); }
virtual string getRegisterName(AddrSpace *base,uintb off,int4 size) const { return ""; }
virtual void getAllRegisters(map<VarnodeData,string> &reglist) const {}

View file

@ -124,13 +124,6 @@ void SleighBase::reregisterContext(void)
}
}
void SleighBase::addRegister(const string &nm,AddrSpace *base,uintb offset,int4 size)
{
VarnodeSymbol *sym = new VarnodeSymbol(nm,base,offset,size);
symtab.addSymbol(sym);
}
const VarnodeData &SleighBase::getRegister(const string &nm) const
{

View file

@ -73,7 +73,6 @@ public:
SleighBase(void); ///< Construct an uninitialized translator
bool isInitialized(void) const { return (root != (SubtableSymbol *)0); } ///< Return \b true if \b this is initialized
virtual ~SleighBase(void) {} ///< Destructor
virtual void addRegister(const string &nm,AddrSpace *base,uintb offset,int4 size);
virtual const VarnodeData &getRegister(const string &nm) const;
virtual string getRegisterName(AddrSpace *base,uintb off,int4 size) const;
virtual void getAllRegisters(map<VarnodeData,string> &reglist) const;

File diff suppressed because it is too large Load diff

View file

@ -13,66 +13,99 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/// \file slgh_compile.hh
/// \brief High-level control of the sleigh compilation process
#include "sleighbase.hh"
#include "pcodecompile.hh"
#include "filemanage.hh"
#include <iostream>
#include <sstream>
// High-level control of the sleigh compilation process
/// \brief A helper class to associate a \e named Constructor section with its symbol scope
///
/// A Constructor can contain multiple named sections of p-code. There is a \e main
/// section associated with the constructor, but other sections are possible and can
/// be accessed through the \b crossbuild directive, which allows their operations to be
/// incorporated into nearby instructions. During parsing of a SLEIGH file, \b this class
/// associates a named section with its dedicated symbol scope.
struct RtlPair {
ConstructTpl *section; // A p-code section
SymbolScope *scope; // and its associated symbol scope
RtlPair(void) { section = (ConstructTpl *)0; scope = (SymbolScope *)0; }
RtlPair(ConstructTpl *sec,SymbolScope *sc) { section = sec; scope = sc; }
ConstructTpl *section; ///< A named p-code section
SymbolScope *scope; ///< Symbol scope associated with the section
RtlPair(void) { section = (ConstructTpl *)0; scope = (SymbolScope *)0; } ///< Construct on empty pair
RtlPair(ConstructTpl *sec,SymbolScope *sc) { section = sec; scope = sc; } ///< Constructor
};
/// \brief A collection of \e named p-code sections for a single Constructor
///
/// A Constructor always has a \b main section of p-code (which may be empty).
/// Alternately a Constructor may define additional \e named sections of p-code.
/// Operations in these sections are emitted using the \b crossbuild directive and
/// can be incorporated into following instructions.
///
/// Internally different sections (RtlPair) are identified by index. A
/// SectionSymbol holds the section's name and its corresponding index.
class SectionVector {
int4 nextindex;
RtlPair main;
vector<RtlPair> named;
int4 nextindex; ///< Index of the section currently being parsed.
RtlPair main; ///< The main section
vector<RtlPair> named; ///< Named sections accessed by index
public:
SectionVector(ConstructTpl *rtl,SymbolScope *scope);
ConstructTpl *getMainSection(void) const { return main.section; }
ConstructTpl *getNamedSection(int4 index) const { return named[index].section; }
RtlPair getMainPair(void) const { return main; }
RtlPair getNamedPair(int4 i) const { return named[i]; }
void setNextIndex(int4 i) { nextindex = i; }
int4 getMaxId(void) const { return named.size(); }
void append(ConstructTpl *rtl,SymbolScope *scope);
SectionVector(ConstructTpl *rtl,SymbolScope *scope); ///< Constructor
ConstructTpl *getMainSection(void) const { return main.section; } ///< Get the \e main section
ConstructTpl *getNamedSection(int4 index) const { return named[index].section; } ///< Get a \e named section by index
RtlPair getMainPair(void) const { return main; } ///< Get the \e main section/namespace pair
RtlPair getNamedPair(int4 i) const { return named[i]; } ///< Get a \e named section/namespace pair by index
void setNextIndex(int4 i) { nextindex = i; } ///< Set the index of the currently parsing \e named section
int4 getMaxId(void) const { return named.size(); } ///< Get the maximum (exclusive) named section index
void append(ConstructTpl *rtl,SymbolScope *scope); ///< Add a new \e named section
};
struct SpaceQuality { // Qualities of an address space
enum { // Class of space
ramtype,
registertype
/// \brief Qualities associated (via parsing) with an address space
///
/// An object of this class accumulates properties of an address space as they
/// are parsed in the \b define statement prior to formally allocating the AddrSpace object.
struct SpaceQuality {
/// \brief The type of space being defined
enum {
ramtype, ///< An address space representing normal, indexed, memory
registertype ///< An address space containing registers
};
string name;
uint4 type;
uint4 size;
uint4 wordsize; // number of bytes in unit of the space
bool isdefault;
SpaceQuality(const string &nm);
string name; ///< Name of the address space
uint4 type; ///< Type of address space, \e ramtype or \e registertype
uint4 size; ///< Number of bytes required to index all bytes of the space
uint4 wordsize; ///< Number of bytes in an addressable unit of the space
bool isdefault; ///< \b true if the new address space will be the default
SpaceQuality(const string &nm); ///< Constructor
};
/// \brief Qualities associated (via parsing) with a token or context \b field
///
/// An object of this class accumulates properties of a field as they
/// are parsed in of a \b define \b token block prior to formally allocating the
/// TokenField or FieldContext object.
struct FieldQuality {
string name;
uint4 low,high;
bool signext;
bool flow;
bool hex;
FieldQuality(string *nm,uintb *l,uintb *h);
string name; ///< Name of the field
uint4 low; ///< The least significant bit of the field within the token
uint4 high; ///< The most significant bit of the field within the token
bool signext; ///< \b true if the field's value is signed
bool flow; ///< \b true if the context \b flows for this field.
bool hex; ///< \b true if the field value is displayed in hex
FieldQuality(string *nm,uintb *l,uintb *h); ///< Constructor
};
/// \brief Subtable, pattern, and context information applied across a \b with block
///
/// The header of a \b with block is applied to all constructors in the block. It
/// attaches each constructor to a specific subtable. A pattern expression and/or a
/// a series of context changes is attached to each constructor as well.
class WithBlock {
SubtableSymbol *ss;
PatternEquation *pateq;
vector<ContextChange *> contvec;
SubtableSymbol *ss; ///< Subtable containing each Constructor (or null for root table)
PatternEquation *pateq; ///< Pattern to prepend to each Constructor (or null)
vector<ContextChange *> contvec; ///< Context change to associate with each constructor (or null)
public:
WithBlock(void) { pateq = (PatternEquation *)0; }
void set(SubtableSymbol *s, PatternEquation *pq, vector<ContextChange *> *cvec);
~WithBlock(void);
WithBlock(void) { pateq = (PatternEquation *)0; } ///< Constructor
void set(SubtableSymbol *s, PatternEquation *pq, vector<ContextChange *> *cvec); ///< Set components of the header
~WithBlock(void); ///< Destructor
static PatternEquation *collectAndPrependPattern(const list<WithBlock> &stack, PatternEquation *pateq);
static vector<ContextChange *> *collectAndPrependContext(const list<WithBlock> &stack, vector<ContextChange *> *contvec);
static SubtableSymbol *getCurrentSubtable(const list<WithBlock> &stack);
@ -80,30 +113,53 @@ public:
class SleighCompile;
/// \brief Derive Varnode sizes and optimize p-code in SLEIGH Constructors
///
/// This class examines p-code parsed from a SLEIGH file and performs three main tasks:
/// - Enforcing size rules in Constructor p-code,
/// - Optimizing p-code within a Constructor, and
/// - Searching for other p-code validity violations
///
/// Many p-code operators require that their input and/or output operands are all the same size
/// or have other specific size restrictions on their operands. This class enforces those requirements.
///
/// This class performs limited optimization of p-code within a Constructor by performing COPY
/// propagation through \e temporary registers.
///
/// This class searches for unnecessary truncations and extensions, temporary varnodes that are either dead,
/// read before written, or that exceed the standard allocation size.
class ConsistencyChecker {
/// \brief Description of how a temporary register is being used within a Constructor
///
/// This counts reads and writes of the register. If the register is read only once, the
/// particular p-code op and input slot reading it is recorded. If the register is written
/// only once, the particular p-code op writing it is recorded.
struct OptimizeRecord {
int4 writeop;
int4 readop;
int4 inslot;
int4 writecount;
int4 readcount;
int4 writesection;
int4 readsection;
int4 opttype;
int4 writeop; ///< Index of the (last) p-code op writing to register (or -1)
int4 readop; ///< Index of the (last) p-code op reading the register (or -1)
int4 inslot; ///< Input slot of p-code op reading the register (or -1)
int4 writecount; ///< Number of times the register is written
int4 readcount; ///< Number of times the register is read
int4 writesection; ///< Section containing (last) p-code op writing to the register (or -2)
int4 readsection; ///< Section containing (last) p-code op reading the register (or -2)
mutable int4 opttype; ///< 0 = register read by a COPY, 1 = register written by a COPY (-1 otherwise)
/// \brief Construct a record, initializing counts
OptimizeRecord(void) {
writeop = -1; readop = -1; inslot=-1; writecount=0; readcount=0; writesection=-2; readsection=-2; opttype=-1; }
};
SleighCompile *compiler;
int4 unnecessarypcode;
int4 readnowrite;
int4 writenoread;
int4 largetemp;
bool printextwarning;
bool printdeadwarning;
bool printlargetempwarning;
SubtableSymbol *root_symbol;
vector<SubtableSymbol *> postorder;
map<SubtableSymbol *,int4> sizemap; // Sizes associated with tables
SleighCompile *compiler; ///< Parsed form of the SLEIGH file being examined
int4 unnecessarypcode; ///< Count of unnecessary extension/truncation operations
int4 readnowrite; ///< Count of temporary registers that are read but not written
int4 writenoread; ///< Count of temporary registers that are written but not read
int4 largetemp; ///< Count of temporary registers that are too large
bool printextwarning; ///< Set to \b true if warning emitted for each unnecessary truncation/extension
bool printdeadwarning; ///< Set to \b true if warning emitted for each written but not read temporary
bool printlargetempwarning; ///< Set to \b true if warning emitted for each too large temporary
SubtableSymbol *root_symbol; ///< The root symbol table for the parsed SLEIGH file
vector<SubtableSymbol *> postorder; ///< Subtables sorted into \e post order (dependent tables listed earlier)
map<SubtableSymbol *,int4> sizemap; ///< Sizes associated with table \e exports
OperandSymbol *getOperandSymbol(int4 slot,OpTpl *op,Constructor *ct);
void printOpName(ostream &s,OpTpl *op);
void printOpError(OpTpl *op,Constructor *ct,int4 err1,int4 err2,const string &message);
@ -118,7 +174,7 @@ class ConsistencyChecker {
bool checkSubtable(SubtableSymbol *sym);
void dealWithUnnecessaryExt(OpTpl *op,Constructor *ct);
void dealWithUnnecessaryTrunc(OpTpl *op,Constructor *ct);
void setPostOrder(SubtableSymbol *root); // Establish table ordering
void setPostOrder(SubtableSymbol *root);
// Optimization routines
static void examineVn(map<uintb,OptimizeRecord> &recs,const VarnodeTpl *vn,uint4 i,int4 inslot,int4 secnum);
@ -126,43 +182,56 @@ class ConsistencyChecker {
bool readWriteInterference(const VarnodeTpl *vn,const OpTpl *op,bool checkread) const;
void optimizeGather1(Constructor *ct,map<uintb,OptimizeRecord> &recs,int4 secnum) const;
void optimizeGather2(Constructor *ct,map<uintb,OptimizeRecord> &recs,int4 secnum) const;
OptimizeRecord *findValidRule(Constructor *ct,map<uintb,OptimizeRecord> &recs) const;
const OptimizeRecord *findValidRule(Constructor *ct,const map<uintb,OptimizeRecord> &recs) const;
void applyOptimization(Constructor *ct,const OptimizeRecord &rec);
void checkUnusedTemps(Constructor *ct,const map<uintb,OptimizeRecord> &recs);
void checkLargeTemporaries(Constructor *ct);
void checkLargeTemporaries(Constructor *ct,ConstructTpl *ctpl);
void optimize(Constructor *ct);
public:
ConsistencyChecker(SleighCompile *sleigh, SubtableSymbol *rt,bool unnecessary,bool warndead, bool warnlargetemp);
bool test(void);
bool testTruncations(bool isbigendian);
void optimizeAll(void);
int4 getNumUnnecessaryPcode(void) const { return unnecessarypcode; }
int4 getNumReadNoWrite(void) const { return readnowrite; }
int4 getNumWriteNoRead(void) const { return writenoread; }
int4 getNumLargeTemporaries(void) const {return largetemp;}
bool testSizeRestrictions(void); ///< Test size consistency of all p-code
bool testTruncations(void); ///< Test truncation validity of all p-code
void testLargeTemporary(void); ///< Test for temporary Varnodes that are too large
void optimizeAll(void); ///< Do COPY propagation optimization on all p-code
int4 getNumUnnecessaryPcode(void) const { return unnecessarypcode; } ///< Return the number of unnecessary extensions and truncations
int4 getNumReadNoWrite(void) const { return readnowrite; } ///< Return the number of temporaries read but not written
int4 getNumWriteNoRead(void) const { return writenoread; } ///< Return the number of temporaries written but not read
int4 getNumLargeTemporaries(void) const {return largetemp;} ///< Return the number of \e too large temporaries
};
/// \brief Helper function holding properties of a \e context field prior to calculating the context layout
///
/// This holds the concrete Varnode reprensenting the context field's physical storage and the
/// properties of the field itself, prior to the final ContextField being allocated.
struct FieldContext {
VarnodeSymbol *sym;
FieldQuality *qual;
bool operator<(const FieldContext &op2) const;
FieldContext(VarnodeSymbol *s,FieldQuality *q) { sym=s; qual=q; }
VarnodeSymbol *sym; ///< The concrete Varnode representing physical storage for the field
FieldQuality *qual; ///< Qualities of the field, as parsed
bool operator<(const FieldContext &op2) const; ///< Sort context fields based on their least significant bit boundary
FieldContext(VarnodeSymbol *s,FieldQuality *q) { sym=s; qual=q; } ///< Constructor
};
/// \brief A class for expanding macro directives within a p-code section
///
/// It is handed a (partial) list of p-code op templates (OpTpl). The
/// macro directive is established with the setMacroOp() method. Then calling
/// build() expands the macro into the list of OpTpls, providing parameter
/// substitution. The class is derived from PcodeBuilder, where the dump() method,
/// instead of emitting raw p-code, clones the macro templates into the list
/// of OpTpls.
class MacroBuilder : public PcodeBuilder {
SleighCompile *slgh;
bool haserror;
vector<OpTpl *> &outvec;
vector<HandleTpl *> params;
SleighCompile *slgh; ///< The SLEIGH parsing object
bool haserror; ///< Set to \b true by the build() method if there was an error
vector<OpTpl *> &outvec; ///< The partial list of op templates to expand the macro into
vector<HandleTpl *> params; ///< List of parameters to substitute into the macro
bool transferOp(OpTpl *op,vector<HandleTpl *> &params);
virtual void dump( OpTpl *op );
void free(void);
void reportError(const Location* loc, const string &val);
void free(void); ///< Free resources used by the builder
void reportError(const Location* loc, const string &val); ///< Report error encountered expanding the macro
public:
MacroBuilder(SleighCompile *sl,vector<OpTpl *> &ovec,uint4 lbcnt) : PcodeBuilder(lbcnt),outvec(ovec) {
slgh = sl; haserror = false; }
void setMacroOp(OpTpl *macroop);
bool hasError(void) const { return haserror; }
slgh = sl; haserror = false; } ///< Constructor
void setMacroOp(OpTpl *macroop); ///< Establish the MACRO directive to expand
bool hasError(void) const { return haserror; } ///< Return \b true if there were errors during expansion
virtual ~MacroBuilder(void) { free(); }
virtual void appendBuild(OpTpl *bld,int4 secnum) { dump(bld); }
virtual void delaySlot(OpTpl *op) { dump(op); }
@ -170,103 +239,151 @@ public:
virtual void appendCrossBuild(OpTpl *bld,int4 secnum) { dump(bld); }
};
/// \brief Parsing for the semantic section of Constructors
///
/// This is just the base p-code compiler for building OpTpl and VarnodeTpl.
/// Symbols, locations, and error/warning messages are tied into to the main
/// parser.
class SleighPcode : public PcodeCompile {
SleighCompile *compiler;
SleighCompile *compiler; ///< The main SLEIGH parser
virtual uintb allocateTemp(void);
virtual const Location *getLocation(SleighSymbol *sym) const;
virtual void reportError(const Location* loc, const string &msg);
virtual void reportWarning(const Location* loc, const string &msg);
virtual void addSymbol(SleighSymbol *sym);
public:
SleighPcode(void) : PcodeCompile() { compiler = (SleighCompile *)0; }
void setCompiler(SleighCompile *comp) { compiler = comp; }
SleighPcode(void) : PcodeCompile() { compiler = (SleighCompile *)0; } ///< Constructor
void setCompiler(SleighCompile *comp) { compiler = comp; } ///< Hook in the main parser
};
/// \brief SLEIGH specification compiling
///
/// Class for parsing SLEIGH specifications (.slaspec files) and producing the
/// \e compiled form (.sla file), which can then be loaded by a SLEIGH disassembly
/// and p-code generation engine. This full parser contains the p-code parser SleighPcode
/// within it. The main entry point is run_compilation(), which takes the input and output
/// file paths as parameters. Various options and preprocessor macros can be set using the
/// various set*() methods prior to calling run_compilation.
class SleighCompile : public SleighBase {
friend class SleighPcode;
public:
SleighPcode pcode;
SleighPcode pcode; ///< The p-code parsing (sub)engine
private:
map<string,string> preproc_defines; // Defines for the preprocessor
vector<FieldContext> contexttable;
vector<ConstructTpl *> macrotable;
vector<Token *> tokentable;
vector<SubtableSymbol *> tables;
vector<SectionSymbol *> sections;
list<WithBlock> withstack;
Constructor *curct; // Current constructor being defined
MacroSymbol *curmacro; // Current macro being defined
bool contextlock; // If the context layout has been established yet
vector<string> relpath; // Relative path (to cwd) for each filename
vector<string> filename; // Stack of current files being parsed
vector<int4> lineno; // Current line number for each file in stack
map<Constructor *, Location> ctorLocationMap; // Map constructor to its defining parse location
map<SleighSymbol *, Location> symbolLocationMap; // Map symbol to its defining parse location
int4 userop_count; // Number of userops defined
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 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 warnallnops; // True if pcode NOPs generate individual warnings
vector<string> noplist; // List of individual NOP warnings
mutable Location currentLocCache; // Location for (last) request of current location
int4 errors;
map<string,string> preproc_defines; ///< Defines for the preprocessor
vector<FieldContext> contexttable; ///< Context field definitions (prior to defining ContextField and ContextSymbol)
vector<ConstructTpl *> macrotable; ///< SLEIGH macro definitions
vector<Token *> tokentable; ///< SLEIGH token definitions
vector<SubtableSymbol *> tables; ///< SLEIGH subtables
vector<SectionSymbol *> sections; ///< Symbols defining Constructor sections
list<WithBlock> withstack; ///< Current stack of \b with blocks
Constructor *curct; ///< Current Constructor being defined
MacroSymbol *curmacro; ///< Current macro being defined
bool contextlock; ///< If the context layout has been established yet
vector<string> relpath; ///< Relative path (to cwd) for each filename
vector<string> filename; ///< Stack of current files being parsed
vector<int4> lineno; ///< Current line number for each file in stack
map<Constructor *, Location> ctorLocationMap; ///< Map each Constructor to its defining parse location
map<SleighSymbol *, Location> symbolLocationMap; ///< Map each symbol to its defining parse location
int4 userop_count; ///< Number of userops defined
bool warnunnecessarypcode; ///< \b true if we warn of unnecessary ZEXT or SEXT
bool warndeadtemps; ///< \b true if we warn of temporaries that are written but not read
bool lenientconflicterrors; ///< \b true if we ignore most pattern conflict errors
bool largetemporarywarning; ///< \b true if we warn about temporaries larger than SleighBase::MAX_UNIQUE_SIZE
bool warnalllocalcollisions; ///< \b true if local export collisions generate individual warnings
bool warnallnops; ///< \b true if pcode NOPs generate individual warnings
bool failinsensitivedups; ///< \b true if case insensitive register duplicates cause error
vector<string> noplist; ///< List of individual NOP warnings
mutable Location currentLocCache; ///< Location for (last) request of current location
int4 errors; ///< Number of fatal errors encountered
const Location* getCurrentLocation(void) const;
void predefinedSymbols(void);
const Location* getCurrentLocation(void) const; ///< Get the current file and line number being parsed
void predefinedSymbols(void); ///< Get SLEIGHs predefined address spaces and symbols
int4 calcContextVarLayout(int4 start,int4 sz,int4 numbits);
void buildDecisionTrees(void);
void buildPatterns(void);
void checkConsistency(void);
void buildDecisionTrees(void); ///< Build decision trees for all subtables
void buildPatterns(void); ///< Generate final match patterns based on parse constraint equations
void checkConsistency(void); ///< Perform final consistency checks on the SLEIGH definitions
static int4 findCollision(map<uintb,int4> &local2Operand,const vector<uintb> &locals,int operand);
bool checkLocalExports(Constructor *ct);
void checkLocalCollisions(void);
void checkNops(void);
string checkSymbols(SymbolScope *scope);
void addSymbol(SleighSymbol *sym);
SleighSymbol *dedupSymbolList(vector<SleighSymbol *> *symlist);
bool expandMacros(ConstructTpl *ctpl,const vector<ConstructTpl *> &macrotable);
bool finalizeSections(Constructor *big,SectionVector *vec);
bool checkLocalExports(Constructor *ct); ///< Check for operands that \e might export the same local variable
void checkLocalCollisions(void); ///< Check all Constructors for local export collisions between operands
void checkNops(void); ///< Report on all Constructors with empty semantic sections
void checkCaseSensitivity(void); ///< Check that register names can be treated as case insensitive
string checkSymbols(SymbolScope *scope); ///< Make sure label symbols are both defined and used
void addSymbol(SleighSymbol *sym); ///< Add a new symbol to the current scope
SleighSymbol *dedupSymbolList(vector<SleighSymbol *> *symlist); ///< Deduplicate the given list of symbols
bool expandMacros(ConstructTpl *ctpl); ///< Expand any formal SLEIGH macros in the given section of p-code
bool finalizeSections(Constructor *big,SectionVector *vec); ///< Do final checks, expansions, and linking for p-code sections
static VarnodeTpl *findSize(const ConstTpl &offset,const ConstructTpl *ct);
static bool forceExportSize(ConstructTpl *ct);
static void shiftUniqueVn(VarnodeTpl *vn,int4 sa);
static void shiftUniqueOp(OpTpl *op,int4 sa);
static void shiftUniqueHandle(HandleTpl *hand,int4 sa);
static void shiftUniqueConstruct(ConstructTpl *tpl,int4 sa);
void checkUniqueAllocation(void);
static string formatStatusMessage(const Location* loc, const string &msg);
void checkUniqueAllocation(void); ///< Modify temporary Varnode offsets to support \b crossbuilds
void process(void); ///< Do all post processing on the parsed data structures
public:
SleighCompile(void);
const Location *getLocation(Constructor* ctor) const;
const Location *getLocation(SleighSymbol *sym) const;
string formatStatusMessage(const Location* loc, const string &msg);
void reportError(const string &msg);
void reportError(const Location *loc, const string &msg);
void reportWarning(const string &msg);
void reportWarning(const Location *loc, const string &msg);
int4 numErrors(void) const { return errors; }
void reportInfo(const string &msg);
void reportInfo(const Location *loc, const string &msg);
SleighCompile(void); ///< Constructor
const Location *getLocation(Constructor* ctor) const; ///< Get the source location of the given Constructor's definition
const Location *getLocation(SleighSymbol *sym) const; ///< Get the source location of the given symbol's definition
void reportError(const string &msg); ///< Issue a fatal error message
void reportError(const Location *loc, const string &msg); ///< Issue a fatal error message with a source location
void reportWarning(const string &msg); ///< Issue a warning message
void reportWarning(const Location *loc, const string &msg); ///< Issue a warning message with a source location
int4 numErrors(void) const { return errors; } ///< Return the current number of fatal errors
uintb getUniqueAddr(void); ///< Get the next available temporary register offset
uintb getUniqueAddr(void);
/// \brief Set whether unnecessary truncation and extension operators generate warnings individually
///
/// \param val is \b true if warnings are generated individually. The default is \b false.
void setUnnecessaryPcodeWarning(bool val) { warnunnecessarypcode = val; }
/// \brief Set whether dead temporary registers generate warnings individually
///
/// \param val is \b true if warnings are generated individually. The default is \b false.
void setDeadTempWarning(bool val) { warndeadtemps = val; }
/// \brief Set whether named temporary registers must be defined using the \b local keyword.
///
/// \param val is \b true if the \b local keyword must always be used. The default is \b false.
void setEnforceLocalKeyWord(bool val) { pcode.setEnforceLocalKey(val); }
/// \brief Set whether too large temporary registers generate warnings individually
///
/// \param val is \b true if warnings are generated individually. The default is \b false.
void setLargeTemporaryWarning (bool val) {largetemporarywarning = val;}
/// \brief Set whether indistinguishable Constructor patterns generate fatal errors
///
/// \param val is \b true if no error is generated. The default is \b true.
void setLenientConflict(bool val) { lenientconflicterrors = val; }
/// \brief Set whether collisions in exported locals generate warnings individually
///
/// \param val is \b true if warnings are generated individually. The default is \b false.
void setLocalCollisionWarning(bool val) { warnalllocalcollisions = val; }
/// \brief Set whether NOP Constructors generate warnings individually
///
/// \param val is \b true if warnings are generated individually. The default is \b false.
void setAllNopWarning(bool val) { warnallnops = val; }
void process(void);
/// \brief Set whether case insensitive duplicates of register names cause an error
///
/// \param val is \b true is duplicates cause an error.
void setInsensitiveDuplicateError(bool val) { failinsensitivedups = val; }
// Lexer functions
void calcContextLayout(void);
string grabCurrentFilePath(void) const;
void parseFromNewFile(const string &fname);
void parsePreprocMacro(void);
void parseFileFinished(void);
void nextLine(void) { lineno.back() += 1; }
bool getPreprocValue(const string &nm,string &res) const;
void setPreprocValue(const string &nm,const string &value);
bool undefinePreprocValue(const string &nm);
void calcContextLayout(void); ///< Calculate the internal context field layout
string grabCurrentFilePath(void) const; ///< Get the path to the current source file
void parseFromNewFile(const string &fname); ///< Push a new source file to the current parse stack
void parsePreprocMacro(void); ///< Mark start of parsing for an expanded preprocessor macro
void parseFileFinished(void); ///< Mark end of parsing for the current file or macro
void nextLine(void) { lineno.back() += 1; } ///< Indicate parsing proceeded to the next line of the current file
bool getPreprocValue(const string &nm,string &res) const; ///< Retrieve a given preprocessor variable
void setPreprocValue(const string &nm,const string &value); ///< Set a given preprocessor variable
bool undefinePreprocValue(const string &nm); ///< Remove the value associated with the given preprocessor variable
// Parser functions
TokenSymbol *defineToken(string *name,uintb *sz,int4 endian);
@ -275,7 +392,12 @@ public:
void newSpace(SpaceQuality *qual);
SectionSymbol *newSectionSymbol(const string &nm);
void setEndian(int4 end);
/// \brief Set instruction alignment for the SLEIGH specification
///
/// \param val is the alignment value in bytes. 1 is the default indicating no alignment
void setAlignment(int4 val) { alignment = val; }
void defineVarnodes(SpaceSymbol *spacesym,uintb *off,uintb *size,vector<string> *names);
void defineBitrange(string *name,VarnodeSymbol *sym,uint4 bitoffset,uint4 numb);
void addUserOp(vector<string> *names);
@ -284,7 +406,6 @@ public:
void attachVarnodes(vector<SleighSymbol *> *symlist,vector<SleighSymbol *> *varlist);
SubtableSymbol *newTable(string *nm);
void newOperand(Constructor *ct,string *nm);
VarnodeTpl *addressOf(VarnodeTpl *var,uint4 size);
PatternEquation *constrainOperand(OperandSymbol *sym,PatternExpression *patexp);
void defineOperand(OperandSymbol *sym,PatternExpression *patexp);
PatternEquation *defineInvisibleOperand(TripleSymbol *sym);
@ -302,7 +423,7 @@ public:
SectionVector *finalNamedSection(SectionVector *vec,ConstructTpl *section);
vector<OpTpl *> *createCrossBuild(VarnodeTpl *addr,SectionSymbol *sym);
Constructor *createConstructor(SubtableSymbol *sym);
bool isInRoot(Constructor *ct) const { return (root == ct->getParent()); }
bool isInRoot(Constructor *ct) const { return (root == ct->getParent()); } ///< Is the Constructor in the root table?
void resetConstructors(void);
void pushWith(SubtableSymbol *ss,PatternEquation *pateq,vector<ContextChange *> *contvec);
void popWith(void);
@ -315,7 +436,13 @@ public:
virtual int4 instructionLength(const Address &baseaddr) const { return 0; }
virtual int4 oneInstruction(PcodeEmit &emit,const Address &baseaddr) const { return 0; }
virtual int4 printAssembly(AssemblyEmit &emit,const Address &baseaddr) const { return 0; }
void setAllOptions(const map<string,string> &defines, bool unnecessaryPcodeWarning,
bool lenientConflict, bool allCollisionWarning,
bool allNopWarning,bool deadTempWarning,bool enforceLocalKeyWord,
bool largeTemporaryWarning, bool caseSensitiveRegisterNames);
int4 run_compilation(const string &filein,const string &fileout);
};
extern SleighCompile *slgh;
extern int yydebug;
extern SleighCompile *slgh; ///< A global reference to the SLEIGH compiler accessible to the parse functions
extern int yydebug; ///< Debug state for the SLEIGH parse functions

View file

@ -346,16 +346,6 @@ public:
/// \param val is \b true to allow context changes, \b false prevents changes
virtual void allowContextSet(bool val) const {}
/// \brief Add a named register to the model for this processor
///
/// \deprecated All registers used to be formally added to the
/// processor model through this method.
/// \param nm is the name of the new register
/// \param base is the address space containing the register
/// \param offset is the offset of the register
/// \param size is the number of bytes in the register
virtual void addRegister(const string &nm,AddrSpace *base,uintb offset,int4 size)=0;
/// \brief Get a register as VarnodeData given its name
///
/// Retrieve the location and size of a register given its name

View file

@ -380,7 +380,7 @@ public:
struct TraverseNode {
const Varnode *vn; ///< Varnode at the point of traversal
uint4 flags; ///< Flags associated with the node
TraverseNode(const Varnode *v,uint4 f) { vn = v; flags = f; }
TraverseNode(const Varnode *v,uint4 f) { vn = v; flags = f; } ///< Constructor
};
bool contiguous_test(Varnode *vn1,Varnode *vn2); ///< Test if Varnodes are pieces of a whole

View file

@ -41,7 +41,7 @@ public abstract class SleighBase extends Translate implements NamedSymbolProvide
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
//Should match value in sleighbase.cc
private VectorSTL<String> userop = new VectorSTL<>();
private address_set varnode_xref = new address_set(); // Cross-reference registers by address
@ -127,12 +127,6 @@ public abstract class SleighBase extends Translate implements NamedSymbolProvide
}
}
@Override
public void addRegister(String nm, AddrSpace base, long offset, int size) {
VarnodeSymbol sym = new VarnodeSymbol(null, nm, base, offset, size);
symtab.addSymbol(sym);
}
@Override
public VarnodeData getRegister(String nm) {
VarnodeSymbol sym = (VarnodeSymbol) findSymbol(nm);

View file

@ -29,24 +29,22 @@ import ghidra.pcodeCPort.space.AddrSpace;
class ConsistencyChecker {
int unnecessarypcode;
int readnowrite;
int writenoread;
// number of constructors using a temporary varnode larger than SleighBase.MAX_UNIQUE_SIZE
int largetemp;
boolean printextwarning;
boolean printdeadwarning;
//if true, print information about constructors using temporary varnodes larger than SleighBase.MAX_UNIQUE_SIZE
boolean printlargetempwarning;
SleighCompile compiler;
SubtableSymbol root_symbol;
VectorSTL<SubtableSymbol> postorder = new VectorSTL<>();
private int unnecessarypcode;
private int readnowrite;
private int writenoread;
private int largetemp; // number of constructors using a temporary varnode larger than SleighBase.MAX_UNIQUE_SIZE
private boolean printextwarning;
private boolean printdeadwarning;
private boolean printlargetempwarning; // if true, warning about temporary varnodes larger than SleighBase.MAX_UNIQUE_SIZE
private SleighCompile compiler;
private SubtableSymbol root_symbol;
private VectorSTL<SubtableSymbol> postorder = new VectorSTL<>();
// Sizes associated with tables
MapSTL<SubtableSymbol, Integer> sizemap =
new MapSTL<>((s1, s2) -> s1.compareTo(s2));
private MapSTL<SubtableSymbol, Integer> sizemap = new MapSTL<>((s1, s2) -> s1.compareTo(s2));
OperandSymbol getOperandSymbol(int slot, OpTpl op, Constructor ct) {
private OperandSymbol getOperandSymbol(int slot, OpTpl op, Constructor ct) {
VarnodeTpl vn;
OperandSymbol opsym = null;
int handindex;
@ -69,9 +67,8 @@ class ConsistencyChecker {
return opsym;
}
boolean sizeRestriction(OpTpl op, Constructor ct)
{ // Make sure op template meets size restrictions
private boolean sizeRestriction(OpTpl op, Constructor ct) {
// Make sure op template meets size restrictions
// Return false and any info about mismatched sizes
int vnout, vn0, vn1;
AddrSpace spc;
@ -103,7 +100,7 @@ class ConsistencyChecker {
return true;
}
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;
case CPUI_INT_ADD:
case CPUI_INT_SUB:
@ -240,8 +237,8 @@ class ConsistencyChecker {
return false;
}
return true;
// The shift amount does not necessarily have to be the same size
// But the output and first parameter must be same size
// The shift amount does not necessarily have to be the same size
// But the output and first parameter must be same size
case CPUI_INT_LEFT:
case CPUI_INT_RIGHT:
case CPUI_INT_SRIGHT:
@ -284,7 +281,7 @@ class ConsistencyChecker {
}
else if (vnout < vn0) {
printOpError(op, ct, -1, 0,
"Output size must be strictly bigger than input size");
"Output size must be strictly bigger than input size");
return false;
}
return true;
@ -349,7 +346,7 @@ class ConsistencyChecker {
return true;
}
String getOpName(OpTpl op) {
private String getOpName(OpTpl op) {
switch (op.getOpcode()) {
case CPUI_COPY:
return "Copy(=)";
@ -484,7 +481,7 @@ class ConsistencyChecker {
}
}
void printOpError(OpTpl op, Constructor ct, int err1, int err2, String message) {
private void printOpError(OpTpl op, Constructor ct, int err1, int err2, String message) {
SubtableSymbol sym = ct.getParent();
OperandSymbol op1, op2;
@ -498,10 +495,10 @@ class ConsistencyChecker {
StringBuilder sb = new StringBuilder();
sb.append("Size restriction error in table '")
.append(sym.getName())
.append("' in constructor at ").append(ct.location)
.append("\n");
.append(sym.getName())
.append("' in constructor at ")
.append(ct.location)
.append("\n");
sb.append(" Problem");
if ((op1 != null) && (op2 != null)) {
@ -521,7 +518,7 @@ class ConsistencyChecker {
}
int recoverSize(ConstTpl sizeconst, Constructor ct) {
private int recoverSize(ConstTpl sizeconst, Constructor ct) {
int size = 0, handindex;
OperandSymbol opsym;
SubtableSymbol tabsym;
@ -572,7 +569,7 @@ class ConsistencyChecker {
"\" (or did you mean to use signed comparison?)", ct);
}
boolean checkOpMisuse(OpTpl op, Constructor ct) {
private boolean checkOpMisuse(OpTpl op, Constructor ct) {
switch (op.getOpcode()) {
case CPUI_INT_LESS: {
VarnodeTpl vn0 = op.getIn(0);
@ -594,7 +591,7 @@ class ConsistencyChecker {
handleBetter("!= 0", ct);
}
}
break;
break;
case CPUI_INT_LESSEQUAL: {
VarnodeTpl vn0 = op.getIn(0);
VarnodeTpl vn1 = op.getIn(1);
@ -615,14 +612,14 @@ class ConsistencyChecker {
handleBetter("== 0", ct);
}
}
break;
break;
default:
break;
}
return true;
}
boolean checkConstructorSection(Constructor ct, ConstructTpl cttpl) {
private boolean checkConstructorSection(Constructor ct, ConstructTpl cttpl) {
// Check all the OpTpl s within the given section for consistency, return true if all tests pass
if (cttpl == null) {
return true; // Nothing to check
@ -649,7 +646,7 @@ class ConsistencyChecker {
* @param opTpl the op to check
* @return true if {@code opTpl} uses a large temporary varnode
*/
boolean hasLargeTemporary(OpTpl opTpl) {
private boolean hasLargeTemporary(OpTpl opTpl) {
VarnodeTpl out = opTpl.getOut();
if (out != null && isTemporaryAndTooBig(out)) {
return true;
@ -669,12 +666,12 @@ class ConsistencyChecker {
* @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;
private 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) {
private boolean checkVarnodeTruncation(Constructor ct, int slot, OpTpl op, VarnodeTpl vn,
boolean isbigendian) {
ConstTpl off = vn.getOffset();
if (off.getType() != const_type.handle) {
return true;
@ -683,24 +680,25 @@ class ConsistencyChecker {
return true;
}
const_type sztype = vn.getSize().getType();
if ((sztype != const_type.real)&&(sztype != const_type.handle)){
printOpError(op,ct,slot,slot,"Bad truncation expression");
if ((sztype != const_type.real) && (sztype != const_type.handle)) {
printOpError(op, ct, slot, slot, "Bad truncation expression");
return false;
}
int sz = recoverSize(off,ct); // Recover the size of the original operand
int sz = recoverSize(off, ct); // Recover the size of the original operand
if (sz <= 0) {
printOpError(op,ct,slot,slot,"Could not recover size");
printOpError(op, ct, slot, slot, "Could not recover size");
return false;
}
boolean res = vn.adjustTruncation(sz, isbigendian);
if (!res) {
printOpError(op,ct,slot,slot,"Truncation operator out of bounds");
printOpError(op, ct, slot, slot, "Truncation operator out of bounds");
return false;
}
return true;
}
boolean checkSectionTruncations(Constructor ct,ConstructTpl cttpl,boolean isbigendian) {
private boolean checkSectionTruncations(Constructor ct, ConstructTpl cttpl,
boolean isbigendian) {
// Check all the varnodes that have an offset_plus template
// adjust the plus if we are big endian
// make sure the truncation is valid
@ -709,16 +707,16 @@ class ConsistencyChecker {
Iterator<OpTpl> iter;
iter = ops.iterator();
while(iter.hasNext()) {
while (iter.hasNext()) {
OpTpl op = iter.next();
VarnodeTpl outvn = op.getOut();
if (outvn != null) {
if (!checkVarnodeTruncation(ct,-1,op,outvn,isbigendian)) {
if (!checkVarnodeTruncation(ct, -1, op, outvn, isbigendian)) {
testresult = false;
}
}
for(int i=0;i<op.numInput();++i) {
if (!checkVarnodeTruncation(ct,i,op,op.getIn(i),isbigendian)) {
for (int i = 0; i < op.numInput(); ++i) {
if (!checkVarnodeTruncation(ct, i, op, op.getIn(i), isbigendian)) {
testresult = false;
}
}
@ -726,7 +724,7 @@ class ConsistencyChecker {
return testresult;
}
boolean checkSubtable(SubtableSymbol sym) {
private boolean checkSubtable(SubtableSymbol sym) {
int tablesize = 0;
int numconstruct = sym.getNumConstructors();
Constructor ct;
@ -796,7 +794,7 @@ class ConsistencyChecker {
// Deal with detected extension (SEXT or ZEXT) where the
// input size is the same as the output size
void dealWithUnnecessaryExt(OpTpl op, Constructor ct) {
private void dealWithUnnecessaryExt(OpTpl op, Constructor ct) {
if (printextwarning) {
compiler.reportWarning(op.location, "Unnecessary '" + getOpName(op) + "'");
}
@ -804,7 +802,7 @@ class ConsistencyChecker {
unnecessarypcode += 1;
}
void dealWithUnnecessaryTrunc(OpTpl op, Constructor ct) {
private void dealWithUnnecessaryTrunc(OpTpl op, Constructor ct) {
if (printextwarning) {
compiler.reportWarning(op.location, "Unnecessary '" + getOpName(op) + "'");
}
@ -814,7 +812,7 @@ class ConsistencyChecker {
}
// Establish table ordering
void setPostOrder(SubtableSymbol root) {
private void setPostOrder(SubtableSymbol root) {
postorder.clear();
sizemap.clear();
@ -869,8 +867,8 @@ class ConsistencyChecker {
}
// Optimization routines
static void examineVn(MapSTL<Long, OptimizeRecord> recs, VarnodeTpl vn, int i, int inslot,
int secnum) {
private static void examineVn(MapSTL<Long, OptimizeRecord> recs, VarnodeTpl vn, int i,
int inslot, int secnum) {
if (vn == null) {
return;
}
@ -900,7 +898,7 @@ class ConsistencyChecker {
}
}
static boolean possibleIntersection(VarnodeTpl vn1, VarnodeTpl vn2) {
private static boolean possibleIntersection(VarnodeTpl vn1, VarnodeTpl vn2) {
// Conservatively test whether vn1 and vn2 can intersect
if (vn1.getSpace().isConstSpace()) {
return false;
@ -958,7 +956,7 @@ class ConsistencyChecker {
// This is extremely conservative. Basically any op where
// we can't see exactly what might be written is considered
// interference
boolean readWriteInterference(VarnodeTpl vn, OpTpl op, boolean checkread) {
private boolean readWriteInterference(VarnodeTpl vn, OpTpl op, boolean checkread) {
switch (op.getOpcode()) {
case CPUI_MULTIEQUAL:
case CPUI_PTRSUB:
@ -999,7 +997,7 @@ class ConsistencyChecker {
}
// Look for reads and writes to temporaries
void optimizeGather1(Constructor ct, MapSTL<Long, OptimizeRecord> recs, int secnum) {
private void optimizeGather1(Constructor ct, MapSTL<Long, OptimizeRecord> recs, int secnum) {
ConstructTpl tpl;
if (secnum < 0) {
tpl = ct.getTempl();
@ -1023,7 +1021,7 @@ class ConsistencyChecker {
}
// Make sure any temp used by the export is not optimized away
void optimizeGather2(Constructor ct, MapSTL<Long, OptimizeRecord> recs, int secnum) {
private void optimizeGather2(Constructor ct, MapSTL<Long, OptimizeRecord> recs, int secnum) {
ConstructTpl tpl;
if (secnum < 0) {
tpl = ct.getTempl();
@ -1053,7 +1051,7 @@ class ConsistencyChecker {
}
if (hand.getSpace().isUniqueSpace()) {
if ((hand.getPtrSpace().getType() == ConstTpl.const_type.real) &&
(hand.getPtrOffset().getType() == ConstTpl.const_type.real)) {
(hand.getPtrOffset().getType() == ConstTpl.const_type.real)) {
long offset = hand.getPtrOffset().getReal();
recs.put(offset, new OptimizeRecord());
IteratorSTL<Pair<Long, OptimizeRecord>> res = recs.find(offset);
@ -1067,7 +1065,7 @@ class ConsistencyChecker {
}
}
OptimizeRecord findValidRule(Constructor ct, MapSTL<Long, OptimizeRecord> recs) {
private OptimizeRecord findValidRule(Constructor ct, MapSTL<Long, OptimizeRecord> recs) {
IteratorSTL<Pair<Long, OptimizeRecord>> iter;
iter = recs.begin();
while (!iter.isEnd()) {
@ -1075,7 +1073,7 @@ class ConsistencyChecker {
iter.increment();
if ((currec.writecount == 1) && (currec.readcount == 1) &&
(currec.readsection == currec.writesection)) {
(currec.readsection == currec.writesection)) {
// Temporary must be read and written exactly once
ConstructTpl tpl;
if (currec.readsection < 0) {
@ -1123,7 +1121,7 @@ class ConsistencyChecker {
return null;
}
void applyOptimization(Constructor ct, OptimizeRecord rec) {
private void applyOptimization(Constructor ct, OptimizeRecord rec) {
VectorSTL<Integer> deleteops = new VectorSTL<>();
ConstructTpl ctempl;
if (rec.readsection < 0) {
@ -1150,7 +1148,7 @@ class ConsistencyChecker {
ctempl.deleteOps(deleteops);
}
void checkUnusedTemps(Constructor ct, MapSTL<Long, OptimizeRecord> recs) {
private void checkUnusedTemps(Constructor ct, MapSTL<Long, OptimizeRecord> recs) {
IteratorSTL<Pair<Long, OptimizeRecord>> iter = recs.begin();
while (!iter.isEnd()) {
Pair<Long, OptimizeRecord> pair = iter.get();
@ -1170,28 +1168,27 @@ class ConsistencyChecker {
}
/**
* Checks {@code ct} to see whether it contains an {@link OpTpl} which
* Checks {@code ct} to see whether p-code section 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
* @param ctpl is the specific p-code section
*/
void checkLargeTemporaries(Constructor ct) {
ConstructTpl ctTpl = ct.getTempl();
if (ctTpl == null) {
return;
}
VectorSTL<OpTpl> ops = ctTpl.getOpvec();
private void checkLargeTemporaries(Constructor ct, ConstructTpl ctpl) {
VectorSTL<OpTpl> ops = ctpl.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.");
}
if (printlargetempwarning) {
compiler.reportWarning(ct.location,
"Constructor uses temporary varnode larger than " +
SleighBase.MAX_UNIQUE_SIZE + " bytes.");
}
largetemp++;
return;
}
}
}
void optimize(Constructor ct) {
private void optimize(Constructor ct) {
OptimizeRecord currec;
MapSTL<Long, OptimizeRecord> recs = new ComparableMapSTL<>();
int numsections = ct.getNumSections();
@ -1208,10 +1205,10 @@ class ConsistencyChecker {
}
while (currec != null);
checkUnusedTemps(ct, recs);
checkLargeTemporaries(ct);
}
ConsistencyChecker(SleighCompile cp, SubtableSymbol rt, boolean unnecessary, boolean warndead, boolean warnlargetemp) {
public ConsistencyChecker(SleighCompile cp, SubtableSymbol rt, boolean unnecessary,
boolean warndead, boolean warnlargetemp) {
compiler = cp;
root_symbol = rt;
unnecessarypcode = 0;
@ -1226,7 +1223,7 @@ class ConsistencyChecker {
}
// Main entry point for size consistency check
boolean test() {
public boolean testSizeRestrictions() {
setPostOrder(root_symbol);
boolean testresult = true;
@ -1239,18 +1236,19 @@ class ConsistencyChecker {
return testresult;
}
boolean testTruncations(boolean isbigendian) {
public boolean testTruncations() {
// Now that the sizemap is calculated, we can check/adjust the offset_plus templates
boolean testresult = true;
for(int i=0;i<postorder.size();++i) {
boolean isbigendian = compiler.isBigEndian();
for (int i = 0; i < postorder.size(); ++i) {
SubtableSymbol sym = postorder.get(i);
int numconstruct = sym.getNumConstructors();
Constructor ct;
for(int j=0;j<numconstruct;++j) {
for (int j = 0; j < numconstruct; ++j) {
ct = sym.getConstructor(j);
int numsections = ct.getNumSections();
for(int k=-1;k<numsections;++k) {
for (int k = -1; k < numsections; ++k) {
ConstructTpl tpl;
if (k < 0) {
tpl = ct.getTempl();
@ -1261,7 +1259,7 @@ class ConsistencyChecker {
if (tpl == null) {
continue;
}
if (!checkSectionTruncations(ct,tpl,isbigendian)) {
if (!checkSectionTruncations(ct, tpl, isbigendian)) {
testresult = false;
}
}
@ -1270,7 +1268,33 @@ class ConsistencyChecker {
return testresult;
}
void optimizeAll() {
public void testLargeTemporary() {
for (int i = 0; i < postorder.size(); ++i) {
SubtableSymbol sym = postorder.get(i);
int numconstruct = sym.getNumConstructors();
Constructor ct;
for (int j = 0; j < numconstruct; ++j) {
ct = sym.getConstructor(j);
int numsections = ct.getNumSections();
for (int k = -1; k < numsections; ++k) {
ConstructTpl tpl;
if (k < 0) {
tpl = ct.getTempl();
}
else {
tpl = ct.getNamedTempl(k);
}
if (tpl == null) {
continue;
}
checkLargeTemporaries(ct, tpl);
}
}
}
}
public void optimizeAll() {
for (int i = 0; i < postorder.size(); ++i) {
SubtableSymbol sym = postorder.get(i);
int numconstruct = sym.getNumConstructors();
@ -1282,15 +1306,15 @@ class ConsistencyChecker {
}
}
int getNumUnnecessaryPcode() {
public int getNumUnnecessaryPcode() {
return unnecessarypcode;
}
int getNumReadNoWrite() {
public int getNumReadNoWrite() {
return readnowrite;
}
int getNumWriteNoRead() {
public int getNumWriteNoRead() {
return writenoread;
}
@ -1299,7 +1323,7 @@ class ConsistencyChecker {
* unique space with size larger than {@link SleighBase#MAX_UNIQUE_SIZE}.
* @return num constructors with large temp varnodes
*/
int getNumLargeTemporaries() {
public int getNumLargeTemporaries() {
return largetemp;
}
}

View file

@ -15,14 +15,13 @@
*/
package ghidra.pcodeCPort.slgh_compile;
import java.io.IOException;
import java.io.PrintStream;
import java.io.*;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import org.antlr.runtime.RecognitionException;
import org.antlr.runtime.*;
import org.antlr.runtime.tree.CommonTreeNodeStream;
import org.jdom.JDOMException;
import generic.stl.*;
@ -39,8 +38,10 @@ import ghidra.pcodeCPort.space.*;
import ghidra.pcodeCPort.utils.Utils;
import ghidra.pcodeCPort.xml.DocumentStorage;
import ghidra.program.model.lang.BasicCompilerSpec;
import ghidra.sleigh.grammar.Location;
import ghidra.sleigh.grammar.*;
import ghidra.util.Msg;
import utilities.util.FileResolutionResult;
import utilities.util.FileUtilities;
/**
* <code>SleighCompile</code> provides the ability to compile Sleigh language module (e.g., *.slaspec)
@ -50,7 +51,7 @@ public class SleighCompile extends SleighBase {
static boolean yydebug = false;
static boolean isLocationIsh(Object o) {
private static boolean isLocationIsh(Object o) {
if (o instanceof Location) {
return true;
}
@ -225,48 +226,45 @@ public class SleighCompile extends SleighBase {
}
// Defines for the preprocessor
MapSTL<String, String> preproc_defines = new MapSTL<>(new SelfComparator<String>());
VectorSTL<FieldContext> contexttable = new VectorSTL<>();
Integer firstContextField = null;
VectorSTL<ConstructTpl> macrotable = new VectorSTL<>();
VectorSTL<ghidra.pcodeCPort.context.Token> tokentable = new VectorSTL<>();
VectorSTL<SubtableSymbol> tables = new VectorSTL<>();
VectorSTL<SectionSymbol> sections = new VectorSTL<>();
Constructor curct; // Current constructor being defined
MacroSymbol curmacro; // Current macro being defined
private MapSTL<String, String> preproc_defines = new MapSTL<>(new SelfComparator<String>());
private VectorSTL<FieldContext> contexttable = new VectorSTL<>();
private Integer firstContextField = null;
private VectorSTL<ConstructTpl> macrotable = new VectorSTL<>();
private VectorSTL<ghidra.pcodeCPort.context.Token> tokentable = new VectorSTL<>();
private VectorSTL<SubtableSymbol> tables = new VectorSTL<>();
private VectorSTL<SectionSymbol> sections = new VectorSTL<>();
private Constructor curct; // Current constructor being defined
private MacroSymbol curmacro; // Current macro being defined
// If the context layout has been established yet
boolean contextlock;
private boolean contextlock;
// Stack of current files being parsed
// VectorSTL<String> filename = new VectorSTL<String>();
String filename;
// Current line number for each file in stack
// VectorSTL<Integer> lineno = new VectorSTL<Integer>();
int lineno;
int linenoDifferential;
int userop_count; // Number of userops defined
private int userop_count; // Number of userops defined
boolean warnunnecessarypcode; // True if we warn of unnecessary ZEXT or SEXT
boolean warndeadtemps; // True if we warn of temporaries that are written but not read
boolean warnunusedfields; // True if fields are defined but not used
boolean enforcelocalkeyword; // Force slaspec to use 'local' keyword when defining temporary varnodes
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 warnallnops;
public VectorSTL<String> noplist = new VectorSTL<>();
private boolean warnunnecessarypcode; // True if we warn of unnecessary ZEXT or SEXT
private boolean warndeadtemps; // True if we warn of temporaries that are written but not read
private boolean warnunusedfields; // True if fields are defined but not used
private boolean lenientconflicterrors; // True if we ignore most pattern conflict errors
private boolean largetemporarywarning; // True if we warn about temporaries larger than SleighBase.MAX_UNIQUE_SIZE
private boolean warnalllocalcollisions; // True if local export collisions generate individual warnings
private boolean warnallnops; // True if pcode NOPs generate individual warnings
private boolean failinsensitivedups; // True if case insensitive register duplicates cause error
private VectorSTL<String> noplist = new VectorSTL<>();
public Deque<WithBlock> withstack = new LinkedList<>();
private Deque<WithBlock> withstack = new LinkedList<>();
int errors;
int warnings;
private int errors;
private int warnings;
// Define the "pre" defined spaces and symbols
// This must happen after endian has been defined
void predefinedSymbols() {
private void predefinedSymbols() {
entry("predefinedSymbols");
symtab.addScope(); // Create global scope
@ -327,14 +325,14 @@ public class SleighCompile extends SleighBase {
return res;
}
SectionVector standaloneSection(ConstructTpl main) {
protected SectionVector standaloneSection(ConstructTpl main) {
entry("standaloneSection", main);
// Create SectionVector for just the main rtl section with no named sections
SectionVector res = new SectionVector(main, symtab.getCurrentScope());
return res;
}
SectionVector firstNamedSection(ConstructTpl main, SectionSymbol sym) {
protected SectionVector firstNamedSection(ConstructTpl main, SectionSymbol sym) {
entry("firstNamedSection", main);
// Start the first named p-code section after the main p-code section
sym.incrementDefineCount();
@ -349,7 +347,8 @@ public class SleighCompile extends SleighBase {
return res;
}
SectionVector nextNamedSection(SectionVector vec, ConstructTpl section, SectionSymbol sym) {
protected SectionVector nextNamedSection(SectionVector vec, ConstructTpl section,
SectionSymbol sym) {
entry("nextNamedSection", vec, section, sym);
// Add additional named p-code sections
sym.incrementDefineCount();
@ -365,7 +364,7 @@ public class SleighCompile extends SleighBase {
return vec;
}
SectionVector finalNamedSection(SectionVector vec, ConstructTpl section) {
protected SectionVector finalNamedSection(SectionVector vec, ConstructTpl section) {
entry("finalNamedSection", vec, section);
// Fill-in final named section to match the previous SectionSymbol
vec.append(section, symtab.getCurrentScope());
@ -373,7 +372,7 @@ public class SleighCompile extends SleighBase {
return vec;
}
int calcContextVarLayout(int start, int sz, int numbits) {
private int calcContextVarLayout(int start, int sz, int numbits) {
entry("calcContextVarLayout", start, sz, numbits);
VarnodeSymbol sym = contexttable.get(start).sym;
FieldQuality qual;
@ -390,7 +389,7 @@ public class SleighCompile extends SleighBase {
i = 0;
while (i < sz) {
qual = contexttable.get(i).qual;
qual = contexttable.get(i + start).qual;
int min = qual.low;
int max = qual.high;
if (max - min > (8 * 4)) {
@ -409,7 +408,7 @@ public class SleighCompile extends SleighBase {
j = i + 1;
// Find union of fields overlapping with first field
while (j < sz) {
qual = contexttable.get(j).qual;
qual = contexttable.get(j + start).qual;
if (qual.low <= max) { // We have overlap of context variables
if (qual.high > max) {
max = qual.high;
@ -434,7 +433,7 @@ public class SleighCompile extends SleighBase {
numbits += alloc;
for (; i < j; ++i) {
qual = contexttable.get(i).qual;
qual = contexttable.get(i + start).qual;
int l = qual.low - min + low;
int h = numbits - 1 - (max - qual.high);
ContextField field = new ContextField(qual.location, qual.signext, l, h);
@ -450,7 +449,7 @@ public class SleighCompile extends SleighBase {
return numbits;
}
void buildDecisionTrees() {
private void buildDecisionTrees() {
entry("buildDecisionTrees");
DecisionProperties props = new DecisionProperties();
root.buildDecisionTree(props);
@ -474,7 +473,7 @@ public class SleighCompile extends SleighBase {
}
}
void buildPatterns() {
private void buildPatterns() {
entry("buildPatterns");
if (root == null) {
reportError(null, "No patterns to match--could not find any constructors");
@ -496,16 +495,16 @@ public class SleighCompile extends SleighBase {
}
}
void checkConsistency() {
private void checkConsistency() {
entry("checkConsistency");
ConsistencyChecker checker =
new ConsistencyChecker(this, root, warnunnecessarypcode, warndeadtemps, largetemporarywarning);
ConsistencyChecker checker = new ConsistencyChecker(this, root, warnunnecessarypcode,
warndeadtemps, largetemporarywarning);
if (!checker.test()) {
if (!checker.testSizeRestrictions()) {
errors += 1;
return;
}
if (!checker.testTruncations(isBigEndian())) {
if (!checker.testTruncations()) {
errors += 1;
return;
}
@ -524,14 +523,17 @@ public class SleighCompile extends SleighBase {
" operations wrote to temporaries that were not read");
reportWarning(null, "Use -t switch to list each individually");
}
checker.testLargeTemporary();
if ((!largetemporarywarning) && checker.getNumLargeTemporaries() > 0) {
reportWarning(null, checker.getNumLargeTemporaries() +
" constructors contain temporaries larger than " + SleighBase.MAX_UNIQUE_SIZE + " bytes.");
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,
private static int findCollision(Map<Long, Integer> local2Operand, ArrayList<Long> locals,
int operand) {
Integer boxOperand = Integer.valueOf(operand);
for (Long local : locals) {
@ -545,7 +547,7 @@ public class SleighCompile extends SleighBase {
return -1;
}
boolean checkLocalExports(Constructor ct) {
private boolean checkLocalExports(Constructor ct) {
if (ct.getTempl() == null) {
return true; // No template, collisions impossible
}
@ -556,9 +558,9 @@ public class SleighCompile extends SleighBase {
return true; // Collisions can only happen with multiple operands
}
boolean noCollisions = true;
Map<Long, Integer> collect = new TreeMap<Long, Integer>();
Map<Long, Integer> collect = new TreeMap<>();
for (int i = 0; i < ct.getNumOperands(); ++i) {
ArrayList<Long> newCollect = new ArrayList<Long>();
ArrayList<Long> newCollect = new ArrayList<>();
ct.getOperand(i).collectLocalValues(newCollect);
if (newCollect.isEmpty()) {
continue;
@ -578,7 +580,7 @@ public class SleighCompile extends SleighBase {
return noCollisions;
}
void checkLocalCollisions() {
private void checkLocalCollisions() {
int collisionCount = 0;
SubtableSymbol sym = root; // Start with the instruction table
int i = -1;
@ -604,8 +606,53 @@ public class SleighCompile extends SleighBase {
}
}
private void checkNops() {
if (noplist.size() > 0) {
if (warnallnops) {
IteratorSTL<String> iter;
for (iter = noplist.begin(); !iter.isEnd(); iter.increment()) {
Msg.warn(SleighCompile.class, iter.get());
}
}
Msg.warn(SleighCompile.class, noplist.size() + " NOP constructors found");
if (!warnallnops) {
Msg.warn(SleighCompile.class, "Use -n switch to list each individually");
}
}
}
private void checkCaseSensitivity() {
if (!failinsensitivedups) {
return; // Case insensitive duplicates don't cause error
}
HashMap<String, SleighSymbol> registerMap = new HashMap<>();
SymbolScope scope = symtab.getGlobalScope();
IteratorSTL<SleighSymbol> iter;
for (iter = scope.begin(); !iter.isEnd(); iter.increment()) {
SleighSymbol sym = iter.get();
if (!(sym instanceof VarnodeSymbol)) {
continue;
}
VarnodeSymbol vsym = (VarnodeSymbol) sym;
AddrSpace space = vsym.getFixedVarnode().space;
if (space.getType() != spacetype.IPTR_PROCESSOR) {
continue;
}
String nm = sym.getName().toUpperCase();
SleighSymbol oldsym = registerMap.putIfAbsent(nm, sym);
if (oldsym != null) { // Name already existed
StringBuilder buffer = new StringBuilder();
buffer.append("Name collision: ").append(sym.getName()).append(" --- ");
Location oldLocation = oldsym.getLocation();
buffer.append("Duplicate symbol ").append(oldsym.getName()).append(" defined at ");
buffer.append(oldLocation);
reportError(sym.getLocation(), buffer.toString());
}
}
}
// Make sure label symbols are used properly
String checkSymbols(SymbolScope scope) {
private String checkSymbols(SymbolScope scope) {
entry("checkSymbols", scope);
List<String> symbolErrors = new ArrayList<>();
IteratorSTL<SleighSymbol> iter;
@ -628,7 +675,7 @@ public class SleighCompile extends SleighBase {
}
// Make sure symbol table errors are caught
int addSymbol(SleighSymbol sym) {
protected int addSymbol(SleighSymbol sym) {
entry("addSymbol", sym);
int id = -1;
try {
@ -648,7 +695,9 @@ public class SleighCompile extends SleighBase {
errors = 0;
warnunnecessarypcode = false;
lenientconflicterrors = true;
largetemporarywarning = false;
warnallnops = false;
failinsensitivedups = true;
root = null;
pcode.resetLabelCount();
}
@ -689,31 +738,30 @@ public class SleighCompile extends SleighBase {
return warnings;
}
long getUniqueAddr() {
protected long getUniqueAddr() {
entry("getUniqueAddr");
long base = getUniqueBase();
setUniqueBase(base + MAX_UNIQUE_SIZE);
return base;
}
void setUnnecessaryPcodeWarning(boolean val) {
public void setUnnecessaryPcodeWarning(boolean val) {
entry("setUnecessaryPcodeWarning", val);
warnunnecessarypcode = val;
}
void setDeadTempWarning(boolean val) {
public void setDeadTempWarning(boolean val) {
entry("setDeadTempWarning", val);
warndeadtemps = val;
}
void setUnusedFieldWarning(boolean val) {
public void setUnusedFieldWarning(boolean val) {
entry("setUnusedFieldWarning", val);
warnunusedfields = val;
}
void setEnforceLocalKeyWord(boolean val) {
public void setEnforceLocalKeyWord(boolean val) {
entry("setEnforceLocalKeyWord", val);
enforcelocalkeyword = val;
pcode.setEnforceLocalKey(val);
}
@ -723,29 +771,36 @@ public class SleighCompile extends SleighBase {
* 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);
public void setLargeTemporaryWarning(boolean val) {
entry("setLargeTemporaryWarning", val);
largetemporarywarning = val;
}
void setLenientConflict(boolean val) {
public void setLenientConflict(boolean val) {
entry("setLenientConflict", val);
lenientconflicterrors = val;
}
void setLocalCollisionWarning(boolean val) {
public void setLocalCollisionWarning(boolean val) {
entry("setLocalCollisionWarning", val);
warnalllocalcollisions = val;
}
void setAllNopWarning(boolean val) {
public void setAllNopWarning(boolean val) {
entry("setAllNopWarning", val);
warnallnops = val;
}
public void setInsensitiveDuplicateError(boolean val) {
entry("setInsensitiveDuplicateError", val);
failinsensitivedups = val;
}
// Do all post processing on the parsed data structures
public void process() {
private void process() {
entry("process");
checkNops();
checkCaseSensitivity();
if (getDefaultSpace() == null) {
reportError(null, "No default space specified");
}
@ -768,7 +823,7 @@ public class SleighCompile extends SleighBase {
if (errors > 0) {
return;
}
ArrayList<SleighSymbol> errorPairs = new ArrayList<SleighSymbol>();
ArrayList<SleighSymbol> errorPairs = new ArrayList<>();
buildXrefs(errorPairs); // Make sure we can build crossrefs properly
if (!errorPairs.isEmpty()) {
for (int i = 0; i < errorPairs.size(); i += 2) {
@ -816,25 +871,7 @@ public class SleighCompile extends SleighBase {
contexttable.clear();
}
private static final Pattern PREPROCPOS = Pattern.compile("%%%(.*)\b(\\d+)%%%");
public void setPosition(String pos, int presumedLineno) {
Matcher m;
if ((m = PREPROCPOS.matcher(pos)).matches()) {
filename = m.group(1);
lineno = Integer.parseInt(m.group(2));
this.linenoDifferential = lineno - presumedLineno;
}
else {
throw new RuntimeException("couldn't parse position '" + pos + "'");
}
}
public void setLineno(int presumedLineno) {
lineno = presumedLineno + linenoDifferential;
}
Pair<Boolean, String> getPreprocValue(String nm) {
public Pair<Boolean, String> getPreprocValue(String nm) {
IteratorSTL<Pair<String, String>> iter = preproc_defines.find(nm);
if (iter.isEnd()) {
return new Pair<>(false, null);
@ -842,11 +879,11 @@ public class SleighCompile extends SleighBase {
return new Pair<>(true, iter.get().second);
}
void setPreprocValue(String nm, String value) {
public void setPreprocValue(String nm, String value) {
preproc_defines.put(nm, value);
}
boolean undefinePreprocValue(String nm) {
public boolean undefinePreprocValue(String nm) {
IteratorSTL<Pair<String, String>> iter = preproc_defines.find(nm);
if (iter.isEnd()) {
return false;
@ -1281,7 +1318,7 @@ public class SleighCompile extends SleighBase {
// Match up any qualities of the macro's OperandSymbols with
// any OperandSymbol passed into the macro
void compareMacroParams(MacroSymbol sym, VectorSTL<ExprTree> param) {
public void compareMacroParams(MacroSymbol sym, VectorSTL<ExprTree> param) {
entry("compareMacroParams", sym, param);
for (int i = 0; i < param.size(); ++i) {
VarnodeTpl outvn = param.get(i).outvn;
@ -1352,7 +1389,7 @@ public class SleighCompile extends SleighBase {
}
// Reset set state after a an error in previous constructor
void resetConstructors() {
protected void resetConstructors() {
entry("resetConstructors");
symtab.setCurrentScope(symtab.getGlobalScope()); // Purge any
// dangling local
@ -1361,7 +1398,7 @@ public class SleighCompile extends SleighBase {
// Find a defining instance of the local variable
// with given -offset-
private static VarnodeTpl find_size(ConstTpl offset, ConstructTpl ct) {
private static VarnodeTpl findSize(ConstTpl offset, ConstructTpl ct) {
entry("find_size", offset, ct);
VectorSTL<OpTpl> ops = ct.getOpvec();
VarnodeTpl vn;
@ -1386,7 +1423,7 @@ public class SleighCompile extends SleighBase {
}
// Look for zero size temps in export statement
private static boolean force_exportsize(ConstructTpl ct) {
private static boolean forceExportSize(ConstructTpl ct) {
entry("force_exportsize", ct);
HandleTpl result = ct.getResult();
if (result == null) {
@ -1396,14 +1433,14 @@ public class SleighCompile extends SleighBase {
VarnodeTpl vt;
if (result.getPtrSpace().isUniqueSpace() && result.getPtrSize().isZero()) {
vt = find_size(result.getPtrOffset(), ct);
vt = findSize(result.getPtrOffset(), ct);
if (vt == null) {
return false;
}
result.setPtrSize(vt.getSize());
}
else if (result.getSpace().isUniqueSpace() && result.getSize().isZero()) {
vt = find_size(result.getPtrOffset(), ct);
vt = findSize(result.getPtrOffset(), ct);
if (vt == null) {
return false;
}
@ -1412,7 +1449,7 @@ public class SleighCompile extends SleighBase {
return true;
}
boolean expandMacros(ConstructTpl ctpl) {
private boolean expandMacros(ConstructTpl ctpl) {
VectorSTL<OpTpl> vec = ctpl.getOpvec();
VectorSTL<OpTpl> newvec = new VectorSTL<>();
IteratorSTL<OpTpl> iter;
@ -1442,7 +1479,7 @@ public class SleighCompile extends SleighBase {
return true;
}
boolean finalizeSections(Constructor big, SectionVector vec) {
private boolean finalizeSections(Constructor big, SectionVector vec) {
entry("finalizeSections", big, vec);
// Do all final checks, expansions, and linking for p-code sections
VectorSTL<String> myErrors = new VectorSTL<>();
@ -1485,7 +1522,7 @@ public class SleighCompile extends SleighBase {
if (big.getParent() == root) {
myErrors.push_back(" Cannot have export statement in root constructor");
}
else if (!force_exportsize(cur.section)) {
else if (!forceExportSize(cur.section)) {
myErrors.push_back(" Size of export is unknown");
}
}
@ -1523,7 +1560,7 @@ public class SleighCompile extends SleighBase {
return true;
}
void shiftUniqueVn(VarnodeTpl vn, int sa) {
private static void shiftUniqueVn(VarnodeTpl vn, int sa) {
entry("shiftUniqueVn", vn, sa);
// If the varnode is in the unique space, shift its offset up by -sa- bits
if (vn.getSpace().isUniqueSpace() &&
@ -1534,7 +1571,7 @@ public class SleighCompile extends SleighBase {
}
}
void shiftUniqueOp(OpTpl op, int sa) {
private static void shiftUniqueOp(OpTpl op, int sa) {
entry("shiftUniqueOp", op, sa);
// Shift the offset up by -sa- bits for any varnode used by this -op- in the unique space
VarnodeTpl outvn = op.getOut();
@ -1546,7 +1583,7 @@ public class SleighCompile extends SleighBase {
}
}
void shiftUniqueHandle(HandleTpl hand, int sa) {
private static void shiftUniqueHandle(HandleTpl hand, int sa) {
entry("shiftUniqueHandle", hand, sa);
// Shift the offset up by -sa- bits, for either the dynamic or static varnode aspects that are in the unique space
if (hand.getSpace().isUniqueSpace() &&
@ -1571,7 +1608,7 @@ public class SleighCompile extends SleighBase {
}
}
void shiftUniqueConstruct(ConstructTpl tpl, int sa) {
private static void shiftUniqueConstruct(ConstructTpl tpl, int sa) {
entry("shiftUniqueConstruct", tpl, sa);
// Shift the offset up by -sa- bits, for any varnode in the unique space associated with this template
HandleTpl result = tpl.getResult();
@ -1584,7 +1621,7 @@ public class SleighCompile extends SleighBase {
}
}
void checkUniqueAllocation() {
private void checkUniqueAllocation() {
// With crossbuilds, temporaries may need to survive across instructions in a packet, so here we
// provide space in the offset of the temporary (within the unique space) so that the run-time sleigh
// engine can alter the value to prevent collisions with other nearby instructions
@ -1623,7 +1660,7 @@ public class SleighCompile extends SleighBase {
setUniqueBase(ubase);
}
void checkFieldUsage() {
private void checkFieldUsage() {
if (warnunusedfields) {
VectorSTL<SleighSymbol> unsoughtSymbols = symtab.getUnsoughtSymbols();
IteratorSTL<SleighSymbol> siter;
@ -1718,6 +1755,93 @@ public class SleighCompile extends SleighBase {
return 0;
}
public void setAllOptions(Map<String, String> preprocs, boolean unnecessaryPcodeWarning,
boolean lenientConflict, boolean allCollisionWarning, boolean allNopWarning,
boolean deadTempWarning, boolean unusedFieldWarning, boolean enforceLocalKeyWord,
boolean largeTemporaryWarning, boolean caseSensitiveRegisterNames) {
Set<Entry<String, String>> entrySet = preprocs.entrySet();
for (Entry<String, String> entry : entrySet) {
setPreprocValue(entry.getKey(), entry.getValue());
}
setUnnecessaryPcodeWarning(unnecessaryPcodeWarning);
setLenientConflict(lenientConflict);
setLocalCollisionWarning(allCollisionWarning);
setAllNopWarning(allNopWarning);
setDeadTempWarning(deadTempWarning);
setUnusedFieldWarning(unusedFieldWarning);
setEnforceLocalKeyWord(enforceLocalKeyWord);
setLargeTemporaryWarning(largeTemporaryWarning);
setInsensitiveDuplicateError(!caseSensitiveRegisterNames);
}
public int run_compilation(String filein, String fileout)
throws IOException, RecognitionException {
LineArrayListWriter writer = new LineArrayListWriter();
ParsingEnvironment env = new ParsingEnvironment(writer);
try {
final SleighCompilePreprocessorDefinitionsAdapater definitionsAdapter =
new SleighCompilePreprocessorDefinitionsAdapater(this);
final File inputFile = new File(filein);
FileResolutionResult result = FileUtilities.existsAndIsCaseDependent(inputFile);
if (!result.isOk()) {
throw new BailoutException("input file \"" + inputFile +
"\" is not properly case dependent: " + result.getMessage());
}
SleighPreprocessor sp = new SleighPreprocessor(definitionsAdapter, inputFile);
sp.process(writer);
CharStream input = new ANTLRStringStream(writer.toString());
SleighLexer lex = new SleighLexer(input);
lex.setEnv(env);
UnbufferedTokenStream tokens = new UnbufferedTokenStream(lex);
SleighParser parser = new SleighParser(tokens);
parser.setEnv(env);
parser.setLexer(lex);
SleighParser.spec_return parserRoot = parser.spec();
/*ANTLRUtil.debugTree(root.getTree(),
new PrintStream(new FileOutputStream("blargh.tree")));*/
CommonTreeNodeStream nodes = new CommonTreeNodeStream(parserRoot.getTree());
nodes.setTokenStream(tokens);
// ANTLRUtil.debugNodeStream(nodes, System.out);
SleighCompiler walker = new SleighCompiler(nodes);
int parseres = -1;
try {
parseres = walker.root(env, this); // Try to parse
}
catch (SleighError e) {
reportError(e.location, e.getMessage());
}
if (parseres == 0) {
process(); // Do all the post-processing
}
if ((parseres == 0) && (numErrors() == 0)) {
// If no errors
PrintStream s = new PrintStream(new FileOutputStream(new File(fileout)));
saveXml(s); // Dump output xml
s.close();
}
else {
Msg.error(SleighCompile.class, "No output produced");
return 2;
}
}
catch (BailoutException e) {
Msg.error(SleighCompile.class, "Unrecoverable error(s), halting compilation", e);
return 3;
}
catch (NullPointerException e) {
Msg.error(SleighCompile.class, "Unrecoverable error(s), halting compilation", e);
return 4;
}
catch (PreprocessorException e) {
Msg.error(SleighCompile.class, e.getMessage());
Msg.error(SleighCompile.class, "Errors during preprocessing, halting compilation");
return 5;
}
return 0;
}
/**
* Run the sleigh compiler. This provides a direct means of invoking the
* compiler without using the launcher. The full SoftwareModeling classpath

View file

@ -17,24 +17,17 @@ package ghidra.pcodeCPort.slgh_compile;
import java.io.*;
import java.util.*;
import java.util.Map.Entry;
import org.antlr.runtime.*;
import org.antlr.runtime.tree.CommonTreeNodeStream;
import org.antlr.runtime.RecognitionException;
import org.jdom.JDOMException;
import generic.jar.ResourceFile;
import generic.stl.IteratorSTL;
import ghidra.GhidraApplicationLayout;
import ghidra.GhidraLaunchable;
import ghidra.framework.Application;
import ghidra.framework.ApplicationConfiguration;
import ghidra.pcodeCPort.context.SleighError;
import ghidra.sleigh.grammar.*;
import ghidra.util.Msg;
import ghidra.util.SystemUtilities;
import utilities.util.FileResolutionResult;
import utilities.util.FileUtilities;
/**
* <code>SleighCompileLauncher</code> Sleigh compiler launch provider
@ -46,24 +39,6 @@ public class SleighCompileLauncher implements GhidraLaunchable {
private static final FileFilter SLASPEC_FILTER =
pathname -> pathname.getName().endsWith(".slaspec");
private static void initCompiler(SleighCompile compiler, Map<String, String> preprocs,
boolean unnecessaryPcodeWarning, boolean lenientConflict, boolean allCollisionWarning,
boolean allNopWarning, boolean deadTempWarning, boolean unusedFieldWarning,
boolean enforceLocalKeyWord, boolean largeTemporaryWarning) {
Set<Entry<String, String>> entrySet = preprocs.entrySet();
for (Entry<String, String> entry : entrySet) {
compiler.setPreprocValue(entry.getKey(), entry.getValue());
}
compiler.setUnnecessaryPcodeWarning(unnecessaryPcodeWarning);
compiler.setLenientConflict(lenientConflict);
compiler.setLocalCollisionWarning(allCollisionWarning);
compiler.setAllNopWarning(allNopWarning);
compiler.setDeadTempWarning(deadTempWarning);
compiler.setUnusedFieldWarning(unusedFieldWarning);
compiler.setEnforceLocalKeyWord(enforceLocalKeyWord);
compiler.setLargeTemporaryWarning(largeTemporaryWarning);
}
@Override
public void launch(GhidraApplicationLayout layout, String[] args)
throws JDOMException, IOException, RecognitionException {
@ -80,9 +55,9 @@ public class SleighCompileLauncher implements GhidraLaunchable {
*
* @param args sleigh compiler command line arguments
* @return exit code (TODO: exit codes are not well defined)
* @throws JDOMException
* @throws IOException
* @throws RecognitionException
* @throws JDOMException for XML errors
* @throws IOException for file access errors
* @throws RecognitionException for parse errors
*/
public static int runMain(String[] args)
throws JDOMException, IOException, RecognitionException {
@ -113,6 +88,7 @@ public class SleighCompileLauncher implements GhidraLaunchable {
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, " -o print warnings for temporaries which are too large");
Msg.info(SleighCompile.class, " -s treat register names as case sensitive");
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, " -i <options-file> inject options from specified file");
@ -128,6 +104,7 @@ public class SleighCompileLauncher implements GhidraLaunchable {
boolean enforceLocalKeyWord = false;
boolean unusedFieldWarning = false;
boolean largeTemporaryWarning = false;
boolean caseSensitiveRegisterNames = false;
int i;
for (i = 0; i < args.length; ++i) {
@ -191,6 +168,9 @@ public class SleighCompileLauncher implements GhidraLaunchable {
else if (args[i].charAt(1) == 'o') {
largeTemporaryWarning = true;
}
else if (args[i].charAt(1) == 's') {
caseSensitiveRegisterNames = true;
}
else if (args[i].charAt(1) == 'x') {
SleighCompile.yydebug = true; // Debug option
}
@ -223,14 +203,14 @@ public class SleighCompileLauncher implements GhidraLaunchable {
for (File input : visitor) {
System.out.println("Compiling " + input + ":");
SleighCompile compiler = new SleighCompile();
initCompiler(compiler, preprocs, unnecessaryPcodeWarning, lenientConflict,
compiler.setAllOptions(preprocs, unnecessaryPcodeWarning, lenientConflict,
allCollisionWarning, allNopWarning, deadTempWarning, unusedFieldWarning,
enforceLocalKeyWord, largeTemporaryWarning);
enforceLocalKeyWord, largeTemporaryWarning, caseSensitiveRegisterNames);
String outname = input.getName().replace(".slaspec", ".sla");
File output = new File(input.getParent(), outname);
retval =
run_compilation(input.getAbsolutePath(), output.getAbsolutePath(), compiler);
compiler.run_compilation(input.getAbsolutePath(), output.getAbsolutePath());
System.out.println();
if (retval != 0) {
++totalFailures;
@ -252,9 +232,9 @@ public class SleighCompileLauncher implements GhidraLaunchable {
// single file compile
SleighCompile compiler = new SleighCompile();
initCompiler(compiler, preprocs, unnecessaryPcodeWarning, lenientConflict,
compiler.setAllOptions(preprocs, unnecessaryPcodeWarning, lenientConflict,
allCollisionWarning, allNopWarning, deadTempWarning, unusedFieldWarning,
enforceLocalKeyWord, largeTemporaryWarning);
enforceLocalKeyWord, largeTemporaryWarning, caseSensitiveRegisterNames);
if (i == args.length) {
Msg.error(SleighCompile.class, "Missing input file name");
return 1;
@ -280,7 +260,7 @@ public class SleighCompileLauncher implements GhidraLaunchable {
}
fileout = baseOutName + FILE_OUT_DEFAULT_EXT;
return run_compilation(filein, fileout, compiler);
return compiler.run_compilation(filein, fileout);
}
private static String[] injectOptionsFromFile(String[] args, int index) {
@ -326,131 +306,4 @@ public class SleighCompileLauncher implements GhidraLaunchable {
return list.toArray(new String[list.size()]);
}
private static int run_compilation(String filein, String fileout, SleighCompile compiler)
throws IOException, RecognitionException {
// try {
// compiler.parseFromNewFile(filein);
//FileInputStream yyin = new FileInputStream(new File(filein));
// StringWriter output = new StringWriter();
// System.out.println(output.toString());
// UGLY_STATIC_GLOBAL_COMPILER = null; // Set global pointer up for parser
// SleighCompiler realCompiler = new SleighCompiler(new StringReader(output.toString()));
// too late for this because we snarf a token or two on constructor time?
// if (yydebug) {
// realCompiler.enable_tracing();
// } else {
// realCompiler.disable_tracing();
// }
LineArrayListWriter writer = new LineArrayListWriter();
ParsingEnvironment env = new ParsingEnvironment(writer);
try {
final SleighCompilePreprocessorDefinitionsAdapater definitionsAdapter =
new SleighCompilePreprocessorDefinitionsAdapater(compiler);
final File inputFile = new File(filein);
FileResolutionResult result = FileUtilities.existsAndIsCaseDependent(inputFile);
if (!result.isOk()) {
throw new BailoutException("input file \"" + inputFile +
"\" is not properly case dependent: " + result.getMessage());
}
SleighPreprocessor sp = new SleighPreprocessor(definitionsAdapter, inputFile);
sp.process(writer);
CharStream input = new ANTLRStringStream(writer.toString());
SleighLexer lex = new SleighLexer(input);
lex.setEnv(env);
UnbufferedTokenStream tokens = new UnbufferedTokenStream(lex);
SleighParser parser = new SleighParser(tokens);
parser.setEnv(env);
parser.setLexer(lex);
SleighParser.spec_return root = parser.spec();
/*ANTLRUtil.debugTree(root.getTree(),
new PrintStream(new FileOutputStream("blargh.tree")));*/
CommonTreeNodeStream nodes = new CommonTreeNodeStream(root.getTree());
nodes.setTokenStream(tokens);
// ANTLRUtil.debugNodeStream(nodes, System.out);
SleighCompiler walker = new SleighCompiler(nodes);
int parseres = -1;
try {
parseres = walker.root(env, compiler); // Try to parse
}
catch (SleighError e) {
compiler.reportError(e.location, e.getMessage());
}
// yyin.close();
if (parseres == 0) {
if (compiler.noplist.size() > 0) {
if (compiler.warnallnops) {
IteratorSTL<String> iter;
for (iter = compiler.noplist.begin(); !iter.isEnd(); iter.increment()) {
Msg.warn(SleighCompile.class, iter.get());
}
}
Msg.warn(SleighCompile.class,
compiler.noplist.size() + " NOP constructors found");
if (!compiler.warnallnops) {
Msg.warn(SleighCompile.class, "Use -n switch to list each individually");
}
}
compiler.process(); // Do all the post-processing
}
if ((parseres == 0) && (compiler.numErrors() == 0)) {
// If no errors
// try {
PrintStream s = new PrintStream(new FileOutputStream(new File(fileout)));
compiler.saveXml(s); // Dump output xml
s.close();
// }
// catch (Exception e) {
// throw new SleighError("Unable to open output file: "
// + fileout);
// }
}
else {
Msg.error(SleighCompile.class, "No output produced");
return 2;
}
}
catch (BailoutException e) {
Msg.error(SleighCompile.class, "Unrecoverable error(s), halting compilation", e);
return 3;
}
catch (NullPointerException e) {
Msg.error(SleighCompile.class, "Unrecoverable error(s), halting compilation", e);
return 4;
}
catch (PreprocessorException e) {
Msg.error(SleighCompile.class, e.getMessage());
Msg.error(SleighCompile.class, "Errors during preprocessing, halting compilation");
return 5;
}
// catch (LowlevelError err) {
// Msg.info(this, "Unrecoverable error: " + err.getMessage());
// err.printStackTrace();
// return 2;
// }
// catch (IOException e) {
// Msg.info(this, "Couldn't close file: " + e.getMessage());
// return 1;
// }
// }
// catch (FileNotFoundException e) {
// Msg.info(this, "Unable to open specfile: " + filein);
// return 2;
// }
// catch (IOException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// catch (ParseException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
return 0;
}
}

View file

@ -220,8 +220,6 @@ public abstract class Translate implements BasicSpaceProvider {
public void setContextDefault(String name, int val) {
}
public abstract void addRegister(String nm, AddrSpace base, long offset, int size);
public abstract VarnodeData getRegister(String nm);
public abstract String getRegisterName(AddrSpace base, long off, int size);
@ -293,15 +291,6 @@ public abstract class Translate implements BasicSpaceProvider {
return null;
}
void addRegisterList(String[] nms, int num, AddrSpace base, long offset, int size, int skip) { // Add names assigning indices in order
// allocating -size- space for each starting at -offset-
int i;
for (i = 0; i < num; ++i) {
addRegister(nms[i], base, offset + skip * i, size);
}
}
// Associate a particular register or memory location with an address space
// The canonical example is the \b stack \b pointer and the stack space.
// The \b basespace is the so-called stack space, which is really a
@ -542,8 +531,8 @@ public abstract class Translate implements BasicSpaceProvider {
public AddrSpace getSpaceBySpacebase(Address loc, int size) { // Get space associated with spacebase register
AddrSpace id;
for (int i = 0; i < baselist.size(); ++i) {
id = baselist.get(i);
for (AddrSpace element : baselist) {
id = element;
int numspace = numSpacebase(id);
for (int j = 0; j < numspace; ++j) {
VarnodeData point = getSpacebase(id, j);