mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 19:42:36 +02:00
313 lines
14 KiB
C++
313 lines
14 KiB
C++
/* ###
|
|
* 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 <iostream>
|
|
#include <sstream>
|
|
|
|
// 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<RtlPair> 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<ContextChange *> contvec;
|
|
public:
|
|
WithBlock(void) { pateq = (PatternEquation *)0; }
|
|
void set(SubtableSymbol *s, PatternEquation *pq, vector<ContextChange *> *cvec);
|
|
~WithBlock(void);
|
|
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);
|
|
};
|
|
|
|
class SleighCompile;
|
|
|
|
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; }
|
|
};
|
|
SleighCompile *compiler;
|
|
int4 unnecessarypcode;
|
|
int4 readnowrite;
|
|
int4 writenoread;
|
|
bool printextwarning;
|
|
bool printdeadwarning;
|
|
SubtableSymbol *root_symbol;
|
|
vector<SubtableSymbol *> postorder;
|
|
map<SubtableSymbol *,int4> 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<uintb,OptimizeRecord> &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<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;
|
|
void applyOptimization(Constructor *ct,const OptimizeRecord &rec);
|
|
void checkUnusedTemps(Constructor *ct,const map<uintb,OptimizeRecord> &recs);
|
|
void optimize(Constructor *ct);
|
|
public:
|
|
ConsistencyChecker(SleighCompile *sleigh, 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 MacroBuilder : public PcodeBuilder {
|
|
SleighCompile *slgh;
|
|
bool haserror;
|
|
vector<OpTpl *> &outvec;
|
|
vector<HandleTpl *> params;
|
|
bool transferOp(OpTpl *op,vector<HandleTpl *> ¶ms);
|
|
virtual void dump( OpTpl *op );
|
|
void free(void);
|
|
void reportError(const Location* loc, const string &val);
|
|
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; }
|
|
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 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; }
|
|
};
|
|
|
|
class SleighCompile : public SleighBase {
|
|
friend class SleighPcode;
|
|
public:
|
|
SleighPcode pcode;
|
|
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 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;
|
|
|
|
const Location* getCurrentLocation(void) const;
|
|
void predefinedSymbols(void);
|
|
int4 calcContextVarLayout(int4 start,int4 sz,int4 numbits);
|
|
void buildDecisionTrees(void);
|
|
void buildPatterns(void);
|
|
void checkConsistency(void);
|
|
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);
|
|
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);
|
|
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);
|
|
|
|
|
|
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 setLocalCollisionWarning(bool val) { warnalllocalcollisions = 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<string> *names);
|
|
void defineBitrange(string *name,VarnodeSymbol *sym,uint4 bitoffset,uint4 numb);
|
|
void addUserOp(vector<string> *names);
|
|
void attachValues(vector<SleighSymbol *> *symlist,vector<intb> *numlist);
|
|
void attachNames(vector<SleighSymbol *> *symlist,vector<string> *names);
|
|
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);
|
|
void selfDefine(OperandSymbol *sym);
|
|
ConstructTpl *setResultVarnode(ConstructTpl *ct,VarnodeTpl *vn);
|
|
ConstructTpl *setResultStarVarnode(ConstructTpl *ct,StarQuality *star,VarnodeTpl *vn);
|
|
bool contextMod(vector<ContextChange *> *vec,ContextSymbol *sym,PatternExpression *pe);
|
|
void contextSet(vector<ContextChange *> *vec,TripleSymbol *sym,ContextSymbol *cvar);
|
|
MacroSymbol *createMacro(string *name,vector<string> *param);
|
|
void compareMacroParams(MacroSymbol *sym,const vector<ExprTree *> ¶m);
|
|
vector<OpTpl *> *createMacroUse(MacroSymbol *sym,vector<ExprTree *> *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<OpTpl *> *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<ContextChange *> *contvec);
|
|
void popWith(void);
|
|
void buildConstructor(Constructor *big,PatternEquation *pateq,vector<ContextChange *> *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;
|