Skip to content

Commit

Permalink
Various fixes for jump table analysis 1. add instruction semantics fo…
Browse files Browse the repository at this point in the history
…r conditional moves 2. correctly distinguish zero extended memory read from sign extended memory read 3. ignore variable size when tracking variable aliasing 4. more precise bound tracking for sub instruction
  • Loading branch information
mxz297 committed Jun 10, 2016
1 parent 1bad741 commit eedef36
Show file tree
Hide file tree
Showing 8 changed files with 144 additions and 37 deletions.
4 changes: 2 additions & 2 deletions dataflowAPI/rose/x86_64InstructionSemantics.h
Original file line number Diff line number Diff line change
Expand Up @@ -2403,7 +2403,7 @@ struct X86_64InstructionSemantics {
default: ROSE_ASSERT(!"Bad size"); break; \
} \
}
/* case x86_cmovne: CMOV(ne); break;
case x86_cmovne: CMOV(ne); break;
case x86_cmove: CMOV(e); break;
case x86_cmovno: CMOV(no); break;
case x86_cmovo: CMOV(o); break;
Expand All @@ -2419,7 +2419,7 @@ struct X86_64InstructionSemantics {
case x86_cmovg: CMOV(g); break;
case x86_cmovge: CMOV(ge); break;
case x86_cmovl: CMOV(l); break;
*/

# undef CMOV

/* The flag expressions are no longer needed */
Expand Down
29 changes: 27 additions & 2 deletions parseAPI/src/BoundFactCalculator.C
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ BoundFact* BoundFactsCalculator::Meet(Node::Ptr curNode) {
prevFact = new BoundFact(*prevFact);
newCopy = true;
parsing_printf("\t\tThe predecessor node is the virtual entry ndoe\n");
if (firstBlock) {
if (firstBlock && handleOneByteRead) {
// If the indirect jump is in the entry block
// of the function, we assume that rax is in
// range [0,8] for analyzing the movaps table.
Expand Down Expand Up @@ -430,7 +430,22 @@ void BoundFactsCalculator::CalcTransferFunction(Node::Ptr curNode, BoundFact *ne
}

AST::Ptr calculation = expandRet.first;
BoundCalcVisitor bcv(*newFact, node->block(), handleOneByteRead);
int derefSize = 0;
if (node->assign() && node->assign()->insn() && node->assign()->insn()->readsMemory()) {
Instruction::Ptr i = node->assign()->insn();
std::vector<Operand> ops;
i->getOperands(ops);
for (auto oit = ops.begin(); oit != ops.end(); ++oit) {
Operand o = *oit;
if (o.readsMemory()) {
Expression::Ptr exp = o.getValue();
derefSize = exp->size();
break;
}
}

}
BoundCalcVisitor bcv(*newFact, node->block(), handleOneByteRead, derefSize);
calculation->accept(&bcv);
AST::Ptr outAST;
// If the instruction writes memory,
Expand Down Expand Up @@ -513,6 +528,8 @@ void BoundFactsCalculator::CalcTransferFunction(Node::Ptr curNode, BoundFact *ne
parsing_printf("\t\t\t%s and %s are equal\n", calculation->format().c_str(), outAST->format().c_str());
newFact->InsertRelation(calculation, outAST, BoundFact::Equal);
}
if (id == e_movzx)
newFact->CheckZeroExtend(outAST);
newFact->AdjustPredicate(outAST, calculation);

// Now try to track all aliasing.
Expand All @@ -528,6 +545,14 @@ void BoundFactsCalculator::CalcTransferFunction(Node::Ptr curNode, BoundFact *ne
parsing_printf("\t\t\tGenerate stricter bound fact for %s\n", outAST->format().c_str());
newFact->GenFact(outAST, strictValue, false);
}
// Apply tracking relations to the calculation for expression like
// r8 - ((r8 >> 4) << 4), which guarantees that
// r8 is in [0, 2^4-1]
strictValue = newFact->ApplyRelations2(outAST);
if (strictValue != NULL) {
parsing_printf("\t\t\tGenerate stricter bound fact for %s\n", outAST->format().c_str());
newFact->GenFact(outAST, strictValue, false);
}
parsing_printf("\t\t\tCalculating transfer function: Output facts\n");
newFact->Print();

Expand Down
70 changes: 63 additions & 7 deletions parseAPI/src/BoundFactData.C
Original file line number Diff line number Diff line change
Expand Up @@ -360,28 +360,32 @@ BoundValue::BoundValue(int64_t val):
targetBase(0),
tableReadSize(0),
isInverted(false),
isSubReadContent(false) {}
isSubReadContent(false),
isZeroExtend(false) {}

BoundValue::BoundValue(const StridedInterval &si):
interval(si),
targetBase(0),
tableReadSize(0),
isInverted(false),
isSubReadContent(false) {}
isSubReadContent(false),
isZeroExtend(false){}

BoundValue::BoundValue():
interval(),
targetBase(0),
tableReadSize(0),
isInverted(false),
isSubReadContent(false) {}
isSubReadContent(false),
isZeroExtend(false) {}

BoundValue::BoundValue(const BoundValue & bv):
interval(bv.interval),
targetBase(bv.targetBase),
tableReadSize(bv.tableReadSize),
isInverted(bv.isInverted),
isSubReadContent(bv.isSubReadContent)
isSubReadContent(bv.isSubReadContent),
isZeroExtend(bv.isZeroExtend)
{
}

Expand All @@ -391,7 +395,8 @@ bool BoundValue::operator == (const BoundValue &bv) const {
(targetBase == bv.targetBase) &&
(tableReadSize == bv.tableReadSize) &&
(isInverted == bv.isInverted) &&
(isSubReadContent == bv.isSubReadContent);
(isSubReadContent == bv.isSubReadContent) &&
(isZeroExtend == bv.isZeroExtend);
}

bool BoundValue::operator != (const BoundValue &bv) const {
Expand All @@ -405,6 +410,7 @@ BoundValue & BoundValue::operator = (const BoundValue &bv) {
tableReadSize = bv.tableReadSize;
isInverted = bv.isInverted;
isSubReadContent = bv.isSubReadContent;
isZeroExtend = bv.isZeroExtend;
return *this;

}
Expand All @@ -414,7 +420,8 @@ void BoundValue::Print() {
parsing_printf("targetBase %lx, ",targetBase);
parsing_printf("tableReadSize %d, ", tableReadSize);
parsing_printf("isInverted %d, ", isInverted);
parsing_printf("isSubReadContent %d\n", isSubReadContent);
parsing_printf("isSubReadContent %d, ", isSubReadContent);
parsing_printf("isZeroExtend %d\n", isZeroExtend);
}


Expand Down Expand Up @@ -478,6 +485,7 @@ void BoundValue::Join(BoundValue &bv) {
if (targetBase != bv.targetBase) targetBase = 0;
if (isInverted != bv.isInverted) isInverted = false;
if (isSubReadContent != bv.isSubReadContent) isSubReadContent = false;
if (isZeroExtend != bv.isZeroExtend) isZeroExtend = false;
}
}

Expand All @@ -486,6 +494,7 @@ void BoundValue::ClearTableCheck(){
targetBase = 0;
isInverted = false;
isSubReadContent = false;
isZeroExtend = false;
}

void BoundValue::Add(const BoundValue &rhs) {
Expand Down Expand Up @@ -773,7 +782,9 @@ void BoundFact::GenFact(const AST::Ptr ast, BoundValue* bv, bool isConditionalJu
// Only check alias for bound produced by conditinal jumps.
if (isConditionalJump) {
AST::Ptr subAST = DeepCopyAnAST(ast);
parsing_printf("Before substitute %s\n", ast->format().c_str());
subAST = SubstituteAnAST(subAST, aliasMap);
parsing_printf("After substitute %s\n", subAST->format().c_str());
if (!(*subAST == *ast)) {
KillFact(subAST, true);
fact.insert(make_pair(subAST, new BoundValue(*bv)));
Expand All @@ -794,7 +805,8 @@ static bool IsSubTree(AST::Ptr tree, AST::Ptr sub) {

void BoundFact::KillFact(const AST::Ptr ast, bool isConditionalJump) {
for (auto fit = fact.begin(); fit != fact.end();)
if (IsSubTree(fit->first, ast)) {
// if (IsSubTree(fit->first, ast)) {
if (*fit->first == *ast) {
auto toErase = fit;
++fit;
if (toErase->second != NULL) delete toErase->second;
Expand Down Expand Up @@ -1560,6 +1572,40 @@ BoundValue * BoundFact::ApplyRelations(AST::Ptr outAST) {
return NULL;
}

BoundValue * BoundFact::ApplyRelations2(AST::Ptr outAST) {
AST::Ptr cal;
for (auto ait = aliasMap.begin(); ait != aliasMap.end(); ++ait)
if ( *(ait->first) == *outAST) {
cal = ait->second;
break;
}
parsing_printf("\t\tApply relations2 to %s\n", cal->format().c_str());
if (cal->getID() != AST::V_RoseAST) return NULL;
RoseAST::Ptr root = boost::static_pointer_cast<RoseAST>(cal);
if (root->val().op != ROSEOperation::addOp) return NULL;
if (root->child(0)->getID() != AST::V_VariableAST || root->child(1)->getID() != AST::V_RoseAST) return NULL;
VariableAST::Ptr leftChild = boost::static_pointer_cast<VariableAST>(root->child(0));
RoseAST::Ptr rightChild = boost::static_pointer_cast<RoseAST>(root->child(1));
if (rightChild->val().op != ROSEOperation::addOp) return NULL;
if (rightChild->child(0)->getID() != AST::V_RoseAST || rightChild->child(1)->getID() != AST::V_ConstantAST) return NULL;
RoseAST::Ptr invertAST = boost::static_pointer_cast<RoseAST>(rightChild->child(0));
if (invertAST->val().op != ROSEOperation::invertOp) return NULL;
ConstantAST::Ptr subAST = boost::static_pointer_cast<ConstantAST>(rightChild->child(1));
if (subAST->val().val != 1) return NULL;
if (invertAST->child(0)->getID() != AST::V_RoseAST) return NULL;
RoseAST::Ptr shlAST = boost::static_pointer_cast<RoseAST>(invertAST->child(0));
if (shlAST->val().op != ROSEOperation::shiftLOp) return NULL;
ConstantAST::Ptr shlBit = boost::static_pointer_cast<ConstantAST>(shlAST->child(1));
if (shlAST->child(0)->getID() != AST::V_RoseAST) return NULL;
RoseAST::Ptr shrAST = boost::static_pointer_cast<RoseAST>(shlAST->child(0));
if (shrAST->val().op != ROSEOperation::shiftROp) return NULL;
ConstantAST::Ptr shrBit = boost::static_pointer_cast<ConstantAST>(shrAST->child(1));
if (shrBit->val().val != shlBit->val().val) return NULL;
if (shrAST->child(0)->getID() != AST::V_VariableAST) return NULL;
VariableAST::Ptr leftChild2 = boost::static_pointer_cast<VariableAST>(shrAST->child(0));
if (leftChild->val().reg != leftChild2->val().reg) return NULL;
return new BoundValue(StridedInterval(1,0,(1 << shlBit->val().val)-1));
}
void BoundFact::SwapFact(AST::Ptr a, AST::Ptr b) {
auto aIter = fact.end();
auto bIter = fact.end();
Expand Down Expand Up @@ -1587,3 +1633,13 @@ void BoundFact::SwapFact(AST::Ptr a, AST::Ptr b) {
(*rit)->right = tmp;
}
}


void BoundFact::CheckZeroExtend(AST::Ptr a) {
for (auto fit = fact.begin(); fit != fact.end(); ++fit) {
if (*(fit->first) == *a) {
BoundValue *val = fit->second;
if (val->tableReadSize > 0) val->isZeroExtend = true;
}
}
}
4 changes: 4 additions & 0 deletions parseAPI/src/BoundFactData.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ struct BoundValue {
int tableReadSize;
bool isInverted;
bool isSubReadContent;
bool isZeroExtend;
BoundValue(int64_t val);
BoundValue(const StridedInterval& si);
BoundValue();
Expand Down Expand Up @@ -224,10 +225,13 @@ struct BoundFact {
void TrackAlias(AST::Ptr expr, AST::Ptr outAST);

BoundValue *ApplyRelations(AST::Ptr outAST);
BoundValue *ApplyRelations2(AST::Ptr outAST);

void PushAConst(int64_t value);
bool PopAConst(AST::Ptr ast);

void SwapFact(AST::Ptr a, AST::Ptr b);
void CheckZeroExtend(AST::Ptr a);

BoundFact();
~BoundFact();
Expand Down
60 changes: 39 additions & 21 deletions parseAPI/src/IndirectASTVisitor.C
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ AST::Ptr SimplifyRoot(AST::Ptr ast, uint64_t insnSize) {
}
}
break;
/* case ROSEOperation::derefOp:
case ROSEOperation::derefOp:
// Any 8-bit value is bounded in [0,255].
// Need to keep the length of the dereference if it is 8-bit.
// However, dereference longer than 8-bit should be regarded the same.
Expand All @@ -94,7 +94,6 @@ AST::Ptr SimplifyRoot(AST::Ptr ast, uint64_t insnSize) {
else
return RoseAST::create(ROSEOperation(ROSEOperation::derefOp), ast->child(0));
break;
*/
default:
break;

Expand All @@ -111,7 +110,15 @@ AST::Ptr SimplifyRoot(AST::Ptr ast, uint64_t insnSize) {
// we can directly use ast->isStrictEqual() to
// compare two ast.
return VariableAST::create(Variable(varAST->val().reg));
} else if (ast->getID() == AST::V_ConstantAST) {
ConstantAST::Ptr constAST = boost::static_pointer_cast<ConstantAST>(ast);
size_t size = constAST->val().size;
uint64_t val = constAST->val().val;
if (size == 32)
if (!(val & (1ULL << (size - 1))))
return ConstantAST::create(Constant(val, 64));
}

return ast;
}

Expand Down Expand Up @@ -153,24 +160,30 @@ AST::Ptr BoundCalcVisitor::visit(DataflowAPI::RoseAST *ast) {
bound.insert(make_pair(ast,val));
}
break;
case ROSEOperation::andOp:{
case ROSEOperation::andOp: {
// For and operation, even one of them is a top,
// we may still produce bound result.
// For example, top And 0[3,3] => 1[0,3]
BoundValue *val = NULL;
if (IsResultBounded(ast->child(0)))
val = new BoundValue(*GetResultBound(ast->child(0)));
else
val = new BoundValue(BoundValue::top);
if (IsResultBounded(ast->child(1)))
val->And(GetResultBound(ast->child(1))->interval);
else
val->And(StridedInterval::top);
// the result of an AND operation should not be
// the table lookup. Set all other values to default
val->ClearTableCheck();
if (*val != BoundValue::top)
bound.insert(make_pair(ast, val));
//
// the bound produced by and may be more relaxed than
// a cmp bound not found yet. So we only apply and
// bound when this is the last attempt
if (handleOneByteRead) {
BoundValue *val = NULL;
if (IsResultBounded(ast->child(0)))
val = new BoundValue(*GetResultBound(ast->child(0)));
else
val = new BoundValue(BoundValue::top);
if (IsResultBounded(ast->child(1)))
val->And(GetResultBound(ast->child(1))->interval);
else
val->And(StridedInterval::top);
// the result of an AND operation should not be
// the table lookup. Set all other values to default
val->ClearTableCheck();
if (*val != BoundValue::top)
bound.insert(make_pair(ast, val));
}
break;
}
case ROSEOperation::sMultOp:
Expand Down Expand Up @@ -201,7 +214,7 @@ AST::Ptr BoundCalcVisitor::visit(DataflowAPI::RoseAST *ast) {
case ROSEOperation::derefOp:
if (IsResultBounded(ast->child(0))) {
BoundValue *val = new BoundValue(*GetResultBound(ast->child(0)));
val->MemoryRead(block, ast->val().size / 8);
val->MemoryRead(block, derefSize);
if (*val != BoundValue::top)
bound.insert(make_pair(ast, val));
} else if (handleOneByteRead && ast->val().size == 8) {
Expand All @@ -211,16 +224,21 @@ AST::Ptr BoundCalcVisitor::visit(DataflowAPI::RoseAST *ast) {
bound.insert(make_pair(ast, new BoundValue(StridedInterval(1,0,255))));
}
break;
case ROSEOperation::orOp: {
case ROSEOperation::orOp:
if (IsResultBounded(ast->child(0)) && IsResultBounded(ast->child(1))) {
BoundValue *val = new BoundValue(*GetResultBound(ast->child(0)));
val->Or(*GetResultBound(ast->child(1)));
if (*val != BoundValue::top)
bound.insert(make_pair(ast, val));
}
break;

}
case ROSEOperation::ifOp:
if (IsResultBounded(ast->child(1)) && IsResultBounded(ast->child(2))) {
BoundValue *val = new BoundValue(*GetResultBound(ast->child(1)));
val->Join(*GetResultBound(ast->child(2)));
if (*val != BoundValue::top)
bound.insert(make_pair(ast, val));
}
default:
break;
}
Expand Down
5 changes: 3 additions & 2 deletions parseAPI/src/IndirectASTVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,10 @@ class BoundCalcVisitor: public ASTVisitor {
BoundFact &boundFact;
ParseAPI::Block *block;
bool handleOneByteRead;
int derefSize;

BoundCalcVisitor(BoundFact &bf, ParseAPI::Block* b, bool handle):
boundFact(bf), block(b), handleOneByteRead(handle) {}
BoundCalcVisitor(BoundFact &bf, ParseAPI::Block* b, bool handle, int size):
boundFact(bf), block(b), handleOneByteRead(handle), derefSize(size) {}
~BoundCalcVisitor();
virtual ASTPtr visit(DataflowAPI::RoseAST *ast);
virtual ASTPtr visit(DataflowAPI::ConstantAST *ast);
Expand Down
1 change: 1 addition & 0 deletions parseAPI/src/IndirectAnalyzer.C
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ using namespace Dyninst::InstructionAPI;


bool IndirectControlFlowAnalyzer::NewJumpTableAnalysis(std::vector<std::pair< Address, Dyninst::ParseAPI::EdgeTypeEnum > >& outEdges) {
// if (block->last() == 0xb1dd9d) dyn_debug_parsing = 1; else dyn_debug_parsing=0;
parsing_printf("Apply indirect control flow analysis at %lx\n", block->last());
parsing_printf("Looking for thunk\n");
// Find all blocks that reach the block containing the indirect jump
Expand Down

0 comments on commit eedef36

Please sign in to comment.