mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
1013 lines
25 KiB
C++
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(); }
|
|
|
|
*/
|