mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 02:09:44 +02:00
1647 lines
43 KiB
C++
1647 lines
43 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 "unify.hh"
|
|
|
|
namespace ghidra {
|
|
|
|
UnifyDatatype::UnifyDatatype(uint4 tp)
|
|
|
|
{
|
|
type = tp;
|
|
switch(type) {
|
|
case op_type:
|
|
case var_type:
|
|
case block_type:
|
|
break;
|
|
case const_type:
|
|
storespot.cn = new uintb;
|
|
break;
|
|
default:
|
|
throw LowlevelError("Bad unify datatype");
|
|
}
|
|
}
|
|
|
|
UnifyDatatype::UnifyDatatype(const UnifyDatatype &op2)
|
|
|
|
{
|
|
type = op2.type;
|
|
switch(type) {
|
|
case op_type:
|
|
case var_type:
|
|
case block_type:
|
|
break;
|
|
case const_type:
|
|
storespot.cn = new uintb; // Copy needs its own memory
|
|
break;
|
|
default:
|
|
throw LowlevelError("Bad unify datatype");
|
|
}
|
|
}
|
|
|
|
UnifyDatatype &UnifyDatatype::operator=(const UnifyDatatype &op2)
|
|
|
|
{
|
|
switch(type) {
|
|
case op_type:
|
|
case var_type:
|
|
case block_type:
|
|
break;
|
|
case const_type:
|
|
delete storespot.cn;
|
|
break;
|
|
default:
|
|
throw LowlevelError("Bad unify datatype");
|
|
}
|
|
type = op2.type;
|
|
switch(type) {
|
|
case op_type:
|
|
case var_type:
|
|
case block_type:
|
|
break;
|
|
case const_type:
|
|
storespot.cn = new uintb; // Copy needs its own memory
|
|
break;
|
|
default:
|
|
throw LowlevelError("Bad unify datatype");
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
UnifyDatatype::~UnifyDatatype(void)
|
|
|
|
{
|
|
switch(type) {
|
|
case op_type:
|
|
case var_type:
|
|
case block_type:
|
|
break;
|
|
case const_type:
|
|
delete storespot.cn;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void UnifyDatatype::setConstant(uintb val)
|
|
|
|
{
|
|
*storespot.cn = val;
|
|
}
|
|
|
|
void UnifyDatatype::printVarDecl(ostream &s,int4 id,const UnifyCPrinter &cprinter) const
|
|
|
|
{
|
|
cprinter.printIndent(s);
|
|
switch(type) {
|
|
case op_type:
|
|
s << "PcodeOp *" << cprinter.getName(id) << ';' << endl;
|
|
break;
|
|
case var_type:
|
|
s << "Varnode *" << cprinter.getName(id) << ';' << endl;
|
|
break;
|
|
case block_type:
|
|
s << "BlockBasic *" << cprinter.getName(id) << ';' << endl;
|
|
break;
|
|
case const_type:
|
|
s << "uintb " << cprinter.getName(id) << ';' << endl;
|
|
break;
|
|
default:
|
|
throw LowlevelError("Bad unify datatype");
|
|
}
|
|
}
|
|
|
|
string UnifyDatatype::getBaseName(void) const
|
|
|
|
{
|
|
switch(type) {
|
|
case op_type:
|
|
return "op";
|
|
case var_type:
|
|
return "vn";
|
|
case block_type:
|
|
return "bl";
|
|
case const_type:
|
|
return "cn";
|
|
default:
|
|
throw LowlevelError("Bad unify datatype");
|
|
}
|
|
}
|
|
|
|
uintb ConstantNamed::getConstant(UnifyState &state) const
|
|
|
|
{
|
|
return state.data(constindex).getConstant();
|
|
}
|
|
|
|
void ConstantNamed::writeExpression(ostream &s,UnifyCPrinter &printstate) const
|
|
|
|
{
|
|
s << printstate.getName(constindex);
|
|
}
|
|
|
|
uintb ConstantAbsolute::getConstant(UnifyState &state) const
|
|
|
|
{
|
|
return val;
|
|
}
|
|
|
|
void ConstantAbsolute::writeExpression(ostream &s,UnifyCPrinter &printstate) const
|
|
|
|
{
|
|
s << "(uintb)0x" << hex << val;
|
|
}
|
|
|
|
uintb ConstantNZMask::getConstant(UnifyState &state) const
|
|
|
|
{
|
|
Varnode *vn = state.data(varindex).getVarnode();
|
|
return vn->getNZMask();
|
|
}
|
|
|
|
void ConstantNZMask::writeExpression(ostream &s,UnifyCPrinter &printstate) const
|
|
|
|
{
|
|
s << printstate.getName(varindex) << "->getNZMask()";
|
|
}
|
|
|
|
uintb ConstantConsumed::getConstant(UnifyState &state) const
|
|
|
|
{
|
|
Varnode *vn = state.data(varindex).getVarnode();
|
|
return vn->getConsume();
|
|
}
|
|
|
|
void ConstantConsumed::writeExpression(ostream &s,UnifyCPrinter &printstate) const
|
|
|
|
{
|
|
s << printstate.getName(varindex) << "->getConsume()";
|
|
}
|
|
|
|
uintb ConstantOffset::getConstant(UnifyState &state) const
|
|
|
|
{
|
|
Varnode *vn = state.data(varindex).getVarnode();
|
|
return vn->getOffset();
|
|
}
|
|
|
|
void ConstantOffset::writeExpression(ostream &s,UnifyCPrinter &printstate) const
|
|
|
|
{
|
|
s << printstate.getName(varindex) << "->getOffset()";
|
|
}
|
|
|
|
uintb ConstantIsConstant::getConstant(UnifyState &state) const
|
|
|
|
{
|
|
Varnode *vn = state.data(varindex).getVarnode();
|
|
return vn->isConstant() ? (uintb)1 : (uintb)0;
|
|
}
|
|
|
|
void ConstantIsConstant::writeExpression(ostream &s,UnifyCPrinter &printstate) const
|
|
|
|
{
|
|
s << "(uintb)" << printstate.getName(varindex) << "->isConstant()";
|
|
}
|
|
|
|
uintb ConstantHeritageKnown::getConstant(UnifyState &state) const
|
|
|
|
{
|
|
Varnode *vn = state.data(varindex).getVarnode();
|
|
return (uintb)(vn->isHeritageKnown() ? 1 : 0);
|
|
}
|
|
|
|
void ConstantHeritageKnown::writeExpression(ostream &s,UnifyCPrinter &printstate) const
|
|
|
|
{
|
|
s << "(uintb)" << printstate.getName(varindex) << "->isHeritageKnown()";
|
|
}
|
|
|
|
uintb ConstantVarnodeSize::getConstant(UnifyState &state) const
|
|
|
|
{
|
|
Varnode *vn = state.data(varindex).getVarnode();
|
|
return (uintb)vn->getSize(); // The size is the actual value
|
|
}
|
|
|
|
void ConstantVarnodeSize::writeExpression(ostream &s,UnifyCPrinter &printstate) const
|
|
|
|
{
|
|
s << "(uintb)" << printstate.getName(varindex) << "->getSize()";
|
|
}
|
|
|
|
ConstantExpression::~ConstantExpression(void)
|
|
|
|
{
|
|
delete expr1;
|
|
if (expr2 != (RHSConstant *)0)
|
|
delete expr2;
|
|
}
|
|
|
|
RHSConstant *ConstantExpression::clone(void)
|
|
|
|
{
|
|
RHSConstant *ecopy1 = expr1->clone();
|
|
RHSConstant *ecopy2 = (RHSConstant *)0;
|
|
if (expr2 != (RHSConstant *)0)
|
|
ecopy2 = expr2->clone();
|
|
return new ConstantExpression(ecopy1,ecopy2,opc);
|
|
}
|
|
|
|
uintb ConstantExpression::getConstant(UnifyState &state) const
|
|
|
|
{
|
|
OpBehavior *behavior = state.getBehavior(opc);
|
|
if (behavior->isSpecial())
|
|
throw LowlevelError("Cannot evaluate special operator in constant expression");
|
|
uintb res;
|
|
if (behavior->isUnary()) {
|
|
uintb ourconst1 = expr1->getConstant(state);
|
|
res = behavior->evaluateUnary(sizeof(uintb),sizeof(uintb),ourconst1);
|
|
}
|
|
else {
|
|
uintb ourconst1 = expr1->getConstant(state);
|
|
uintb ourconst2 = expr2->getConstant(state);
|
|
res = behavior->evaluateBinary(sizeof(uintb),sizeof(uintb),ourconst1,ourconst2);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
void ConstantExpression::writeExpression(ostream &s,UnifyCPrinter &printstate) const
|
|
|
|
{
|
|
int4 type; // 0=binary 1=unarypre 2=unarypost 3=func
|
|
string name; // name of operator
|
|
switch(opc) {
|
|
case CPUI_INT_ADD:
|
|
type=0;
|
|
name = " + ";
|
|
break;
|
|
case CPUI_INT_SUB:
|
|
type=0;
|
|
name = " - ";
|
|
break;
|
|
case CPUI_INT_AND:
|
|
type=0;
|
|
name = " & ";
|
|
break;
|
|
case CPUI_INT_OR:
|
|
type=0;
|
|
name = " | ";
|
|
break;
|
|
case CPUI_INT_XOR:
|
|
type=0;
|
|
name = " ^ ";
|
|
break;
|
|
case CPUI_INT_MULT:
|
|
type = 0;
|
|
name = " * ";
|
|
break;
|
|
case CPUI_INT_DIV:
|
|
type = 0;
|
|
name = " / ";
|
|
break;
|
|
case CPUI_INT_EQUAL:
|
|
type = 0;
|
|
name = " == ";
|
|
break;
|
|
case CPUI_INT_NOTEQUAL:
|
|
type = 0;
|
|
name = " != ";
|
|
break;
|
|
// case CPUI_INT_SLESS:
|
|
// case CPUI_INT_SLESSEQUAL:
|
|
case CPUI_INT_LESS:
|
|
type = 0;
|
|
name = " < ";
|
|
break;
|
|
case CPUI_INT_LESSEQUAL:
|
|
type = 0;
|
|
name = " <= ";
|
|
break;
|
|
// case CPUI_INT_ZEXT:
|
|
// case CPUI_INT_SEXT:
|
|
// case CPUI_INT_CARRY:
|
|
// case CPUI_INT_SCARRY:
|
|
// case CPUI_INT_SBORROW:
|
|
case CPUI_INT_LEFT:
|
|
type = 0;
|
|
name = " << ";
|
|
break;
|
|
case CPUI_INT_RIGHT:
|
|
type = 0;
|
|
name = " >> ";
|
|
break;
|
|
// case CPUI_INT_SRIGHT:
|
|
default:
|
|
throw LowlevelError("Unable to generate C for this expression element");
|
|
}
|
|
if (type==0) {
|
|
s << '(';
|
|
expr1->writeExpression(s,printstate);
|
|
s << name;
|
|
expr2->writeExpression(s,printstate);
|
|
s << ')';
|
|
}
|
|
else if (type==1) {
|
|
s << '(' << name;
|
|
expr1->writeExpression(s,printstate);
|
|
s << ')';
|
|
}
|
|
else if (type==2) {
|
|
s << '(';
|
|
expr1->writeExpression(s,printstate);
|
|
s << name << ')';
|
|
}
|
|
else {
|
|
s << name << '(';
|
|
expr1->writeExpression(s,printstate);
|
|
s << ')';
|
|
}
|
|
}
|
|
|
|
void UnifyConstraint::initialize(UnifyState &state)
|
|
|
|
{ // Default initialization (with only 1 state)
|
|
TraverseCountState *traverse = (TraverseCountState *)state.getTraverse(uniqid);
|
|
traverse->initialize(1); // Initialize with only one state
|
|
}
|
|
|
|
void UnifyConstraint::buildTraverseState(UnifyState &state)
|
|
|
|
{ // Build the default boolean traversal state
|
|
if (uniqid != state.numTraverse())
|
|
throw LowlevelError("Traverse id does not match index");
|
|
TraverseConstraint *newt = new TraverseCountState(uniqid);
|
|
state.registerTraverseConstraint(newt);
|
|
}
|
|
|
|
bool ConstraintBoolean::step(UnifyState &state)
|
|
|
|
{
|
|
TraverseCountState *traverse = (TraverseCountState *)state.getTraverse(uniqid);
|
|
if (!traverse->step()) return false;
|
|
uintb ourconst = expr->getConstant(state);
|
|
if (istrue)
|
|
return (ourconst != 0);
|
|
return (ourconst == 0);
|
|
}
|
|
|
|
void ConstraintBoolean::print(ostream &s,UnifyCPrinter &printstate) const
|
|
|
|
{
|
|
printstate.printIndent(s);
|
|
s << "if (";
|
|
expr->writeExpression(s,printstate);
|
|
if (istrue)
|
|
s << "== 0)"; // If false abort
|
|
else
|
|
s << "!= 0)"; // If true abort
|
|
s << endl;
|
|
printstate.printAbort(s);
|
|
}
|
|
|
|
ConstraintVarConst::~ConstraintVarConst(void)
|
|
|
|
{
|
|
delete expr;
|
|
if (exprsz != (RHSConstant *)0)
|
|
delete exprsz;
|
|
}
|
|
|
|
UnifyConstraint *ConstraintVarConst::clone(void) const
|
|
|
|
{
|
|
UnifyConstraint *res;
|
|
RHSConstant *newexprsz = (RHSConstant *)0;
|
|
if (exprsz != (RHSConstant *)0)
|
|
newexprsz = exprsz->clone();
|
|
res = (new ConstraintVarConst(varindex,expr->clone(),newexprsz))->copyid(this);
|
|
return res;
|
|
}
|
|
|
|
bool ConstraintVarConst::step(UnifyState &state)
|
|
|
|
{
|
|
TraverseCountState *traverse = (TraverseCountState *)state.getTraverse(uniqid);
|
|
if (!traverse->step()) return false;
|
|
uintb ourconst = expr->getConstant(state);
|
|
Funcdata *fd = state.getFunction();
|
|
int4 sz;
|
|
if (exprsz != (RHSConstant *)0)
|
|
sz = (int4)exprsz->getConstant(state);
|
|
else
|
|
sz = (int4)sizeof(uintb);
|
|
ourconst &= calc_mask(sz);
|
|
Varnode *vn = fd->newConstant( sz, ourconst );
|
|
state.data(varindex).setVarnode(vn);
|
|
return true;
|
|
}
|
|
|
|
void ConstraintVarConst::collectTypes(vector<UnifyDatatype> &typelist) const
|
|
|
|
{
|
|
typelist[varindex] = UnifyDatatype(UnifyDatatype::var_type);
|
|
}
|
|
|
|
void ConstraintVarConst::print(ostream &s,UnifyCPrinter &printstate) const
|
|
|
|
{
|
|
printstate.printIndent(s);
|
|
s << printstate.getName(varindex) << " = data.newConstant(";
|
|
if (exprsz != (RHSConstant *)0)
|
|
exprsz->writeExpression(s,printstate);
|
|
else
|
|
s << dec << (int4)sizeof(uintb);
|
|
s << ',';
|
|
expr->writeExpression(s,printstate);
|
|
s << " & calc_mask(";
|
|
exprsz->writeExpression(s,printstate);
|
|
s << "));" << endl;
|
|
}
|
|
|
|
bool ConstraintNamedExpression::step(UnifyState &state)
|
|
|
|
{
|
|
TraverseCountState *traverse = (TraverseCountState *)state.getTraverse(uniqid);
|
|
if (!traverse->step()) return false;
|
|
uintb ourconst = expr->getConstant(state);
|
|
state.data(constindex).setConstant(ourconst);
|
|
return true;
|
|
}
|
|
|
|
void ConstraintNamedExpression::collectTypes(vector<UnifyDatatype> &typelist) const
|
|
|
|
{
|
|
typelist[constindex] = UnifyDatatype(UnifyDatatype::const_type);
|
|
}
|
|
|
|
void ConstraintNamedExpression::print(ostream &s,UnifyCPrinter &printstate) const
|
|
|
|
{
|
|
printstate.printIndent(s);
|
|
s << printstate.getName(constindex) << " = ";
|
|
expr->writeExpression(s,printstate);
|
|
s << ';' << endl;
|
|
}
|
|
|
|
bool ConstraintOpCopy::step(UnifyState &state)
|
|
|
|
{
|
|
TraverseCountState *traverse = (TraverseCountState *)state.getTraverse(uniqid);
|
|
if (!traverse->step()) return false;
|
|
PcodeOp *op = state.data(oldopindex).getOp();
|
|
state.data(newopindex).setOp(op);
|
|
return true;
|
|
}
|
|
|
|
void ConstraintOpCopy::collectTypes(vector<UnifyDatatype> &typelist) const
|
|
|
|
{
|
|
typelist[oldopindex] = UnifyDatatype(UnifyDatatype::op_type);
|
|
typelist[newopindex] = UnifyDatatype(UnifyDatatype::op_type);
|
|
}
|
|
|
|
void ConstraintOpCopy::print(ostream &s,UnifyCPrinter &printstate) const
|
|
|
|
{
|
|
printstate.printIndent(s);
|
|
s << printstate.getName(newopindex) << " = " << printstate.getName(oldopindex) << ';' << endl;
|
|
}
|
|
|
|
bool ConstraintOpcode::step(UnifyState &state)
|
|
|
|
{
|
|
TraverseCountState *traverse = (TraverseCountState *)state.getTraverse(uniqid);
|
|
if (!traverse->step()) return false;
|
|
PcodeOp *op = state.data(opindex).getOp();
|
|
for(int4 i=0;i<opcodes.size();++i)
|
|
if (op->code() == opcodes[i]) return true;
|
|
return false;
|
|
}
|
|
|
|
void ConstraintOpcode::collectTypes(vector<UnifyDatatype> &typelist) const
|
|
|
|
{
|
|
typelist[opindex] = UnifyDatatype(UnifyDatatype::op_type);
|
|
}
|
|
|
|
void ConstraintOpcode::print(ostream &s,UnifyCPrinter &printstate) const
|
|
|
|
{
|
|
printstate.printIndent(s);
|
|
s << "if (";
|
|
if (opcodes.size()==1) {
|
|
s << printstate.getName(opindex) << "->code() != CPUI_" << get_opname(opcodes[0]);
|
|
}
|
|
else {
|
|
s << '(' << printstate.getName(opindex) << "->code() != CPUI_" << get_opname(opcodes[0]) << ')';
|
|
for(int4 i=1;i<opcodes.size();++i) {
|
|
s << "&&";
|
|
s << '(' << printstate.getName(opindex) << "->code() != CPUI_" << get_opname(opcodes[i]) << ')';
|
|
}
|
|
}
|
|
s << ')' << endl;
|
|
printstate.printAbort(s);
|
|
}
|
|
|
|
bool ConstraintOpCompare::step(UnifyState &state)
|
|
|
|
{
|
|
TraverseCountState *traverse = (TraverseCountState *)state.getTraverse(uniqid);
|
|
if (!traverse->step()) return false;
|
|
PcodeOp *op1 = state.data(op1index).getOp();
|
|
PcodeOp *op2 = state.data(op2index).getOp();
|
|
return ((op1==op2) == istrue);
|
|
}
|
|
|
|
void ConstraintOpCompare::collectTypes(vector<UnifyDatatype> &typelist) const
|
|
|
|
{
|
|
typelist[op1index] = UnifyDatatype(UnifyDatatype::op_type);
|
|
typelist[op2index] = UnifyDatatype(UnifyDatatype::op_type);
|
|
}
|
|
|
|
void ConstraintOpCompare::print(ostream &s,UnifyCPrinter &printstate) const
|
|
|
|
{
|
|
printstate.printIndent(s);
|
|
s << "if (" << printstate.getName(op1index);
|
|
if (istrue)
|
|
s << " != ";
|
|
else
|
|
s << " == ";
|
|
s << printstate.getName(op2index) << ')' << endl;
|
|
printstate.printAbort(s);
|
|
}
|
|
|
|
bool ConstraintOpInput::step(UnifyState &state)
|
|
|
|
{
|
|
TraverseCountState *traverse = (TraverseCountState *)state.getTraverse(uniqid);
|
|
if (!traverse->step()) return false;
|
|
PcodeOp *op = state.data(opindex).getOp();
|
|
Varnode *vn = op->getIn(slot);
|
|
state.data(varnodeindex).setVarnode(vn);
|
|
return true;
|
|
}
|
|
|
|
void ConstraintOpInput::collectTypes(vector<UnifyDatatype> &typelist) const
|
|
|
|
{
|
|
typelist[opindex] = UnifyDatatype(UnifyDatatype::op_type);
|
|
typelist[varnodeindex] = UnifyDatatype(UnifyDatatype::var_type);
|
|
}
|
|
|
|
void ConstraintOpInput::print(ostream &s,UnifyCPrinter &printstate) const
|
|
|
|
{
|
|
printstate.printIndent(s);
|
|
s << printstate.getName(varnodeindex) << " = " << printstate.getName(opindex);
|
|
s << "->getIn(" << dec << slot << ");" << endl;
|
|
}
|
|
|
|
void ConstraintOpInputAny::initialize(UnifyState &state)
|
|
|
|
{ // Default initialization (with only 1 state)
|
|
TraverseCountState *traverse = (TraverseCountState *)state.getTraverse(uniqid);
|
|
PcodeOp *op = state.data(opindex).getOp();
|
|
traverse->initialize(op->numInput()); // Initialize total number of inputs
|
|
}
|
|
|
|
bool ConstraintOpInputAny::step(UnifyState &state)
|
|
|
|
{
|
|
TraverseCountState *traverse = (TraverseCountState *)state.getTraverse(uniqid);
|
|
if (!traverse->step()) return false;
|
|
PcodeOp *op = state.data(opindex).getOp();
|
|
Varnode *vn = op->getIn(traverse->getState());
|
|
state.data(varnodeindex).setVarnode(vn);
|
|
return true;
|
|
}
|
|
|
|
void ConstraintOpInputAny::collectTypes(vector<UnifyDatatype> &typelist) const
|
|
|
|
{
|
|
typelist[opindex] = UnifyDatatype(UnifyDatatype::op_type);
|
|
typelist[varnodeindex] = UnifyDatatype(UnifyDatatype::var_type);
|
|
}
|
|
|
|
void ConstraintOpInputAny::print(ostream &s,UnifyCPrinter &printstate) const
|
|
|
|
{
|
|
printstate.printIndent(s);
|
|
s << "for(int4 i" << dec << printstate.getDepth() << "=0;i"<<printstate.getDepth()<< '<';
|
|
s << printstate.getName(opindex) << "->numInput();++i" << printstate.getDepth() << ") {" << endl;
|
|
printstate.incDepth(); // A permanent increase in depth
|
|
printstate.printIndent(s);
|
|
s << printstate.getName(varnodeindex) << " = " << printstate.getName(opindex) << "->getIn(i";
|
|
s << (printstate.getDepth()-1) << ");" << endl;
|
|
}
|
|
|
|
bool ConstraintOpOutput::step(UnifyState &state)
|
|
|
|
{
|
|
TraverseCountState *traverse = (TraverseCountState *)state.getTraverse(uniqid);
|
|
if (!traverse->step()) return false;
|
|
PcodeOp *op = state.data(opindex).getOp();
|
|
Varnode *vn = op->getOut();
|
|
state.data(varnodeindex).setVarnode(vn);
|
|
return true;
|
|
}
|
|
|
|
void ConstraintOpOutput::collectTypes(vector<UnifyDatatype> &typelist) const
|
|
|
|
{
|
|
typelist[opindex] = UnifyDatatype(UnifyDatatype::op_type);
|
|
typelist[varnodeindex] = UnifyDatatype(UnifyDatatype::var_type);
|
|
}
|
|
|
|
void ConstraintOpOutput::print(ostream &s,UnifyCPrinter &printstate) const
|
|
|
|
{
|
|
printstate.printIndent(s);
|
|
s << printstate.getName(varnodeindex) << " = " << printstate.getName(opindex) << "->getOut();" << endl;
|
|
}
|
|
|
|
bool ConstraintParamConstVal::step(UnifyState &state)
|
|
|
|
{
|
|
TraverseCountState *traverse = (TraverseCountState *)state.getTraverse(uniqid);
|
|
if (!traverse->step()) return false;
|
|
PcodeOp *op = state.data(opindex).getOp();
|
|
Varnode *vn = op->getIn(slot);
|
|
if (!vn->isConstant()) return false;
|
|
if (vn->getOffset() != (val&calc_mask(vn->getSize()))) return false;
|
|
return true;
|
|
}
|
|
|
|
void ConstraintParamConstVal::collectTypes(vector<UnifyDatatype> &typelist) const
|
|
|
|
{
|
|
typelist[opindex] = UnifyDatatype(UnifyDatatype::op_type);
|
|
}
|
|
|
|
void ConstraintParamConstVal::print(ostream &s,UnifyCPrinter &printstate) const
|
|
|
|
{
|
|
printstate.printIndent(s);
|
|
s << "if (!" << printstate.getName(opindex) << "->getIn(" << dec << slot << ")->isConstant())" << endl;
|
|
printstate.printAbort(s);
|
|
printstate.printIndent(s);
|
|
s << "if (" << printstate.getName(opindex) << "->getIn(" << dec << slot << ")->getOffset() != 0x";
|
|
s << hex << val << " & calc_mask(" << printstate.getName(opindex) << "->getIn(" << dec;
|
|
s << slot << ")->getSize()))" << endl;
|
|
printstate.printAbort(s);
|
|
}
|
|
|
|
bool ConstraintParamConst::step(UnifyState &state)
|
|
|
|
{
|
|
TraverseCountState *traverse = (TraverseCountState *)state.getTraverse(uniqid);
|
|
if (!traverse->step()) return false;
|
|
PcodeOp *op = state.data(opindex).getOp();
|
|
Varnode *vn = op->getIn(slot);
|
|
if (!vn->isConstant()) return false;
|
|
state.data(constindex).setConstant(vn->getOffset());
|
|
return true;
|
|
}
|
|
|
|
void ConstraintParamConst::collectTypes(vector<UnifyDatatype> &typelist) const
|
|
|
|
{
|
|
typelist[opindex] = UnifyDatatype(UnifyDatatype::op_type);
|
|
typelist[constindex] = UnifyDatatype(UnifyDatatype::const_type);
|
|
}
|
|
|
|
void ConstraintParamConst::print(ostream &s,UnifyCPrinter &printstate) const
|
|
|
|
{
|
|
printstate.printIndent(s);
|
|
s << "if (!" << printstate.getName(opindex) << "->getIn(" << dec << slot << ")->isConstant())" << endl;
|
|
printstate.printAbort(s);
|
|
printstate.printIndent(s);
|
|
s << printstate.getName(constindex) << " = ";
|
|
s << printstate.getName(opindex) << "->getIn(" << dec << slot << ")->getOffset();" << endl;
|
|
}
|
|
|
|
bool ConstraintVarnodeCopy::step(UnifyState &state)
|
|
|
|
{
|
|
TraverseCountState *traverse = (TraverseCountState *)state.getTraverse(uniqid);
|
|
if (!traverse->step()) return false;
|
|
Varnode *vn = state.data(oldvarindex).getVarnode();
|
|
state.data(newvarindex).setVarnode(vn);
|
|
return true;
|
|
}
|
|
|
|
void ConstraintVarnodeCopy::collectTypes(vector<UnifyDatatype> &typelist) const
|
|
|
|
{
|
|
typelist[oldvarindex] = UnifyDatatype(UnifyDatatype::var_type);
|
|
typelist[newvarindex] = UnifyDatatype(UnifyDatatype::var_type);
|
|
}
|
|
|
|
void ConstraintVarnodeCopy::print(ostream &s,UnifyCPrinter &printstate) const
|
|
|
|
{
|
|
printstate.printIndent(s);
|
|
s << printstate.getName(newvarindex) << " = " << printstate.getName(oldvarindex) << ';' << endl;
|
|
}
|
|
|
|
bool ConstraintVarCompare::step(UnifyState &state)
|
|
|
|
{
|
|
TraverseCountState *traverse = (TraverseCountState *)state.getTraverse(uniqid);
|
|
if (!traverse->step()) return false;
|
|
Varnode *vn1 = state.data(var1index).getVarnode();
|
|
Varnode *vn2 = state.data(var2index).getVarnode();
|
|
return ((vn1 == vn2)==istrue);
|
|
}
|
|
|
|
void ConstraintVarCompare::collectTypes(vector<UnifyDatatype> &typelist) const
|
|
|
|
{
|
|
typelist[var1index] = UnifyDatatype(UnifyDatatype::var_type);
|
|
typelist[var2index] = UnifyDatatype(UnifyDatatype::var_type);
|
|
}
|
|
|
|
void ConstraintVarCompare::print(ostream &s,UnifyCPrinter &printstate) const
|
|
|
|
{
|
|
printstate.printIndent(s);
|
|
s << "if (" << printstate.getName(var1index);
|
|
if (istrue)
|
|
s << " != ";
|
|
else
|
|
s << " == ";
|
|
s << printstate.getName(var2index) << ')' << endl;
|
|
printstate.printAbort(s);
|
|
}
|
|
|
|
bool ConstraintDef::step(UnifyState &state)
|
|
|
|
{
|
|
TraverseCountState *traverse = (TraverseCountState *)state.getTraverse(uniqid);
|
|
if (!traverse->step()) return false;
|
|
Varnode *vn = state.data(varindex).getVarnode();
|
|
if (!vn->isWritten()) return false;
|
|
PcodeOp *op = vn->getDef();
|
|
state.data(opindex).setOp(op);
|
|
return true;
|
|
}
|
|
|
|
void ConstraintDef::collectTypes(vector<UnifyDatatype> &typelist) const
|
|
|
|
{
|
|
typelist[opindex] = UnifyDatatype(UnifyDatatype::op_type);
|
|
typelist[varindex] = UnifyDatatype(UnifyDatatype::var_type);
|
|
}
|
|
|
|
void ConstraintDef::print(ostream &s,UnifyCPrinter &printstate) const
|
|
|
|
{
|
|
printstate.printIndent(s);
|
|
s << "if (!" << printstate.getName(varindex) << "->isWritten())" << endl;
|
|
printstate.printAbort(s);
|
|
printstate.printIndent(s);
|
|
s << printstate.getName(opindex) << " = " << printstate.getName(varindex) << "->getDef();" << endl;
|
|
}
|
|
|
|
void ConstraintDescend::buildTraverseState(UnifyState &state)
|
|
|
|
{
|
|
if (uniqid != state.numTraverse())
|
|
throw LowlevelError("Traverse id does not match index");
|
|
TraverseConstraint *newt = new TraverseDescendState(uniqid);
|
|
state.registerTraverseConstraint(newt);
|
|
}
|
|
|
|
void ConstraintDescend::initialize(UnifyState &state)
|
|
|
|
{
|
|
TraverseDescendState *traverse = (TraverseDescendState *)state.getTraverse(uniqid);
|
|
Varnode *vn = state.data(varindex).getVarnode();
|
|
traverse->initialize(vn);
|
|
}
|
|
|
|
bool ConstraintDescend::step(UnifyState &state)
|
|
|
|
{
|
|
TraverseDescendState *traverse = (TraverseDescendState *)state.getTraverse(uniqid);
|
|
if (!traverse->step()) return false;
|
|
PcodeOp *op = traverse->getCurrentOp();
|
|
state.data(opindex).setOp(op);
|
|
return true;
|
|
}
|
|
|
|
void ConstraintDescend::collectTypes(vector<UnifyDatatype> &typelist) const
|
|
|
|
{
|
|
typelist[opindex] = UnifyDatatype(UnifyDatatype::op_type);
|
|
typelist[varindex] = UnifyDatatype(UnifyDatatype::var_type);
|
|
}
|
|
|
|
void ConstraintDescend::print(ostream &s,UnifyCPrinter &printstate) const
|
|
|
|
{
|
|
printstate.printIndent(s);
|
|
s << "list<PcodeOp *>::const_iterator iter" << dec << printstate.getDepth() << ",enditer" << printstate.getDepth() << ';' << endl;
|
|
printstate.printIndent(s);
|
|
s << "iter" << printstate.getDepth() << " = " << printstate.getName(varindex) << "->beginDescend();" << endl;
|
|
printstate.printIndent(s);
|
|
s << "enditer" << printstate.getDepth() << " = " << printstate.getName(varindex) << "->endDescend();" << endl;
|
|
printstate.printIndent(s);
|
|
s << "while(iter" << printstate.getDepth() << " != enditer" << printstate.getDepth() << ") {" << endl;
|
|
printstate.incDepth(); // permanent increase in depth
|
|
printstate.printIndent(s);
|
|
s << printstate.getName(opindex) << " = *iter" << (printstate.getDepth()-1) << ';' << endl;
|
|
printstate.printIndent(s);
|
|
s << "++iter" << (printstate.getDepth()-1) << endl;
|
|
}
|
|
|
|
bool ConstraintLoneDescend::step(UnifyState &state)
|
|
|
|
{
|
|
TraverseCountState *traverse = (TraverseCountState *)state.getTraverse(uniqid);
|
|
if (!traverse->step()) return false;
|
|
Varnode *vn = state.data(varindex).getVarnode();
|
|
PcodeOp *res = vn->loneDescend();
|
|
if (res == (PcodeOp *)0) return false;
|
|
state.data(opindex).setOp(res);
|
|
return true;
|
|
}
|
|
|
|
void ConstraintLoneDescend::collectTypes(vector<UnifyDatatype> &typelist) const
|
|
|
|
{
|
|
typelist[opindex] = UnifyDatatype(UnifyDatatype::op_type);
|
|
typelist[varindex] = UnifyDatatype(UnifyDatatype::var_type);
|
|
}
|
|
|
|
void ConstraintLoneDescend::print(ostream &s,UnifyCPrinter &printstate) const
|
|
|
|
{
|
|
printstate.printIndent(s);
|
|
s << printstate.getName(opindex) << " = " << printstate.getName(varindex) << "->loneDescend();" << endl;
|
|
printstate.printIndent(s);
|
|
s << "if (" << printstate.getName(opindex) << " == (PcodeOp *)0)" << endl;
|
|
printstate.printAbort(s);
|
|
}
|
|
|
|
bool ConstraintOtherInput::step(UnifyState &state)
|
|
|
|
{
|
|
TraverseCountState *traverse = (TraverseCountState *)state.getTraverse(uniqid);
|
|
if (!traverse->step()) return false;
|
|
PcodeOp *op = state.data(opindex).getOp();
|
|
Varnode *vn = state.data(varindex_in).getVarnode();
|
|
Varnode *res = op->getIn(1-op->getSlot(vn)); // Get the "other" input
|
|
state.data(varindex_out).setVarnode(res);
|
|
return true;
|
|
}
|
|
|
|
void ConstraintOtherInput::collectTypes(vector<UnifyDatatype> &typelist) const
|
|
|
|
{
|
|
typelist[opindex] = UnifyDatatype(UnifyDatatype::op_type);
|
|
typelist[varindex_in] = UnifyDatatype(UnifyDatatype::var_type);
|
|
typelist[varindex_out] = UnifyDatatype(UnifyDatatype::var_type);
|
|
}
|
|
|
|
void ConstraintOtherInput::print(ostream &s,UnifyCPrinter &printstate) const
|
|
|
|
{
|
|
printstate.printIndent(s);
|
|
s << printstate.getName(varindex_out) << " = " << printstate.getName(opindex) << "->getIn(1 - ";
|
|
s << printstate.getName(opindex) << "->getSlot(" << printstate.getName(varindex_in) << "));" << endl;
|
|
}
|
|
|
|
bool ConstraintConstCompare::step(UnifyState &state)
|
|
|
|
{
|
|
TraverseCountState *traverse = (TraverseCountState *)state.getTraverse(uniqid);
|
|
if (!traverse->step()) return false;
|
|
uintb c1 = state.data(const1index).getConstant();
|
|
uintb c2 = state.data(const2index).getConstant();
|
|
// This only does operations with boolean result
|
|
OpBehavior *behavior = state.getBehavior(opc);
|
|
uintb res = behavior->evaluateBinary(1,sizeof(uintb),c1,c2);
|
|
return (res != 0);
|
|
}
|
|
|
|
void ConstraintConstCompare::collectTypes(vector<UnifyDatatype> &typelist) const
|
|
|
|
{
|
|
typelist[const1index] = UnifyDatatype(UnifyDatatype::const_type);
|
|
typelist[const2index] = UnifyDatatype(UnifyDatatype::const_type);
|
|
}
|
|
|
|
void ConstraintConstCompare::print(ostream &s,UnifyCPrinter &printstate) const
|
|
|
|
{
|
|
printstate.printIndent(s);
|
|
s << "if (";
|
|
switch(opc) {
|
|
case CPUI_INT_EQUAL:
|
|
s << printstate.getName(const1index) << " != " << printstate.getName(const2index);
|
|
break;
|
|
case CPUI_INT_NOTEQUAL:
|
|
s << printstate.getName(const1index) << " == " << printstate.getName(const2index);
|
|
break;
|
|
default:
|
|
s << "/* unimplemented constant operation */" ;
|
|
break;
|
|
}
|
|
s << ')' << endl;
|
|
printstate.printAbort(s);
|
|
}
|
|
|
|
ConstraintGroup::ConstraintGroup(void)
|
|
|
|
{
|
|
maxnum = -1;
|
|
}
|
|
|
|
ConstraintGroup::~ConstraintGroup(void)
|
|
|
|
{
|
|
for(uint4 i=0;i<constraintlist.size();++i)
|
|
delete constraintlist[i];
|
|
// We do not own the traverselist objects
|
|
}
|
|
|
|
void ConstraintGroup::addConstraint(UnifyConstraint *c)
|
|
|
|
{
|
|
constraintlist.push_back(c);
|
|
|
|
if (c->getMaxNum() > maxnum)
|
|
maxnum = c->getMaxNum();
|
|
}
|
|
|
|
void ConstraintGroup::deleteConstraint(int4 slot)
|
|
|
|
{
|
|
vector<UnifyConstraint *>::iterator iter = constraintlist.begin();
|
|
iter = iter + slot;
|
|
UnifyConstraint *mydel = *iter;
|
|
constraintlist.erase(iter);
|
|
delete mydel;
|
|
}
|
|
|
|
void ConstraintGroup::mergeIn(ConstraintGroup *b)
|
|
|
|
{ // Merge all the subconstraints from -b- into this
|
|
for(int4 i=0;i<b->constraintlist.size();++i)
|
|
addConstraint(b->constraintlist[i]);
|
|
b->constraintlist.clear(); // Constraints are no longer controlled by -b-
|
|
delete b;
|
|
}
|
|
|
|
UnifyConstraint *ConstraintGroup::clone(void) const
|
|
|
|
{
|
|
ConstraintGroup *res = new ConstraintGroup();
|
|
for(int4 i=0;i<constraintlist.size();++i) {
|
|
UnifyConstraint *subconst = constraintlist[i]->clone();
|
|
res->constraintlist.push_back(subconst);
|
|
}
|
|
res->copyid(this);
|
|
return res;
|
|
}
|
|
|
|
void ConstraintGroup::initialize(UnifyState &state)
|
|
|
|
{
|
|
TraverseGroupState *traverse = (TraverseGroupState *)state.getTraverse(uniqid);
|
|
traverse->setState(-1);
|
|
}
|
|
|
|
bool ConstraintGroup::step(UnifyState &state)
|
|
|
|
{
|
|
TraverseGroupState *traverse = (TraverseGroupState *)state.getTraverse(uniqid);
|
|
|
|
UnifyConstraint *subconstraint;
|
|
TraverseConstraint *subtraverse;
|
|
int4 subindex;
|
|
int4 stateint;
|
|
int4 max = constraintlist.size();
|
|
do {
|
|
stateint = traverse->getState();
|
|
if (stateint == 0) { // Attempt a step at current constraint
|
|
subindex = traverse->getCurrentIndex();
|
|
subtraverse = traverse->getSubTraverse(subindex);
|
|
subconstraint = constraintlist[subindex];
|
|
if (subconstraint->step(state)) {
|
|
traverse->setState(1); // Now try a push
|
|
subindex += 1;
|
|
traverse->setCurrentIndex(subindex);
|
|
}
|
|
else {
|
|
subindex -= 1;
|
|
if (subindex < 0) return false; // Popped off the top
|
|
traverse->setCurrentIndex(subindex);
|
|
traverse->setState(0); // Try a step next
|
|
}
|
|
}
|
|
else if (stateint == 1) { // Push
|
|
subindex = traverse->getCurrentIndex();
|
|
subtraverse = traverse->getSubTraverse(subindex);
|
|
subconstraint = constraintlist[subindex];
|
|
subconstraint->initialize(state);
|
|
traverse->setState(0); // Try a step next
|
|
}
|
|
else { // Very first time through
|
|
traverse->setCurrentIndex(0);
|
|
subindex = 0;
|
|
subtraverse = traverse->getSubTraverse(subindex);
|
|
subconstraint = constraintlist[subindex];
|
|
subconstraint->initialize(state); // Initialize the very first subcontraint
|
|
traverse->setState(0); // Now try a step
|
|
}
|
|
} while(subindex < max);
|
|
subindex -= 1;
|
|
traverse->setCurrentIndex(subindex);
|
|
traverse->setState(0); // Have full solution, do step next, to get to next solution
|
|
return true;
|
|
}
|
|
|
|
void ConstraintGroup::collectTypes(vector<UnifyDatatype> &typelist) const
|
|
|
|
{
|
|
for(int4 i=0;i<constraintlist.size();++i)
|
|
constraintlist[i]->collectTypes(typelist);
|
|
}
|
|
|
|
void ConstraintGroup::buildTraverseState(UnifyState &state)
|
|
|
|
{
|
|
if (uniqid != state.numTraverse())
|
|
throw LowlevelError("Traverse id does not match index");
|
|
TraverseGroupState *basetrav = new TraverseGroupState(uniqid);
|
|
state.registerTraverseConstraint(basetrav);
|
|
|
|
for(int4 i=0;i<constraintlist.size();++i) {
|
|
UnifyConstraint *subconstraint = constraintlist[i];
|
|
subconstraint->buildTraverseState(state);
|
|
TraverseConstraint *subtraverse = state.getTraverse(subconstraint->getId());
|
|
basetrav->addTraverse(subtraverse);
|
|
}
|
|
}
|
|
|
|
void ConstraintGroup::setId(int4 &id)
|
|
|
|
{
|
|
UnifyConstraint::setId(id);
|
|
for(int4 i=0;i<constraintlist.size();++i)
|
|
constraintlist[i]->setId(id);
|
|
}
|
|
|
|
void ConstraintGroup::print(ostream &s,UnifyCPrinter &printstate) const
|
|
|
|
{
|
|
for(int4 i=0;i<constraintlist.size();++i)
|
|
constraintlist[i]->print(s,printstate);
|
|
}
|
|
|
|
void ConstraintGroup::removeDummy(void)
|
|
|
|
{ // Remove any dummy constraints within us
|
|
vector<UnifyConstraint *> newlist;
|
|
|
|
for(int4 i=0;i<constraintlist.size();++i) {
|
|
UnifyConstraint *cur = constraintlist[i];
|
|
if (cur->isDummy()) {
|
|
delete cur;
|
|
}
|
|
else {
|
|
cur->removeDummy();
|
|
newlist.push_back(cur);
|
|
}
|
|
}
|
|
constraintlist = newlist;
|
|
}
|
|
|
|
UnifyConstraint *ConstraintOr::clone(void) const
|
|
|
|
{
|
|
ConstraintOr *res = new ConstraintOr();
|
|
for(int4 i=0;i<constraintlist.size();++i) {
|
|
UnifyConstraint *subconst = constraintlist[i]->clone();
|
|
res->constraintlist.push_back(subconst);
|
|
}
|
|
res->copyid(this);
|
|
return res;
|
|
}
|
|
|
|
void ConstraintOr::initialize(UnifyState &state)
|
|
|
|
{
|
|
TraverseCountState *traverse = (TraverseCountState *)state.getTraverse(uniqid);
|
|
traverse->initialize(constraintlist.size());
|
|
}
|
|
|
|
bool ConstraintOr::step(UnifyState &state)
|
|
|
|
{
|
|
TraverseCountState *traverse = (TraverseCountState *)state.getTraverse(uniqid);
|
|
int4 stateind = traverse->getState();
|
|
UnifyConstraint *cur;
|
|
if (stateind == -1) { // First time through
|
|
if (!traverse->step()) return false;
|
|
stateind = traverse->getState();
|
|
cur = getConstraint(stateind);
|
|
cur->initialize(state);
|
|
}
|
|
else
|
|
cur = getConstraint(stateind);
|
|
for(;;) {
|
|
if (cur->step(state)) return true;
|
|
if (!traverse->step()) break;
|
|
stateind = traverse->getState();
|
|
cur = getConstraint(stateind);
|
|
cur->initialize(state);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void ConstraintOr::buildTraverseState(UnifyState &state)
|
|
|
|
{
|
|
if (uniqid != state.numTraverse())
|
|
throw LowlevelError("Traverse id does not match index in or");
|
|
TraverseCountState *trav = new TraverseCountState(uniqid);
|
|
state.registerTraverseConstraint(trav);
|
|
|
|
for(int4 i=0;i<constraintlist.size();++i) {
|
|
UnifyConstraint *subconstraint = constraintlist[i];
|
|
subconstraint->buildTraverseState(state);
|
|
}
|
|
}
|
|
|
|
void ConstraintOr::print(ostream &s,UnifyCPrinter &printstate) const
|
|
|
|
{
|
|
printstate.printIndent(s);
|
|
s << "for(i" << dec << printstate.getDepth() << "=0;i" << printstate.getDepth() << '<';
|
|
s << (int4)constraintlist.size() << ";++i" << printstate.getDepth() << ") {" << endl;
|
|
printstate.incDepth(); // permanent increase in depth
|
|
for(int4 i=0;i<constraintlist.size();++i) {
|
|
printstate.printIndent(s);
|
|
if (i != 0)
|
|
s << "else ";
|
|
if (i != constraintlist.size()-1)
|
|
s << "if (i" << printstate.getDepth()-1 << " == " << dec << i << ") ";
|
|
s << '{' << endl;
|
|
int4 olddepth = printstate.getDepth();
|
|
printstate.incDepth();
|
|
constraintlist[i]->print(s,printstate);
|
|
printstate.popDepth(s,olddepth);
|
|
}
|
|
}
|
|
|
|
ConstraintNewOp::ConstraintNewOp(int4 newind,int4 oldind,OpCode oc,bool iafter,int4 num)
|
|
|
|
{
|
|
newopindex = newind;
|
|
oldopindex = oldind;
|
|
opc = oc;
|
|
insertafter = iafter;
|
|
numparams = num;
|
|
maxnum = (newind > oldind) ? newind : oldind;
|
|
}
|
|
|
|
bool ConstraintNewOp::step(UnifyState &state)
|
|
|
|
{
|
|
TraverseCountState *traverse = (TraverseCountState *)state.getTraverse(uniqid);
|
|
if (!traverse->step()) return false;
|
|
Funcdata *fd = state.getFunction();
|
|
PcodeOp *op = state.data(oldopindex).getOp();
|
|
PcodeOp *newop = fd->newOp(numparams,op->getAddr());
|
|
fd->opSetOpcode(newop,opc);
|
|
if (insertafter)
|
|
fd->opInsertAfter(newop,op);
|
|
else
|
|
fd->opInsertBefore(newop,op);
|
|
return true;
|
|
}
|
|
|
|
void ConstraintNewOp::collectTypes(vector<UnifyDatatype> &typelist) const
|
|
|
|
{
|
|
typelist[newopindex] = UnifyDatatype(UnifyDatatype::op_type);
|
|
typelist[oldopindex] = UnifyDatatype(UnifyDatatype::op_type);
|
|
}
|
|
|
|
void ConstraintNewOp::print(ostream &s,UnifyCPrinter &printstate) const
|
|
|
|
{
|
|
printstate.printIndent(s);
|
|
s << printstate.getName(newopindex) << " = data.newOp(" << dec << numparams;
|
|
s << ',' << printstate.getName(oldopindex) << "->getAddr());" << endl;
|
|
printstate.printIndent(s);
|
|
s << "data.opSetOpcode(" << printstate.getName(newopindex) << ",CPUI_" << get_opname(opc) << ");" << endl;
|
|
s << "data.opInsert";
|
|
if (insertafter)
|
|
s << "After(";
|
|
else
|
|
s << "Before(";
|
|
s << printstate.getName(newopindex) << ',' << printstate.getName(oldopindex) << ");" << endl;
|
|
}
|
|
|
|
ConstraintNewUniqueOut::ConstraintNewUniqueOut(int4 oind,int4 newvarind,int4 sizeind)
|
|
|
|
{
|
|
opindex = oind;
|
|
newvarindex = newvarind;
|
|
sizevarindex = sizeind;
|
|
maxnum = (opindex > newvarindex) ? opindex : newvarindex;
|
|
if (sizevarindex > maxnum)
|
|
maxnum = sizevarindex;
|
|
}
|
|
|
|
bool ConstraintNewUniqueOut::step(UnifyState &state)
|
|
|
|
{
|
|
TraverseCountState *traverse = (TraverseCountState *)state.getTraverse(uniqid);
|
|
if (!traverse->step()) return false;
|
|
Funcdata *fd = state.getFunction();
|
|
PcodeOp *op = state.data(opindex).getOp();
|
|
int4 sz;
|
|
if (sizevarindex < 0)
|
|
sz = -sizevarindex; // A specific size
|
|
else {
|
|
Varnode *sizevn = state.data(sizevarindex).getVarnode();
|
|
sz = sizevn->getSize();
|
|
}
|
|
Varnode *newvn = fd->newUniqueOut(sz,op);
|
|
state.data(newvarindex).setVarnode(newvn);
|
|
return true;
|
|
}
|
|
|
|
void ConstraintNewUniqueOut::collectTypes(vector<UnifyDatatype> &typelist) const
|
|
|
|
{
|
|
typelist[opindex] = UnifyDatatype(UnifyDatatype::op_type);
|
|
typelist[newvarindex] = UnifyDatatype(UnifyDatatype::var_type);
|
|
if (sizevarindex >= 0)
|
|
typelist[sizevarindex] = UnifyDatatype(UnifyDatatype::var_type);
|
|
}
|
|
|
|
void ConstraintNewUniqueOut::print(ostream &s,UnifyCPrinter &printstate) const
|
|
|
|
{
|
|
printstate.printIndent(s);
|
|
s << printstate.getName(newvarindex) << " = data.newUniqueOut(";
|
|
if (sizevarindex < 0)
|
|
s << dec << -sizevarindex;
|
|
else
|
|
s << printstate.getName(sizevarindex) << "->getSize()";
|
|
s << ',' << printstate.getName(opindex) << ");" << endl;
|
|
}
|
|
|
|
bool ConstraintSetInput::step(UnifyState &state)
|
|
|
|
{
|
|
TraverseCountState *traverse = (TraverseCountState *)state.getTraverse(uniqid);
|
|
if (!traverse->step()) return false;
|
|
Funcdata *fd = state.getFunction();
|
|
PcodeOp *op = state.data(opindex).getOp();
|
|
Varnode *vn = state.data(varindex).getVarnode();
|
|
int4 slt = (int4)slot->getConstant(state);
|
|
fd->opSetInput(op,vn,slt);
|
|
return true;
|
|
}
|
|
|
|
void ConstraintSetInput::collectTypes(vector<UnifyDatatype> &typelist) const
|
|
|
|
{
|
|
typelist[opindex] = UnifyDatatype(UnifyDatatype::op_type);
|
|
typelist[varindex] = UnifyDatatype(UnifyDatatype::var_type);
|
|
}
|
|
|
|
void ConstraintSetInput::print(ostream &s,UnifyCPrinter &printstate) const
|
|
|
|
{
|
|
printstate.printIndent(s);
|
|
s << "data.opSetInput(" << printstate.getName(opindex) << ',' << printstate.getName(varindex);
|
|
s << ',';
|
|
slot->writeExpression(s,printstate);
|
|
s << ");" << endl;
|
|
}
|
|
|
|
ConstraintSetInputConstVal::~ConstraintSetInputConstVal(void)
|
|
|
|
{
|
|
delete val;
|
|
delete slot;
|
|
if (exprsz != (RHSConstant *)0)
|
|
delete exprsz;
|
|
}
|
|
|
|
UnifyConstraint *ConstraintSetInputConstVal::clone(void) const
|
|
|
|
{
|
|
RHSConstant *newexprsz = (RHSConstant *)0;
|
|
if (exprsz != (RHSConstant *)0)
|
|
newexprsz = exprsz->clone();
|
|
UnifyConstraint *res;
|
|
res = (new ConstraintSetInputConstVal(opindex,slot->clone(),val->clone(),newexprsz))->copyid(this);
|
|
return res;
|
|
}
|
|
|
|
bool ConstraintSetInputConstVal::step(UnifyState &state)
|
|
|
|
{
|
|
TraverseCountState *traverse = (TraverseCountState *)state.getTraverse(uniqid);
|
|
if (!traverse->step()) return false;
|
|
Funcdata *fd = state.getFunction();
|
|
PcodeOp *op = state.data(opindex).getOp();
|
|
uintb ourconst = val->getConstant(state);
|
|
int4 sz;
|
|
if (exprsz != (RHSConstant *)0)
|
|
sz = (int4)exprsz->getConstant(state);
|
|
else
|
|
sz = (int4)sizeof(uintb);
|
|
int4 slt = (int4)slot->getConstant(state);
|
|
fd->opSetInput(op,fd->newConstant(sz,ourconst&calc_mask(sz)),slt);
|
|
return true;
|
|
}
|
|
|
|
void ConstraintSetInputConstVal::collectTypes(vector<UnifyDatatype> &typelist) const
|
|
|
|
{
|
|
typelist[opindex] = UnifyDatatype(UnifyDatatype::op_type);
|
|
// typelist[varindex] = UnifyDatatype(UnifyDatatype::var_type);
|
|
}
|
|
|
|
void ConstraintSetInputConstVal::print(ostream &s,UnifyCPrinter &printstate) const
|
|
|
|
{
|
|
printstate.printIndent(s);
|
|
s << "data.opSetInput(" << printstate.getName(opindex) << ",data.newConstant(";
|
|
if (exprsz != (RHSConstant *)0)
|
|
exprsz->writeExpression(s,printstate);
|
|
else
|
|
s << dec << (int4)sizeof(uintb);
|
|
s << ",calc_mask(";
|
|
if (exprsz != (RHSConstant *)0)
|
|
exprsz->writeExpression(s,printstate);
|
|
else
|
|
s << dec << (int4)sizeof(uintb);
|
|
s << ")&";
|
|
val->writeExpression(s,printstate);
|
|
s << "),";
|
|
slot->writeExpression(s,printstate);
|
|
s << ");" << endl;
|
|
}
|
|
|
|
bool ConstraintRemoveInput::step(UnifyState &state)
|
|
|
|
{
|
|
TraverseCountState *traverse = (TraverseCountState *)state.getTraverse(uniqid);
|
|
if (!traverse->step()) return false;
|
|
Funcdata *fd = state.getFunction();
|
|
PcodeOp *op = state.data(opindex).getOp();
|
|
int4 slt = (int4)slot->getConstant(state);
|
|
fd->opRemoveInput(op,slt);
|
|
return true;
|
|
}
|
|
|
|
void ConstraintRemoveInput::collectTypes(vector<UnifyDatatype> &typelist) const
|
|
|
|
{
|
|
typelist[opindex] = UnifyDatatype(UnifyDatatype::op_type);
|
|
}
|
|
|
|
void ConstraintRemoveInput::print(ostream &s,UnifyCPrinter &printstate) const
|
|
|
|
{
|
|
printstate.printIndent(s);
|
|
s << "data.opRemoveInput(" << printstate.getName(opindex) << ',';
|
|
slot->writeExpression(s,printstate);
|
|
s << ");" << endl;
|
|
}
|
|
|
|
bool ConstraintSetOpcode::step(UnifyState &state)
|
|
|
|
{
|
|
TraverseCountState *traverse = (TraverseCountState *)state.getTraverse(uniqid);
|
|
if (!traverse->step()) return false;
|
|
Funcdata *fd = state.getFunction();
|
|
PcodeOp *op = state.data(opindex).getOp();
|
|
fd->opSetOpcode(op,opc);
|
|
return true;
|
|
}
|
|
|
|
void ConstraintSetOpcode::collectTypes(vector<UnifyDatatype> &typelist) const
|
|
|
|
{
|
|
typelist[opindex] = UnifyDatatype(UnifyDatatype::op_type);
|
|
}
|
|
|
|
void ConstraintSetOpcode::print(ostream &s,UnifyCPrinter &printstate) const
|
|
|
|
{
|
|
printstate.printIndent(s);
|
|
s << "data.opSetOpcode(" << printstate.getName(opindex) << ",CPUI_" << get_opname(opc) << ");" << endl;
|
|
}
|
|
|
|
UnifyState::UnifyState(ConstraintGroup *uni)
|
|
|
|
{
|
|
container = uni;
|
|
storemap.resize(container->getMaxNum()+1,UnifyDatatype());
|
|
container->collectTypes(storemap);
|
|
container->buildTraverseState(*this);
|
|
}
|
|
|
|
UnifyState::~UnifyState(void)
|
|
|
|
{
|
|
for(int4 i=0;i<traverselist.size();++i)
|
|
delete traverselist[i];
|
|
}
|
|
|
|
OpBehavior *UnifyState::getBehavior(OpCode opc)
|
|
|
|
{ // Get the behavior associated with a particular opcode
|
|
Architecture *glb = fd->getArch();
|
|
return glb->inst[opc]->getBehavior();
|
|
}
|
|
|
|
void UnifyState::initialize(int4 id,Varnode *vn)
|
|
|
|
{ // Enter an initial varnode (root) starting point
|
|
storemap[id].setVarnode(vn);
|
|
}
|
|
|
|
void UnifyState::initialize(int4 id,PcodeOp *op)
|
|
|
|
{ // Enter an initial op (root) starting point
|
|
storemap[id].setOp(op);
|
|
}
|
|
|
|
void UnifyCPrinter::initializeBase(ConstraintGroup *g)
|
|
|
|
{
|
|
grp = g;
|
|
depth = 0;
|
|
namemap.clear();
|
|
storemap.clear();
|
|
opparam = -1;
|
|
opcodelist.clear();
|
|
int4 maxop = g->getMaxNum();
|
|
storemap.resize(maxop+1,UnifyDatatype());
|
|
|
|
g->collectTypes(storemap);
|
|
|
|
for(int4 i=0;i<=maxop;++i) {
|
|
ostringstream s;
|
|
s << storemap[i].getBaseName() << dec << i;
|
|
namemap.push_back(s.str());
|
|
}
|
|
}
|
|
|
|
void UnifyCPrinter::printGetOpList(ostream &s)
|
|
|
|
{ // Print the getOpList method of the new rule
|
|
s << "void " << classname << "::getOpList(vector<uint4> &oplist) const" << endl;
|
|
s << endl;
|
|
s << '{' << endl;
|
|
for(int4 i=0;i<opcodelist.size();++i) {
|
|
s << " oplist.push_back(CPUI_" << get_opname(opcodelist[i]) << ");" << endl;
|
|
}
|
|
s << '}' << endl;
|
|
s << endl;
|
|
}
|
|
|
|
void UnifyCPrinter::printRuleHeader(ostream &s)
|
|
|
|
{ // print the header for the applyOp method of the rule
|
|
s << "int " << classname << "::applyOp(PcodeOp *" << namemap[opparam] << ",Funcdata &data)" << endl;
|
|
s << endl;
|
|
s << '{' << endl;
|
|
}
|
|
|
|
void UnifyCPrinter::printAbort(ostream &s)
|
|
|
|
{
|
|
depth += 1;
|
|
printIndent(s);
|
|
if (depth >1)
|
|
s << "continue;";
|
|
else {
|
|
if (printingtype == 0)
|
|
s << "return 0;";
|
|
else
|
|
s << "return false;";
|
|
}
|
|
depth -= 1;
|
|
s << endl;
|
|
}
|
|
|
|
void UnifyCPrinter::popDepth(ostream &s,int4 newdepth)
|
|
|
|
{
|
|
while(depth != newdepth) {
|
|
depth -= 1;
|
|
printIndent(s);
|
|
s << '}' << endl;
|
|
}
|
|
}
|
|
|
|
void UnifyCPrinter::printVarDecls(ostream &s) const
|
|
|
|
{ // Print the variables declarations
|
|
for(int4 i=0;i<namemap.size();++i) {
|
|
if (i==opparam) continue;
|
|
storemap[i].printVarDecl(s,i,*this);
|
|
}
|
|
if (namemap.size() != 0)
|
|
s << endl; // Extra blank line
|
|
}
|
|
|
|
void UnifyCPrinter::initializeRuleAction(ConstraintGroup *g,int4 opp,const vector<OpCode> &oplist)
|
|
|
|
{
|
|
initializeBase(g);
|
|
printingtype = 0;
|
|
classname = "DummyRule";
|
|
|
|
opparam = opp;
|
|
opcodelist = oplist;
|
|
}
|
|
|
|
void UnifyCPrinter::initializeBasic(ConstraintGroup *g)
|
|
|
|
{
|
|
initializeBase(g);
|
|
printingtype = 1;
|
|
opparam = -1;
|
|
}
|
|
|
|
void UnifyCPrinter::addNames(const map<string,int4> &nmmap)
|
|
|
|
{
|
|
map<string,int4>::const_iterator iter;
|
|
|
|
for(iter=nmmap.begin();iter!=nmmap.end();++iter) {
|
|
int4 slot = (*iter).second;
|
|
if (namemap.size() <= slot)
|
|
throw LowlevelError("Name indices do not match constraint");
|
|
namemap[slot] = (*iter).first;
|
|
}
|
|
}
|
|
|
|
void UnifyCPrinter::print(ostream &s)
|
|
|
|
{
|
|
if (printingtype == 0) {
|
|
printGetOpList(s);
|
|
s << endl;
|
|
printRuleHeader(s);
|
|
printVarDecls(s);
|
|
grp->print(s,*this);
|
|
printIndent(s);
|
|
s << "return 1;" << endl; // Found a complete match
|
|
if (depth != 0) {
|
|
popDepth(s,0);
|
|
printIndent(s);
|
|
s << "return 0;" << endl; // Could never find a complete match
|
|
}
|
|
s << '}' << endl;
|
|
}
|
|
else if (printingtype == 1) {
|
|
printVarDecls(s);
|
|
grp->print(s,*this);
|
|
printIndent(s);
|
|
s << "return true;" << endl;
|
|
if (depth != 0) {
|
|
popDepth(s,0);
|
|
printIndent(s);
|
|
s << "return false;" << endl;
|
|
}
|
|
s << '}' << endl;
|
|
}
|
|
}
|
|
|
|
} // End namespace ghidra
|
|
#endif
|