ghidra/Ghidra/Features/Decompiler/src/decompile/cpp/rulecompile.hh

204 lines
7.8 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.
*/
#ifndef __RULECOMPILE_HH__
#define __RULECOMPILE_HH__
#include "unify.hh"
namespace ghidra {
class RuleLexer {
static int4 identlist[256]; // 1 is identifier, 2 is digit, 4=namechar
map<string,int4> keywordmap;
istream *s;
char identifier[256];
int4 identlength;
int4 lookahead[4];
int4 pos;
bool endofstream;
int4 lineno;
int4 getNextChar(void) {
char c;
int4 ret = lookahead[pos];
if (!endofstream) {
(*s).get(c);
if ((*s).eof()||(c=='\0')) {
endofstream = true;
lookahead[pos] = '\n';
}
else
lookahead[pos] = c;
}
else
lookahead[pos] = -1;
pos = (pos+1)&3;
return ret;
}
int4 next(int4 i) { return lookahead[(pos+i)&3]; }
int4 scanIdentifier(void);
int4 scanNumber(void);
int4 buildString(int4 tokentype);
int4 otherIdentifiers(void);
void initKeywords(void);
public:
RuleLexer(void);
void initialize(istream &t);
int4 getLineNo(void) { return lineno; }
int4 nextToken(void);
};
class DummyTranslate : public Translate {
public:
virtual void initialize(DocumentStorage &store) {}
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 {}
virtual void getUserOpNames(vector<string> &res) const {}
virtual int4 instructionLength(const Address &baseaddr) const { return -1; }
virtual int4 oneInstruction(PcodeEmit &emit,const Address &baseaddr) const { return -1; }
virtual int4 printAssembly(AssemblyEmit &emit,const Address &baseaddr) const { return -1; }
};
class RuleCompile {
ostream *error_stream;
int4 errors;
RuleLexer lexer;
map<string,int4> namemap;
ConstraintGroup *finalrule;
vector<OpBehavior *> inst;
public:
RuleCompile(void);
~RuleCompile(void);
void ruleError(const char *s);
int4 numErrors(void) const { return errors; }
int4 getLineNo(void) { return lexer.getLineNo(); }
void setFullRule(ConstraintGroup *full) { finalrule = full; }
ConstraintGroup *getRule(void) { return finalrule; }
ConstraintGroup *releaseRule(void) { ConstraintGroup *res = finalrule; finalrule = (ConstraintGroup *)0; return res; }
const map<string,int4> &getNameMap(void) const { return namemap; }
int4 findIdentifier(string *nm);
ConstraintGroup *newOp(int4 id);
ConstraintGroup *newVarnode(int4 id);
ConstraintGroup *newConst(int4 id);
ConstraintGroup *opCopy(ConstraintGroup *base,int4 opid);
ConstraintGroup *opInput(ConstraintGroup *base,int8 *slot,int4 varid);
ConstraintGroup *opInputAny(ConstraintGroup *base,int4 varid);
ConstraintGroup *opInputConstVal(ConstraintGroup *base,int8 *slot,RHSConstant *rhs);
ConstraintGroup *opOutput(ConstraintGroup *base,int4 varid);
ConstraintGroup *varCopy(ConstraintGroup *base,int4 varid);
ConstraintGroup *varConst(ConstraintGroup *base,RHSConstant *ex,RHSConstant *sz);
ConstraintGroup *varDef(ConstraintGroup *base,int4 opid);
ConstraintGroup *varDescend(ConstraintGroup *base,int4 opid);
ConstraintGroup *varUniqueDescend(ConstraintGroup *base,int4 opid);
ConstraintGroup *opCodeConstraint(ConstraintGroup *base,vector<OpCode> *oplist);
ConstraintGroup *opCompareConstraint(ConstraintGroup *base,int4 opid,OpCode opc);
ConstraintGroup *varCompareConstraint(ConstraintGroup *base,int4 varid,OpCode opc);
ConstraintGroup *constCompareConstraint(ConstraintGroup *base,int4 constid,OpCode opc);
ConstraintGroup *constNamedExpression(int4 id,RHSConstant *expr);
ConstraintGroup *emptyGroup(void);
ConstraintGroup *emptyOrGroup(void);
ConstraintGroup *mergeGroups(ConstraintGroup *a,ConstraintGroup *b);
ConstraintGroup *addOr(ConstraintGroup *base,ConstraintGroup *newor);
ConstraintGroup *opCreation(int4 newid,OpCode oc,bool iafter,int4 oldid);
ConstraintGroup *newUniqueOut(ConstraintGroup *base,int4 varid,int4 sz);
ConstraintGroup *newSetInput(ConstraintGroup *base,RHSConstant *slot,int4 varid);
ConstraintGroup *newSetInputConstVal(ConstraintGroup *base,RHSConstant *slot,RHSConstant *val,RHSConstant *sz);
ConstraintGroup *removeInput(ConstraintGroup *base,RHSConstant *slot);
ConstraintGroup *newSetOpcode(ConstraintGroup *base,OpCode opc);
ConstraintGroup *booleanConstraint(bool ist,RHSConstant *expr);
RHSConstant *constNamed(int4 id);
RHSConstant *constAbsolute(int8 *val);
RHSConstant *constBinaryExpression(RHSConstant *ex1,OpCode opc,RHSConstant *ex2);
RHSConstant *constVarnodeSize(int4 varindex);
RHSConstant *dotIdentifier(int4 id,string *str);
int4 nextToken(void) { return lexer.nextToken(); }
void setErrorStream(ostream &t) { error_stream = &t; }
void run(istream &s,bool debug);
void postProcess(void);
int4 postProcessRule(vector<OpCode> &opcodelist);
static ConstraintGroup *buildUnifyer(const string &rule,const vector<string> &idlist,vector<int4> &res);
};
class RuleGeneric : public Rule { // A user configurable rule, (a rule read in from a file)
vector<OpCode> starterops;
int4 opinit; // Index of initialized op
ConstraintGroup *constraint;
UnifyState state;
public:
RuleGeneric(const string &g,const string &nm,const vector<OpCode> &sops,int4 opi,ConstraintGroup *c);
virtual ~RuleGeneric(void) { delete constraint; }
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0; return new RuleGeneric(getGroup(),getName(),starterops,opinit,(ConstraintGroup *)constraint->clone()); }
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
static RuleGeneric *build(const string &nm,const string &gp,const string &content);
};
/*
Definition of the language
Identifiers start with 'o' for named pcodeops
'v' for named varnodes
'#' for named constants
A "statement" is a sequence of "steps", ending in a semicolon
Steps are sequential, proceeding left to right. Each step is either a
building step (which defines a new entity in terms of an existing entity), or a
constraint (which forces a condition to be true)
Building steps:
o -> v v is the output of o
o1 -> o2 o2 is a (named) copy of o1
o <- v v is ANY input of o
o <-(0) v v is input 0 of o
o <-(1) #c input 1 to o is a constant (now named c)
o <-(1) #0 input 1 to o is a constant with value 0
v <- o o is the defining op of v
v -> o o is ANY of the ops taking v as an input (may be inefficient)
v ->! o o is the one and only op taking v as input
v1 -> v2 v2 is a (named) copy of v1
Constraints:
o(+) o must have an opcode equal '+'
o1(== o2) o1 and o2 must be the same pcode op
o1(!= o2) o1 and o2 must not be the same pcode op
v1(== v2) v1 and v2 must be the same varnode
v1(!= v2) v1 and v2 must not be the same varnode
Statements can be grouped (into "statementlist") with parentheses '(' and ')'
There is an OR operator
'[' statementlist
| statementlist
...
']'
*/
} // End namespace ghidra
#endif