/* ### * IP: GHIDRA * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "sleighbase.hh" #include "pcodecompile.hh" #include "filemanage.hh" #include #include // High-level control of the sleigh compilation process 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; } }; class SectionVector { int4 nextindex; RtlPair main; vector named; 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); }; struct SpaceQuality { // Qualities of an address space enum { // Class of space ramtype, registertype }; string name; uint4 type; uint4 size; uint4 wordsize; // number of bytes in unit of the space bool isdefault; SpaceQuality(const string &nm); }; struct FieldQuality { string name; uint4 low,high; bool signext; bool flow; bool hex; FieldQuality(string *nm,uintb *l,uintb *h); }; class WithBlock { SubtableSymbol *ss; PatternEquation *pateq; vector contvec; public: WithBlock(void) { pateq = (PatternEquation *)0; } void set(SubtableSymbol *s, PatternEquation *pq, vector *cvec); ~WithBlock(void); static PatternEquation *collectAndPrependPattern(const list &stack, PatternEquation *pateq); static vector *collectAndPrependContext(const list &stack, vector *contvec); static SubtableSymbol *getCurrentSubtable(const list &stack); }; class ConsistencyChecker { struct OptimizeRecord { int4 writeop; int4 readop; int4 inslot; int4 writecount; int4 readcount; int4 writesection; int4 readsection; int4 opttype; OptimizeRecord(void) { writeop = -1; readop = -1; inslot=-1; writecount=0; readcount=0; writesection=-2; readsection=-2; opttype=-1; } }; int4 unnecessarypcode; int4 readnowrite; int4 writenoread; bool printextwarning; bool printdeadwarning; SubtableSymbol *root_symbol; vector postorder; map sizemap; // Sizes associated with tables 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); int4 recoverSize(const ConstTpl &sizeconst,Constructor *ct); bool checkOpMisuse(OpTpl *op,Constructor *ct); bool sizeRestriction(OpTpl *op,Constructor *ct); bool checkConstructorSection(Constructor *ct,ConstructTpl *cttpl); bool checkVarnodeTruncation(Constructor *ct,int4 slot,OpTpl *op,VarnodeTpl *vn,bool isbigendian); bool checkSectionTruncations(Constructor *ct,ConstructTpl *cttpl,bool isbigendian); bool checkSubtable(SubtableSymbol *sym); void dealWithUnnecessaryExt(OpTpl *op,Constructor *ct); void dealWithUnnecessaryTrunc(OpTpl *op,Constructor *ct); void setPostOrder(SubtableSymbol *root); // Establish table ordering // Optimization routines static void examineVn(map &recs,const VarnodeTpl *vn,uint4 i,int4 inslot,int4 secnum); static bool possibleIntersection(const VarnodeTpl *vn1,const VarnodeTpl *vn2); bool readWriteInterference(const VarnodeTpl *vn,const OpTpl *op,bool checkread) const; void optimizeGather1(Constructor *ct,map &recs,int4 secnum) const; void optimizeGather2(Constructor *ct,map &recs,int4 secnum) const; OptimizeRecord *findValidRule(Constructor *ct,map &recs) const; void applyOptimization(Constructor *ct,const OptimizeRecord &rec); void checkUnusedTemps(Constructor *ct,const map &recs); void optimize(Constructor *ct); public: ConsistencyChecker(SubtableSymbol *rt,bool unnecessary,bool warndead); 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; } }; struct FieldContext { VarnodeSymbol *sym; FieldQuality *qual; bool operator<(const FieldContext &op2) const; FieldContext(VarnodeSymbol *s,FieldQuality *q) { sym=s; qual=q; } }; class SleighCompile; class MacroBuilder : public PcodeBuilder { SleighCompile *slgh; bool haserror; vector &outvec; vector params; bool transferOp(OpTpl *op,vector ¶ms); virtual void dump( OpTpl *op ); void free(void); void reportError(const string &val); public: MacroBuilder(SleighCompile *sl,vector &ovec,uint4 lbcnt) : PcodeBuilder(lbcnt),outvec(ovec) { slgh = sl; haserror = false; } void setMacroOp(OpTpl *macroop); bool hasError(void) const { return haserror; } virtual ~MacroBuilder(void) { free(); } virtual void appendBuild(OpTpl *bld,int4 secnum) { dump(bld); } virtual void delaySlot(OpTpl *op) { dump(op); } virtual void setLabel(OpTpl *op); virtual void appendCrossBuild(OpTpl *bld,int4 secnum) { dump(bld); } }; class SleighPcode : public PcodeCompile { SleighCompile *compiler; virtual uintb allocateTemp(void); virtual void reportError(const string &msg); virtual void addSymbol(SleighSymbol *sym); public: SleighPcode(void) : PcodeCompile() { compiler = (SleighCompile *)0; } void setCompiler(SleighCompile *comp) { compiler = comp; } }; class SleighCompile : public SleighBase { friend class SleighPcode; public: SleighPcode pcode; private: map preproc_defines; // Defines for the preprocessor vector contexttable; vector macrotable; vector tokentable; vector tables; vector sections; list withstack; Constructor *curct; // Current constructor being defined MacroSymbol *curmacro; // Current macro being defined bool contextlock; // If the context layout has been established yet vector relpath; // Relative path (to cwd) for each filename vector filename; // Stack of current files being parsed vector lineno; // Current line number for each file in stack 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 warnallnops; // True if pcode NOPs generate individual warnings vector noplist; // List of individual NOP warnings int4 errors; void predefinedSymbols(void); int4 calcContextVarLayout(int4 start,int4 sz,int4 numbits); void buildDecisionTrees(void); void buildPatterns(void); void checkConsistency(void); void checkNops(void); string checkSymbols(SymbolScope *scope); void addSymbol(SleighSymbol *sym); SleighSymbol *dedupSymbolList(vector *symlist); bool expandMacros(ConstructTpl *ctpl,const vector ¯otable); bool finalizeSections(Constructor *big,SectionVector *vec); 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); public: SleighCompile(void); void reportError(const string &msg,bool includeline); void reportWarning(const string &msg,bool includeline); int4 numErrors(void) const { return errors; } uintb getUniqueAddr(void); void setUnnecessaryPcodeWarning(bool val) { warnunnecessarypcode = val; } void setDeadTempWarning(bool val) { warndeadtemps = val; } void setEnforceLocalKeyWord(bool val) { pcode.setEnforceLocalKey(val); } void setLenientConflict(bool val) { lenientconflicterrors = val; } void setAllNopWarning(bool val) { warnallnops = val; } void process(void); // 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); // Parser functions TokenSymbol *defineToken(string *name,uintb *sz); void addTokenField(TokenSymbol *sym,FieldQuality *qual); bool addContextField(VarnodeSymbol *sym,FieldQuality *qual); void newSpace(SpaceQuality *qual); SectionSymbol *newSectionSymbol(const string &nm); void setEndian(int4 end); void setAlignment(int4 val) { alignment = val; } void defineVarnodes(SpaceSymbol *spacesym,uintb *off,uintb *size,vector *names); void defineBitrange(string *name,VarnodeSymbol *sym,uint4 bitoffset,uint4 numb); void addUserOp(vector *names); void attachValues(vector *symlist,vector *numlist); void attachNames(vector *symlist,vector *names); void attachVarnodes(vector *symlist,vector *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); void selfDefine(OperandSymbol *sym); ConstructTpl *setResultVarnode(ConstructTpl *ct,VarnodeTpl *vn); ConstructTpl *setResultStarVarnode(ConstructTpl *ct,StarQuality *star,VarnodeTpl *vn); bool contextMod(vector *vec,ContextSymbol *sym,PatternExpression *pe); void contextSet(vector *vec,TripleSymbol *sym,ContextSymbol *cvar); MacroSymbol *createMacro(string *name,vector *param); void compareMacroParams(MacroSymbol *sym,const vector ¶m); vector *createMacroUse(MacroSymbol *sym,vector *param); SectionVector *standaloneSection(ConstructTpl *main); SectionVector *firstNamedSection(ConstructTpl *main,SectionSymbol *sym); SectionVector *nextNamedSection(SectionVector *vec,ConstructTpl *section,SectionSymbol *sym); SectionVector *finalNamedSection(SectionVector *vec,ConstructTpl *section); vector *createCrossBuild(VarnodeTpl *addr,SectionSymbol *sym); Constructor *createConstructor(SubtableSymbol *sym); bool isInRoot(Constructor *ct) const { return (root == ct->getParent()); } void resetConstructors(void); void pushWith(SubtableSymbol *ss,PatternEquation *pateq,vector *contvec); void popWith(void); void buildConstructor(Constructor *big,PatternEquation *pateq,vector *contvec,SectionVector *vec); void buildMacro(MacroSymbol *sym,ConstructTpl *rtl); void recordNop(void); // Virtual functions (not used by the compiler) virtual void initialize(DocumentStorage &store) {} 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; } }; extern SleighCompile *slgh; extern int yydebug;