mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
Merge remote-tracking branch 'origin/GP-927_SleighCaseSensitiveRegisters' into Ghidra_10.0
This commit is contained in:
commit
43a9499e39
14 changed files with 1607 additions and 808 deletions
|
@ -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
|
||||
|
|
|
@ -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> ®list) const {
|
||||
|
|
|
@ -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> ®list) const {}
|
||||
|
|
|
@ -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
|
||||
|
||||
{
|
||||
|
|
|
@ -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> ®list) const;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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 *> ¶ms);
|
||||
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 *> ¯otable);
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue