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

1013 lines
25 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.
*/
#ifdef CPUI_RULECOMPILE
#include "rulecompile.hh"
#include "ruleparse.hh"
namespace ghidra {
RuleCompile *rulecompile;
extern int4 ruleparsedebug;
extern int4 ruleparseparse(void);
class MyLoadImage : public LoadImage { // Dummy loadimage
public:
MyLoadImage(void) : LoadImage("nofile") {}
virtual void loadFill(uint1 *ptr,int4 size,const Address &addr) { for(int4 i=0;i<size;++i) ptr[i] = 0; }
virtual string getArchType(void) const { return "myload"; }
virtual void adjustVma(long adjust) { }
};
int4 RuleLexer::identlist[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0,
0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 5,
0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
int4 RuleLexer::scanIdentifier(void)
{
int4 i=0;
identifier[i] = (char)getNextChar(); // Scan at least the first character
i += 1;
do {
if ((identlist[next(0)]&1) != 0) {
identifier[i] = (char) getNextChar();
i += 1;
}
else
break;
} while(i<255);
if ((i==255)||(i==0))
return -1; // Identifier is too long
identifier[i] = '\0';
identlength = i;
if ((identlist[(int4)identifier[0]]&2) != 0) // First number is digit
return scanNumber();
switch(identifier[0]) {
case 'o':
return buildString(OP_IDENTIFIER);
case 'v':
return buildString(VAR_IDENTIFIER);
case '#':
return buildString(CONST_IDENTIFIER);
case 'O':
return buildString(OP_NEW_IDENTIFIER);
case 'V':
return buildString(VAR_NEW_IDENTIFIER);
case '.':
return buildString(DOT_IDENTIFIER);
default:
return otherIdentifiers();
}
}
int4 RuleLexer::scanNumber(void)
{
istringstream s(identifier);
s.unsetf(ios::dec | ios::hex | ios::oct);
uint8 val;
s >> val;
if (!s)
return BADINTEGER;
ruleparselval.big = new int8(val);
return INTB;
}
int4 RuleLexer::buildString(int4 tokentype)
{
if (identlength <= 1) return -1;
for(int4 i=1;i<identlength;++i) {
if ((identlist[(int4)identifier[i]]&4)==0) return -1;
}
if (identifier[0] == '.') {
ruleparselval.str = new string(identifier+1);
return tokentype;
}
if (identifier[0] == '#')
identifier[0] = 'c';
ruleparselval.str = new string(identifier);
return tokentype;
}
int4 RuleLexer::otherIdentifiers(void)
{
map<string,int4>::const_iterator iter;
iter = keywordmap.find(string(identifier));
if (iter != keywordmap.end())
return (*iter).second;
return -1;
}
void RuleLexer::initKeywords(void)
{
keywordmap["COPY"] = OP_COPY;
keywordmap["ZEXT"] = OP_INT_ZEXT;
keywordmap["CARRY"] = OP_INT_CARRY;
keywordmap["SCARRY"] = OP_INT_SCARRY;
keywordmap["SEXT"] = OP_INT_SEXT;
keywordmap["SBORROW"] = OP_INT_SBORROW;
keywordmap["NAN"] = OP_FLOAT_NAN;
keywordmap["ABS"] = OP_FLOAT_ABS;
keywordmap["SQRT"] = OP_FLOAT_SQRT;
keywordmap["CEIL"] = OP_FLOAT_CEIL;
keywordmap["FLOOR"] = OP_FLOAT_FLOOR;
keywordmap["ROUND"] = OP_FLOAT_ROUND;
keywordmap["INT2FLOAT"] = OP_FLOAT_INT2FLOAT;
keywordmap["FLOAT2FLOAT"] = OP_FLOAT_FLOAT2FLOAT;
keywordmap["TRUNC"] = OP_FLOAT_TRUNC;
keywordmap["GOTO"] = OP_BRANCH;
keywordmap["GOTOIND"] = OP_BRANCHIND;
keywordmap["CALL"] = OP_CALL;
keywordmap["CALLIND"] = OP_CALLIND;
keywordmap["RETURN"] = OP_RETURN;
keywordmap["CBRANCH"] = OP_CBRANCH;
keywordmap["USEROP"] = OP_CALLOTHER;
keywordmap["LOAD"] = OP_LOAD;
keywordmap["STORE"] = OP_STORE;
keywordmap["CONCAT"] = OP_PIECE;
keywordmap["SUBPIECE"] = OP_SUBPIECE;
keywordmap["before"] = BEFORE_KEYWORD;
keywordmap["after"] = AFTER_KEYWORD;
keywordmap["remove"] = REMOVE_KEYWORD;
keywordmap["set"] = SET_KEYWORD;
keywordmap["istrue"] = ISTRUE_KEYWORD;
keywordmap["isfalse"] = ISFALSE_KEYWORD;
}
int4 RuleLexer::nextToken(void)
{
for(;;) {
int4 mychar = next(0);
switch(mychar) {
case '(':
case ')':
case ',':
case '[':
case ']':
case ';':
case '{':
case '}':
case ':':
getNextChar();
ruleparselval.ch = (char)mychar;
return mychar;
case '\r':
case ' ':
case '\t':
case '\v':
getNextChar();
break;
case '\n':
getNextChar();
lineno += 1;
break;
case '-':
getNextChar();
if (next(0) == '>') {
getNextChar();
return RIGHT_ARROW;
}
else if (next(0) == '-') {
getNextChar();
if (next(0) == '>') {
getNextChar();
return DOUBLE_RIGHT_ARROW;
}
return ACTION_TICK;
}
return OP_INT_SUB;
case '<':
getNextChar();
if (next(0) == '-') {
getNextChar();
if (next(0) == '-') {
getNextChar();
return DOUBLE_LEFT_ARROW;
}
return LEFT_ARROW;
}
else if (next(0) == '<') {
getNextChar();
return OP_INT_LEFT;
}
else if (next(0) == '=') {
getNextChar();
return OP_INT_LESSEQUAL;
}
return OP_INT_LESS;
case '|':
getNextChar();
if (next(0) == '|') {
getNextChar();
return OP_BOOL_OR;
}
return OP_INT_OR;
case '&':
getNextChar();
if (next(0) == '&') {
getNextChar();
return OP_BOOL_AND;
}
return OP_INT_AND;
case '^':
getNextChar();
if (next(0) == '^') {
getNextChar();
return OP_BOOL_XOR;
}
return OP_INT_XOR;
case '>':
if (next(1) == '>') {
getNextChar();
getNextChar();
return OP_INT_RIGHT;
}
return -1;
case '=':
getNextChar();
if (next(0) == '=') {
getNextChar();
return OP_INT_EQUAL;
}
ruleparselval.ch = (char)mychar;
return mychar;
case '!':
getNextChar();
if (next(0) == '=') {
getNextChar();
return OP_INT_NOTEQUAL;
}
return OP_BOOL_NEGATE;
case 's':
if (next(1) == '/') {
getNextChar();
getNextChar();
return OP_INT_SDIV;
}
else if (next(1) == '%') {
getNextChar();
getNextChar();
return OP_INT_SREM;
}
else if ((next(1)=='>')&&(next(2)=='>')) {
getNextChar();
getNextChar();
getNextChar();
return OP_INT_SRIGHT;
}
else if (next(1)=='<') {
getNextChar();
getNextChar();
if (next(0) == '=') {
getNextChar();
return OP_INT_SLESSEQUAL;
}
return OP_INT_SLESS;
}
return scanIdentifier();
case 'f':
if (next(1) == '+') {
getNextChar();
getNextChar();
return OP_FLOAT_ADD;
}
else if (next(1) == '-') {
getNextChar();
getNextChar();
return OP_FLOAT_SUB;
}
else if (next(1) == '*') {
getNextChar();
getNextChar();
return OP_FLOAT_MULT;
}
else if (next(1) == '/') {
getNextChar();
getNextChar();
return OP_FLOAT_DIV;
}
else if ((next(1) == '=')&&(next(2) == '=')) {
getNextChar();
getNextChar();
getNextChar();
return OP_FLOAT_EQUAL;
}
else if ((next(1) == '!')&&(next(2) == '=')) {
getNextChar();
getNextChar();
getNextChar();
return OP_FLOAT_NOTEQUAL;
}
else if (next(1) == '<') {
getNextChar();
getNextChar();
if (next(0) == '=') {
getNextChar();
return OP_FLOAT_LESSEQUAL;
}
return OP_FLOAT_LESS;
}
return -1;
case '+':
getNextChar();
return OP_INT_ADD;
case '*':
getNextChar();
return OP_INT_MULT;
case '/':
getNextChar();
return OP_INT_DIV;
case '%':
getNextChar();
return OP_INT_REM;
case '~':
getNextChar();
return OP_INT_NEGATE;
case '#':
if ((identlist[next(1)]&6)==4)
return scanIdentifier();
getNextChar();
ruleparselval.ch = (char)mychar; // Return '#' as single token
return mychar;
default:
return scanIdentifier();
}
}
return -1;
}
RuleLexer::RuleLexer(void)
{
initKeywords();
}
void RuleLexer::initialize(istream &t)
{
s = &t;
pos = 0;
endofstream = false;
lineno = 1;
getNextChar();
getNextChar();
getNextChar();
getNextChar(); // Fill lookahead buffer
}
RuleCompile::RuleCompile(void)
{
DummyTranslate dummy;
error_stream = (ostream *)0;
errors = 0;
finalrule = (ConstraintGroup *)0;
OpBehavior::registerInstructions(inst,&dummy);
}
RuleCompile::~RuleCompile(void)
{
if (finalrule != (ConstraintGroup *)0)
delete finalrule;
for(int4 i=0;i<inst.size();++i) {
OpBehavior *t_op = inst[i];
if (t_op != (OpBehavior *)0)
delete t_op;
}
}
void RuleCompile::ruleError(const char *s)
{
if (error_stream != (ostream *)0) {
*error_stream << "Error at line " << dec << lexer.getLineNo() << endl;
*error_stream << " " << s << endl;
}
errors += 1;
}
int4 RuleCompile::findIdentifier(string *nm)
{
int4 resid;
map<string,int4>::const_iterator iter;
iter = namemap.find(*nm);
if (iter == namemap.end()) {
resid = namemap.size();
namemap[*nm] = resid;
}
else
resid = (*iter).second;
delete nm;
return resid;
}
ConstraintGroup *RuleCompile::newOp(int4 id)
{
ConstraintGroup *res = new ConstraintGroup();
res->addConstraint(new DummyOpConstraint(id));
return res;
}
ConstraintGroup *RuleCompile::newVarnode(int4 id)
{
ConstraintGroup *res = new ConstraintGroup();
res->addConstraint(new DummyVarnodeConstraint(id));
return res;
}
ConstraintGroup *RuleCompile::newConst(int4 id)
{
ConstraintGroup *res = new ConstraintGroup();
res->addConstraint(new DummyConstConstraint(id));
return res;
}
ConstraintGroup *RuleCompile::opCopy(ConstraintGroup *base,int4 opid)
{
int4 opindex = base->getBaseIndex();
UnifyConstraint *newconstraint = new ConstraintOpCopy(opindex,opid);
base->addConstraint(newconstraint);
return base;
}
ConstraintGroup *RuleCompile::opInput(ConstraintGroup *base,int8 *slot,int4 varid)
{
int4 ourslot = (int4) *slot;
delete slot;
int4 opindex = base->getBaseIndex();
UnifyConstraint *newconstraint = new ConstraintOpInput(opindex,varid,ourslot);
base->addConstraint(newconstraint);
return base;
}
ConstraintGroup *RuleCompile::opInputAny(ConstraintGroup *base,int4 varid)
{
int4 opindex = base->getBaseIndex();
UnifyConstraint *newconstraint = new ConstraintOpInputAny(opindex,varid);
base->addConstraint(newconstraint);
return base;
}
ConstraintGroup *RuleCompile::opInputConstVal(ConstraintGroup *base,int8 *slot,RHSConstant *val)
{
int4 ourslot = (int4) *slot;
delete slot;
int4 opindex = base->getBaseIndex();
UnifyConstraint *newconstraint;
ConstantAbsolute *myconst = dynamic_cast<ConstantAbsolute *>(val);
if (myconst != (ConstantAbsolute *)0) {
newconstraint = new ConstraintParamConstVal(opindex,ourslot,myconst->getVal());
}
else {
ConstantNamed *mynamed = dynamic_cast<ConstantNamed *>(val);
if (mynamed != (ConstantNamed *)0) {
newconstraint = new ConstraintParamConst(opindex,ourslot,mynamed->getId());
}
else {
ruleError("Can only use absolute constant here");
newconstraint = new ConstraintParamConstVal(opindex,ourslot,0);
}
}
delete val;
base->addConstraint(newconstraint);
return base;
}
ConstraintGroup *RuleCompile::opOutput(ConstraintGroup *base,int4 varid)
{
int4 opindex = base->getBaseIndex();
UnifyConstraint *newconstraint = new ConstraintOpOutput(opindex,varid);
base->addConstraint(newconstraint);
return base;
}
ConstraintGroup *RuleCompile::varCopy(ConstraintGroup *base,int4 varid)
{
int4 varindex = base->getBaseIndex();
UnifyConstraint *newconstraint = new ConstraintVarnodeCopy(varid,varindex);
base->addConstraint(newconstraint);
return base;
}
ConstraintGroup *RuleCompile::varConst(ConstraintGroup *base,RHSConstant *ex,RHSConstant *sz)
{
int4 varindex = base->getBaseIndex();
UnifyConstraint *newconstraint = new ConstraintVarConst(varindex,ex,sz);
base->addConstraint(newconstraint);
return base;
}
ConstraintGroup *RuleCompile::varDef(ConstraintGroup *base,int4 opid)
{
int4 varindex = base->getBaseIndex();
UnifyConstraint *newconstraint = new ConstraintDef(opid,varindex);
base->addConstraint(newconstraint);
return base;
}
ConstraintGroup *RuleCompile::varDescend(ConstraintGroup *base,int4 opid)
{
int4 varindex = base->getBaseIndex();
UnifyConstraint *newconstraint = new ConstraintDescend(opid,varindex);
base->addConstraint(newconstraint);
return base;
}
ConstraintGroup *RuleCompile::varUniqueDescend(ConstraintGroup *base,int4 opid)
{
int4 varindex = base->getBaseIndex();
UnifyConstraint *newconstraint = new ConstraintLoneDescend(opid,varindex);
base->addConstraint(newconstraint);
return base;
}
ConstraintGroup *RuleCompile::opCodeConstraint(ConstraintGroup *base,vector<OpCode> *oplist)
{
if (oplist->size() != 1)
throw LowlevelError("Not currently supporting multiple opcode constraints");
int4 opindex = base->getBaseIndex();
UnifyConstraint *newconstraint = new ConstraintOpcode(opindex,*oplist);
delete oplist;
base->addConstraint(newconstraint);
return base;
}
ConstraintGroup *RuleCompile::opCompareConstraint(ConstraintGroup *base,int4 opid,OpCode opc)
{
int4 op1index = base->getBaseIndex();
UnifyConstraint *newconstraint = new ConstraintOpCompare(op1index,opid,(opc==CPUI_INT_EQUAL));
base->addConstraint(newconstraint);
return base;
}
ConstraintGroup *RuleCompile::varCompareConstraint(ConstraintGroup *base,int4 varid,OpCode opc)
{
int4 var1index = base->getBaseIndex();
UnifyConstraint *newconstraint = new ConstraintVarCompare(var1index,varid,(opc==CPUI_INT_EQUAL));
base->addConstraint(newconstraint);
return base;
}
ConstraintGroup *RuleCompile::constCompareConstraint(ConstraintGroup *base,int4 constid,OpCode opc)
{
int4 const1index = base->getBaseIndex();
UnifyConstraint *newconstraint = new ConstraintConstCompare(const1index,constid,opc);
base->addConstraint(newconstraint);
return base;
}
ConstraintGroup *RuleCompile::constNamedExpression(int4 id,RHSConstant *expr)
{
ConstraintGroup *res = new ConstraintGroup();
res->addConstraint(new ConstraintNamedExpression(id,expr));
return res;
}
ConstraintGroup *RuleCompile::emptyGroup(void)
{
return new ConstraintGroup();
}
ConstraintGroup *RuleCompile::emptyOrGroup(void)
{
return new ConstraintOr();
}
ConstraintGroup *RuleCompile::mergeGroups(ConstraintGroup *a,ConstraintGroup *b)
{
a->mergeIn(b);
return a;
}
ConstraintGroup *RuleCompile::addOr(ConstraintGroup *base,ConstraintGroup *newor)
{
base->addConstraint(newor);
return base;
}
ConstraintGroup *RuleCompile::opCreation(int4 newid,OpCode oc,bool iafter,int4 oldid)
{
OpBehavior *behave = inst[oc];
int4 numparms = behave->isUnary() ? 1 : 2;
UnifyConstraint *newconstraint = new ConstraintNewOp(newid,oldid,oc,iafter,numparms);
ConstraintGroup *res = new ConstraintGroup();
res->addConstraint(newconstraint);
return res;
}
ConstraintGroup *RuleCompile::newUniqueOut(ConstraintGroup *base,int4 varid,int4 sz)
{
UnifyConstraint *newconstraint = new ConstraintNewUniqueOut(base->getBaseIndex(),varid,sz);
base->addConstraint(newconstraint);
return base;
}
ConstraintGroup *RuleCompile::newSetInput(ConstraintGroup *base,RHSConstant *slot,int4 varid)
{
UnifyConstraint *newconstraint = new ConstraintSetInput(base->getBaseIndex(),slot,varid);
base->addConstraint(newconstraint);
return base;
}
ConstraintGroup *RuleCompile::newSetInputConstVal(ConstraintGroup *base,RHSConstant *slot,RHSConstant *val,RHSConstant *sz)
{
UnifyConstraint *newconstraint = new ConstraintSetInputConstVal(base->getBaseIndex(),slot,val,sz);
base->addConstraint(newconstraint);
return base;
}
ConstraintGroup *RuleCompile::removeInput(ConstraintGroup *base,RHSConstant *slot)
{
UnifyConstraint *newconstraint = new ConstraintRemoveInput(base->getBaseIndex(),slot);
base->addConstraint(newconstraint);
return base;
}
ConstraintGroup *RuleCompile::newSetOpcode(ConstraintGroup *base,OpCode opc)
{
int4 opid = base->getBaseIndex();
UnifyConstraint *newconstraint = new ConstraintSetOpcode(opid,opc);
base->addConstraint(newconstraint);
return base;
}
ConstraintGroup *RuleCompile::booleanConstraint(bool ist,RHSConstant *expr)
{
ConstraintGroup *base = new ConstraintGroup();
UnifyConstraint *newconstraint = new ConstraintBoolean(ist,expr);
base->addConstraint(newconstraint);
return base;
}
RHSConstant *RuleCompile::constNamed(int4 id)
{
RHSConstant *res = new ConstantNamed(id);
return res;
}
RHSConstant *RuleCompile::constAbsolute(int8 *val)
{
RHSConstant *res = new ConstantAbsolute(*val);
delete val;
return res;
}
RHSConstant *RuleCompile::constBinaryExpression(RHSConstant *ex1,OpCode opc,RHSConstant *ex2)
{
RHSConstant *res = new ConstantExpression( ex1, ex2, opc );
return res;
}
RHSConstant *RuleCompile::constVarnodeSize(int4 varindex)
{
RHSConstant *res = new ConstantVarnodeSize(varindex);
return res;
}
RHSConstant *RuleCompile::dotIdentifier(int4 id,string *str)
{
RHSConstant *res;
if ((*str) == "offset")
res = new ConstantOffset(id);
else if ((*str) == "size")
res = new ConstantVarnodeSize(id);
else if ((*str) == "isconstant")
res = new ConstantIsConstant(id);
else if ((*str) == "heritageknown")
res = new ConstantHeritageKnown(id);
else if ((*str) == "consume")
res = new ConstantConsumed(id);
else if ((*str) == "nzmask")
res = new ConstantNZMask(id);
else {
string errmsg = "Unknown variable attribute: " + *str;
ruleError(errmsg.c_str());
res = new ConstantAbsolute(0);
}
delete str;
return res;
}
void RuleCompile::run(istream &s,bool debug)
{
#ifdef YYDEBUG
ruleparsedebug = debug ? 1 : 0;
#endif
if (!s) {
if (error_stream != (ostream *)0)
*error_stream << "Bad input stream to rule compiler" << endl;
return;
}
errors = 0;
if (finalrule != (ConstraintGroup *)0) {
delete finalrule;
finalrule = (ConstraintGroup *)0;
}
lexer.initialize(s);
rulecompile = this; // Setup the global pointer
int4 parseres = ruleparseparse(); // Try to parse
if (parseres!=0) {
errors += 1;
if (error_stream != (ostream *)0)
*error_stream << "Parsing error" << endl;
}
if (errors!=0) {
if (error_stream != (ostream *)0)
*error_stream << "Parsing incomplete" << endl;
}
}
void RuleCompile::postProcess(void)
{
int4 id = 0;
finalrule->removeDummy();
finalrule->setId(id); // Set id for everybody
}
int4 RuleCompile::postProcessRule(vector<OpCode> &opcodelist)
{ // Do normal post processing but also remove initial opcode check
finalrule->removeDummy();
if (finalrule->numConstraints() == 0)
throw LowlevelError("Cannot postprocess empty rule");
ConstraintOpcode *subconst = dynamic_cast<ConstraintOpcode *>(finalrule->getConstraint(0));
if (subconst == (ConstraintOpcode *)0)
throw LowlevelError("Rule does not start with opcode constraint");
opcodelist = subconst->getOpCodes();
int4 opinit = subconst->getMaxNum();
finalrule->deleteConstraint(0);
int4 id = 0;
finalrule->setId(id);
return opinit;
}
ConstraintGroup *RuleCompile::buildUnifyer(const string &rule,const vector<string> &idlist,
vector<int4> &res)
{
RuleCompile ruler;
istringstream s(rule);
ruler.run(s,false);
if (ruler.numErrors() != 0)
throw LowlevelError("Could not build rule");
ConstraintGroup *resconst = ruler.releaseRule();
for(int4 i=0;i<idlist.size();++i) {
char initc;
int4 id = -1;
map<string,int4>::const_iterator iter;
if (idlist[i].size() != 0) {
initc = idlist[i][0];
if ((initc == 'o')||(initc == 'O')||(initc == 'v')||(initc == 'V')||(initc == '#')) {
iter = ruler.namemap.find(idlist[i]);
if (iter != ruler.namemap.end())
id = (*iter).second;
}
}
if (id == -1)
throw LowlevelError("Bad initializer name: "+idlist[i]);
res.push_back(id);
}
return resconst;
}
RuleGeneric::RuleGeneric(const string &g,const string &nm,const vector<OpCode> &sops,int4 opi,ConstraintGroup *c)
: Rule(g,0,nm), state(c)
{
starterops = sops;
opinit = opi;
constraint = c;
}
void RuleGeneric::getOpList(vector<uint4> &oplist) const
{
for(int4 i=0;i<starterops.size();++i)
oplist.push_back((uint4)starterops[i]);
}
int4 RuleGeneric::applyOp(PcodeOp *op,Funcdata &data)
{
state.setFunction(&data);
state.initialize(opinit,op);
constraint->initialize(state);
return constraint->step(state);
}
RuleGeneric *RuleGeneric::build(const string &nm,const string &gp,const string &content)
{
RuleCompile compiler;
istringstream s(content);
compiler.run(s,false);
if (compiler.numErrors() != 0)
throw LowlevelError("Unable to parse dynamic rule: "+nm);
vector<OpCode> opcodelist;
int4 opinit = compiler.postProcessRule(opcodelist);
RuleGeneric *res = new RuleGeneric(gp,nm,opcodelist,opinit,compiler.releaseRule());
return res;
}
} // End namespace ghidra
#endif
/*
Here is the original flex parser
%{
#include "rulecompile.hh"
#include "ruleparse.hh"
#define ruleparsewrap() 1
#define YY_SKIP_YYWRAP
extern RuleCompile *rulecompile;
int4 scan_number(char *numtext,YYSTYPE *lval)
{
istringstream s(numtext);
s.unsetf(ios::dec | ios::hex | ios::oct);
uintb val;
s >> val;
if (!s)
return BADINTEGER;
lval->big = new intb(val);
return INTB;
}
int4 find_op_identifier(void)
{
string ident(yytext);
ruleparselval.id = rulecompile->findOpIdentifier(ident);
return OP_IDENTIFIER;
}
int4 find_var_identifier(void)
{
string ident(yytext);
ruleparselval.id = rulecompile->findVarIdentifier(ident);
return VAR_IDENTIFIER;
}
int4 find_const_identifier(void)
{
string ident(yytext);
ruleparselval.id = rulecompile->findConstIdentifier(ident);
return CONST_IDENTIFIER;
}
%}
%%
[(),\[\];\{\}\#] { ruleparselval.ch = yytext[0]; return yytext[0]; }
[0-9]+ { return scan_number(yytext,&ruleparselval); }
0x[0-9a-fA-F]+ { return scan_number(yytext,&ruleparselval); }
[\r\ \t\v]+
\n { rulecompile->nextLine(); }
\-\> { return RIGHT_ARROW; }
\<\- { return LEFT_ARROW; }
\|\| { return OP_BOOL_OR; }
\&\& { return OP_BOOL_AND; }
\^\^ { return OP_BOOL_XOR; }
\>\> { return OP_INT_RIGHT; }
\<\< { return OP_INT_LEFT; }
\=\= { return OP_INT_EQUAL; }
\!\= { return OP_INT_NOTEQUAL; }
\<\= { return OP_INT_LESSEQUAL; }
s\/ { return OP_INT_SDIV; }
s\% { return OP_INT_SREM; }
s\>\> { return OP_INT_SRIGHT; }
s\< { return OP_INT_SLESS; }
s\<\= { return OP_INT_SLESSEQUAL; }
f\+ { return OP_FLOAT_ADD; }
f\- { return OP_FLOAT_SUB; }
f\* { return OP_FLOAT_MULT; }
f\/ { return OP_FLOAT_DIV; }
f\=\= { return OP_FLOAT_EQUAL; }
f\!\= { return OP_FLOAT_NOTEQUAL; }
f\< { return OP_FLOAT_LESS; }
f\<\= { return OP_FLOAT_LESSEQUAL; }
ZEXT { return OP_INT_ZEXT; }
CARRY { return OP_INT_CARRY; }
SEXT { return OP_INT_SEXT; }
SCARRY { return OP_INT_SCARRY; }
SBORROW { return OP_INT_SBORROW; }
NAN { return OP_FLOAT_NAN; }
ABS { return OP_FLOAT_ABS; }
SQRT { return OP_FLOAT_SQRT; }
CEIL { return OP_FLOAT_CEIL; }
FLOOR { return OP_FLOAT_FLOOR; }
ROUND { return OP_FLOAT_ROUND; }
INT2FLOAT { return OP_FLOAT_INT2FLOAT; }
FLOAT2FLOAT { return OP_FLOAT_FLOAT2FLOAT; }
TRUNC { return OP_FLOAT_TRUNC; }
GOTO { return OP_BRANCH; }
GOTOIND { return OP_BRANCHIND; }
CALL { return OP_CALL; }
CALLIND { return OP_CALLIND; }
RETURN { return OP_RETURN; }
CBRRANCH { return OP_CBRANCH; }
USEROP { return OP_CALLOTHER; }
LOAD { return OP_LOAD; }
STORE { return OP_STORE; }
CONCAT { return OP_PIECE; }
SUBPIECE { return OP_SUBPIECE; }
\+ { return OP_INT_ADD; }
\- { return OP_INT_SUB; }
\! { return OP_BOOL_NEGATE; }
\& { return OP_INT_AND; }
\| { return OP_INT_OR; }
\^ { return OP_INT_XOR; }
\* { return OP_INT_MULT; }
\/ { return OP_INT_DIV; }
\% { return OP_INT_REM; }
\~ { return OP_INT_NEGATE; }
\< { return OP_INT_LESS; }
o[a-zA-Z0-9_]+ { return find_op_identifier(); }
v[a-zA-Z0-9_]+ { return find_var_identifier(); }
#[a-zA-Z0-9_]+ { return find_const_identifier(); }
*/