bool SymEval::expand(Result_t &res, std::set<InstructionPtr> &failedInsns, bool applyVisitors) { // Symbolic evaluation works off an Instruction // so we have something to hand to ROSE. failedInsns.clear(); for (Result_t::iterator i = res.begin(); i != res.end(); ++i) { if (i->second != AST::Ptr()) { // Must've already filled it in from a previous instruction crack continue; } Assignment::Ptr ptr = i->first; bool success = expandInsn(ptr->insn(), ptr->addr(), res); if (!success) failedInsns.insert(ptr->insn()); } if (applyVisitors) { // Must apply the visitor to each filled in element for (Result_t::iterator i = res.begin(); i != res.end(); ++i) { if (!i->second) continue; AST::Ptr tmp = simplifyStack(i->second, i->first->addr(), i->first->func(), i->first->block()); BooleanVisitor b; AST::Ptr tmp2 = tmp->accept(&b); i->second = tmp2; } } return (failedInsns.empty()); }
bool ContainAnAST(AST::Ptr root, AST::Ptr check) { if (*root == *check) return true; bool ret = false; unsigned totalChildren = root->numChildren(); for (unsigned i = 0 ; i < totalChildren && !ret; ++i) { ret |= ContainAnAST(root->child(i), check); } return ret; }
AST::Ptr ComparisonVisitor::visit(DataflowAPI::RoseAST *ast) { // For cmp type instruction setting zf // Looking like <eqZero?>(<add>(<V([x86_64::rbx])>,<Imm:8>,),) // Assuming ast has been simplified if (ast->val().op == ROSEOperation::equalToZeroOp) { bool minuendIsZero = true; AST::Ptr child = ast->child(0); if (child->getID() == AST::V_RoseAST) { RoseAST::Ptr childRose = boost::static_pointer_cast<RoseAST>(child); if (childRose->val().op == ROSEOperation::addOp) { minuendIsZero = false; subtrahend = childRose->child(0); minuend = childRose->child(1); // If the minuend is a constant, then // the minuend is currently in its two-complement form if (minuend->getID() == AST::V_ConstantAST) { ConstantAST::Ptr constAST = boost::static_pointer_cast<ConstantAST>(minuend); uint64_t val = constAST->val().val; int size = constAST->val().size; if (size < 64) val = ((~val)+ 1) & ((1ULL << size) - 1); else if (size == 64) val = (~val) + 1; else parsing_printf("WARNING: constant bit size %d exceeds 64!\n", size); minuend = ConstantAST::create(Constant(val, size)); } else if (minuend->getID() == AST::V_RoseAST) { RoseAST::Ptr sub = boost::static_pointer_cast<RoseAST>(minuend); minuend = AST::Ptr(); if (sub->val().op == ROSEOperation::addOp && sub->child(0)->getID() == AST::V_RoseAST) { sub = boost::static_pointer_cast<RoseAST>(sub->child(0)); if (sub->val().op == ROSEOperation::invertOp) { // Otherwise, the minuend ast is in the form of add(invert(minuend), 1) // Need to extract the real minuend minuend = sub->child(0); } } } } } if (minuendIsZero) { // The minuend is 0, thus the add operation is subsume. subtrahend = ast->child(0); minuend = ConstantAST::create(Constant(0)); } } return AST::Ptr(); }
static bool IsVariableArgumentFormat(AST::Ptr t, AbsRegion &index) { if (t->getID() != AST::V_RoseAST) { return false; } RoseAST::Ptr rt = boost::static_pointer_cast<RoseAST>(t); if (rt->val().op != ROSEOperation::addOp) { return false; } if (rt->child(0)->getID() != AST::V_ConstantAST || rt->child(1)->getID() != AST::V_RoseAST) { return false; } RoseAST::Ptr c1 = boost::static_pointer_cast<RoseAST>(rt->child(1)); if (c1->val().op == ROSEOperation::addOp) { if (c1->child(0)->getID() == AST::V_RoseAST && c1->child(1)->getID() == AST::V_ConstantAST) { RoseAST::Ptr lc = boost::static_pointer_cast<RoseAST>(c1->child(0)); ConstantAST::Ptr rc = boost::static_pointer_cast<ConstantAST>(c1->child(1)); if (lc->val().op == ROSEOperation::invertOp && rc->val().val == 1) { return IsIndexing(lc->child(0), index); } } return false; } return IsIndexing(rt->child(1), index); }
StackTamper StackTamperVisitor::tampersStack(AST::Ptr a, Address &newAddr) { if(tamper_ != TAMPER_UNSET) { newAddr = modpc_; return tamper_; } a->accept(this); if (tamper_ == TAMPER_NONZERO) { return tamper_; } assert(diffs_.size() == 1); modpc_ = diffs_.top().a.x; switch(diffs_.top().b.x) { case 0: tamper_ = TAMPER_ABS; break; case 1: if (modpc_) { tamper_ = TAMPER_REL; } else { tamper_ = TAMPER_NONE; } break; default: tamper_ = TAMPER_NONZERO; break; } newAddr = modpc_; return tamper_; }
AST::Ptr SubstituteAnAST(AST::Ptr ast, const BoundFact::AliasMap &aliasMap) { for (auto ait = aliasMap.begin(); ait != aliasMap.end(); ++ait) if (*ast == *(ait->first)) { return ait->second; } unsigned totalChildren = ast->numChildren(); for (unsigned i = 0 ; i < totalChildren; ++i) { ast->setChild(i, SubstituteAnAST(ast->child(i), aliasMap)); } if (ast->getID() == AST::V_VariableAST) { // If this variable is not in the aliasMap yet, // this variable is from the input. VariableAST::Ptr varAST = boost::static_pointer_cast<VariableAST>(ast); return VariableAST::create(Variable(varAST->val().reg, 1)); } return ast; }
AST::Ptr SymEval::simplifyStack(AST::Ptr ast, Address addr, ParseAPI::Function *func, ParseAPI::Block *block) { if (!ast) return ast; // Let's experiment with simplification StackAnalysis sA(func); StackAnalysis::Height sp = sA.findSP(block, addr); StackAnalysis::Height fp = sA.find(block, addr, MachRegister::getFramePointer(func->isrc()->getArch())); StackVisitor sv(addr, func, sp, fp); AST::Ptr simplified = ast->accept(&sv); return simplified; }
AST::Ptr DeepCopyAnAST(AST::Ptr ast) { if (ast->getID() == AST::V_RoseAST) { RoseAST::Ptr roseAST = boost::static_pointer_cast<RoseAST>(ast); AST::Children kids; unsigned totalChildren = ast->numChildren(); for (unsigned i = 0 ; i < totalChildren; ++i) { kids.push_back(DeepCopyAnAST(ast->child(i))); } return RoseAST::create(ROSEOperation(roseAST->val()), kids); } else if (ast->getID() == AST::V_VariableAST) { VariableAST::Ptr varAST = boost::static_pointer_cast<VariableAST>(ast); return VariableAST::create(Variable(varAST->val())); } else if (ast->getID() == AST::V_ConstantAST) { ConstantAST::Ptr constAST = boost::static_pointer_cast<ConstantAST>(ast); return ConstantAST::create(Constant(constAST->val())); } else if (ast->getID() == AST::V_BottomAST) { BottomAST::Ptr bottomAST = boost::static_pointer_cast<BottomAST>(ast); return BottomAST::create(bottomAST->val()); } fprintf(stderr, "ast type %d, %s\n", ast->getID(), ast->format().c_str()); assert(0); return AST::Ptr(); }
void IndirectControlFlowAnalyzer::ReadTable(AST::Ptr jumpTargetExpr, AbsRegion index, StridedInterval &indexBound, int memoryReadSize, bool isZeroExtend, bool scanTable, set<Address> &constAddr, std::vector<std::pair<Address, Dyninst::ParseAPI::EdgeTypeEnum> > &targetEdges) { CodeSource *cs = block->obj()->cs(); set<Address> jumpTargets; int start = 0; if (indexBound.low > 0) start = indexBound.low = start; for (int v = start; v <= indexBound.high; v += indexBound.stride) { JumpTableReadVisitor jtrv(index, v, cs, block->region(), isZeroExtend, memoryReadSize); jumpTargetExpr->accept(&jtrv); if (jtrv.valid && cs->isCode(jtrv.targetAddress)) { if (cs->getArch() == Arch_x86_64 && FindJunkInstruction(jtrv.targetAddress)) { parsing_printf("WARNING: resolving jump tables leads to junk instruction from %lx\n", jtrv.targetAddress); break; } jumpTargets.insert(jtrv.targetAddress); } else { // We have a bad entry. We stop here, as we have wrong information // In this case, we keep the good entries parsing_printf("WARNING: resolving jump tables leads to a bad address %lx\n", jtrv.targetAddress); break; } if (indexBound.stride == 0) break; } for (auto ait = constAddr.begin(); ait != constAddr.end(); ++ait) { if (block->region()->isCode(*ait)) { jumpTargets.insert(*ait); } } for (auto tit = jumpTargets.begin(); tit != jumpTargets.end(); ++tit) { targetEdges.push_back(make_pair(*tit, INDIRECT)); } }
void BoundFactsCalculator::CalcTransferFunction(Node::Ptr curNode, BoundFact *newFact){ SliceNode::Ptr node = boost::static_pointer_cast<SliceNode>(curNode); if (!node->assign()) return; if (node->assign() && node->assign()->out().absloc().type() == Absloc::Register && (node->assign()->out().absloc().reg() == x86::zf || node->assign()->out().absloc().reg() == x86_64::zf)) { // zf should be only predecessor of this node parsing_printf("\t\tThe predecessor node is zf assignment!\n"); newFact->SetPredicate(node->assign(), ExpandAssignment(node->assign()) ); return; } entryID id = node->assign()->insn()->getOperation().getID(); // The predecessor is not a conditional jump, // then we can determine buond fact based on the src assignment parsing_printf("\t\tThe predecessor node is normal node\n"); parsing_printf("\t\t\tentry id %d\n", id); AbsRegion &ar = node->assign()->out(); Instruction::Ptr insn = node->assign()->insn(); pair<AST::Ptr, bool> expandRet = ExpandAssignment(node->assign()); if (expandRet.first == NULL) { parsing_printf("\t\t\t No semantic support for this instruction. Assume it does not affect jump target calculation. Ignore it (Treat as identity function) except for ptest. ptest should kill the current predicate\n"); if (id == e_ptest) { parsing_printf("\t\t\t\tptest instruction, kill predciate.\n"); newFact->pred.valid = false; } return; } else { parsing_printf("\tAST: %s\n", expandRet.first->format().c_str()); } AST::Ptr calculation = expandRet.first; BoundCalcVisitor bcv(*newFact, node->block(), handleOneByteRead); calculation->accept(&bcv); AST::Ptr outAST; // If the instruction writes memory, // we need the AST that represents the memory access and the address. // When the AbsRegion represents memory, // the generator of the AbsRegion is set to be the AST that represents // the memory address during symbolic expansion. // In other cases, if the AbsRegion represents a register, // the generator is not set. if (ar.generator() != NULL) outAST = SimplifyAnAST(RoseAST::create(ROSEOperation(ROSEOperation::derefOp, ar.size()), ar.generator()), node->assign()->insn()->size()); else outAST = VariableAST::create(Variable(ar)); /* * Naively, bsf and bsr produces a bound from 0 to the number of bits of the source operands. * In pratice, especially in libc, the real bound is usually smaller than the size of the source operand. * Ex 1: shl %cl,%edx * bsf %rdx,%rcx * Here rcx is in range [0,31] rather than [0,63] even though rdx has 64 bits. * * Ex 2: pmovmskb %xmm0,%edx * bsf %rdx, %rdx * Here rdx is in range[0,15] because pmovmskb only sets the least significat 16 bits * In addition, overapproximation of the bound can lead to bogus control flow * that causes overlapping blocks or function. * It is important to further anaylze the operand in bsf rather than directly conclude the bound if (id == e_bsf || id == e_bsr) { int size = node->assign()->insn()->getOperand(0).getValue()->size(); newFact->GenFact(outAST, new BoundValue(StridedInterval(1,0, size * 8 - 1)), false); parsing_printf("\t\t\tCalculating transfer function: Output facts\n"); newFact->Print(); return; } */ if (id == e_xchg) { newFact->SwapFact(calculation, outAST); parsing_printf("\t\t\tCalculating transfer function: Output facts\n"); newFact->Print(); return; } if (id == e_push) { if (calculation->getID() == AST::V_ConstantAST) { ConstantAST::Ptr c = boost::static_pointer_cast<ConstantAST>(calculation); newFact->PushAConst(c->val().val); parsing_printf("\t\t\tCalculating transfer function: Output facts\n"); newFact->Print(); return; } } if (id == e_pop) { if (newFact->PopAConst(outAST)) { parsing_printf("\t\t\tCalculating transfer function: Output facts\n"); newFact->Print(); return; } } // Assume all SETxx entry ids are contiguous if (id >= e_setb && id <= e_setz) { newFact->GenFact(outAST, new BoundValue(StridedInterval(1,0,1)), false); parsing_printf("\t\t\tCalculating transfer function: Output facts\n"); newFact->Print(); return; } if (bcv.IsResultBounded(calculation)) { parsing_printf("\t\t\tGenerate bound fact for %s\n", outAST->format().c_str()); newFact->GenFact(outAST, new BoundValue(*bcv.GetResultBound(calculation)), false); } else { parsing_printf("\t\t\tKill bound fact for %s\n", outAST->format().c_str()); newFact->KillFact(outAST, false); } if (calculation->getID() == AST::V_VariableAST) { // We only track alising between registers 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); } newFact->AdjustPredicate(outAST, calculation); // Now try to track all aliasing. // Currently, all variables in the slice are presented as an AST // consists of input variables to the slice (the variables that // we do not the sources of their values). newFact->TrackAlias(DeepCopyAnAST(calculation), outAST); // Apply tracking relations to the calculation to generate a // potentially stricter bound BoundValue *strictValue = newFact->ApplyRelations(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(); }
SymEval::Retval_t SymEval::process(SliceNode::Ptr ptr, Result_t &dbase, std::set<Edge::Ptr> &skipEdges) { bool failedTranslation; bool skippedEdge = false; bool skippedInput = false; bool success = false; std::map<const AbsRegion*, std::set<Assignment::Ptr> > inputMap; expand_cerr << "Calling process on " << ptr->format() << endl; // Don't try an expansion of a widen node... if (!ptr->assign()) return WIDEN_NODE; EdgeIterator begin, end; ptr->ins(begin, end); for (; begin != end; ++begin) { SliceEdge::Ptr edge = boost::static_pointer_cast<SliceEdge>(*begin); SliceNode::Ptr source = boost::static_pointer_cast<SliceNode>(edge->source()); // Skip this one to break a cycle. if (skipEdges.find(edge) != skipEdges.end()) { expand_cerr << "In process, skipping edge from " << source->format() << endl; skippedEdge = true; continue; } Assignment::Ptr assign = source->assign(); if (!assign) continue; // widen node expand_cerr << "Assigning input " << edge->data().format() << " from assignment " << assign->format() << endl; inputMap[&edge->data()].insert(assign); } expand_cerr << "\t Input map has size " << inputMap.size() << endl; // All of the expanded inputs are in the parameter dbase // If not (like this one), add it AST::Ptr ast; boost::tie(ast, failedTranslation) = SymEval::expand(ptr->assign()); // expand_cerr << "\t ... resulting in " << dbase.format() << endl; // We have an AST. Now substitute in all of its predecessors. for (std::map<const AbsRegion*, std::set<Assignment::Ptr> >::iterator iter = inputMap.begin(); iter != inputMap.end(); ++iter) { // If we have multiple secondary definitions, we: // if all definitions are equal, use the first // otherwise, use nothing AST::Ptr definition; for (std::set<Assignment::Ptr>::iterator iter2 = iter->second.begin(); iter2 != iter->second.end(); ++iter2) { AST::Ptr newDef = dbase[*iter2]; if (!definition) { definition = newDef; continue; } else if (definition->equals(newDef)) { continue; } else { // Not equal definition = AST::Ptr(); skippedInput = true; break; } } // The region used by the current assignment... const AbsRegion ® = *iter->first; // Create an AST around this one VariableAST::Ptr use = VariableAST::create(Variable(reg, ptr->addr())); if (!definition) { // Can happen if we're expanding out of order, and is generally harmless. continue; } expand_cerr << "Before substitution: " << (ast ? ast->format() : "<NULL AST>") << endl; if (!ast) { expand_cerr << "Skipping substitution because of null AST" << endl; } else { ast = AST::substitute(ast, use, definition); success = true; } expand_cerr << "\t result is " << (ast ? ast->format() : "<NULL AST>") << endl; } expand_cerr << "Result of substitution: " << ptr->assign()->format() << " == " << (ast ? ast->format() : "<NULL AST>") << endl; // And attempt simplification again ast = simplifyStack(ast, ptr->addr(), ptr->func(), ptr->block()); expand_cerr << "Result of post-substitution simplification: " << ptr->assign()->format() << " == " << (ast ? ast->format() : "<NULL AST>") << endl; dbase[ptr->assign()] = ast; if (failedTranslation) return FAILED_TRANSLATION; else if (skippedEdge || skippedInput) return SKIPPED_INPUT; else if (success) return SUCCESS; else return FAILED; }
// Do the previous, but use a Graph as a guide for // performing forward substitution on the AST results SymEval::Retval_t SymEval::expand(Dyninst::Graph::Ptr slice, DataflowAPI::Result_t &res) { bool failedTranslation = false; bool skippedInput = false; //cout << "Calling expand" << endl; // Other than the substitution this is pretty similar to the first example. NodeIterator gbegin, gend; slice->allNodes(gbegin, gend); // First, we'll sort the nodes in some deterministic order so that the loop removal // is deterministic std::vector<SliceNode::Ptr> sortVector; for ( ; gbegin != gend; ++gbegin) { Node::Ptr ptr = *gbegin; expand_cerr << "pushing " << (*gbegin)->format() << " to sortVector" << endl; SliceNode::Ptr cur = boost::static_pointer_cast<SliceNode>(ptr); sortVector.push_back(cur); } std::stable_sort(sortVector.begin(), sortVector.end(), vectorSort); // Optimal ordering of search ExpandOrder worklist; std::queue<Node::Ptr> dfs_worklist; std::vector<SliceNode::Ptr>::iterator vit = sortVector.begin(); for ( ; vit != sortVector.end(); ++vit) { SliceNode::Ptr ptr = *vit; Node::Ptr cur = boost::static_pointer_cast<Node>(ptr); dfs_worklist.push(cur); } /* First, we'll do DFS to check for circularities in the graph; * if so, mark them so we don't do infinite substitution */ std::map<Node::Ptr, int> state; while (!dfs_worklist.empty()) { Node::Ptr ptr = dfs_worklist.front(); dfs_worklist.pop(); dfs(ptr, state, worklist.skipEdges()); } slice->allNodes(gbegin, gend); for (; gbegin != gend; ++gbegin) { expand_cerr << "adding " << (*gbegin)->format() << " to worklist" << endl; Node::Ptr ptr = *gbegin; SliceNode::Ptr sptr = boost::static_pointer_cast<SliceNode>(ptr); worklist.insert(sptr,false); } /* have a list * for each node, process * if processessing succeeded, remove the element * if the size of the list has changed, continue */ while (1) { SliceNode::Ptr aNode; int order; boost::tie(aNode,order) = worklist.pop_next(); if (order == -1) // empty break; if (!aNode->assign()) { worklist.mark_done(aNode); continue; // Could be a widen point } expand_cerr << "Visiting node " << aNode->assign()->format() << " order " << order << endl; if (order != 0) { cerr << "ERROR: order is non zero: " << order << endl; } assert(order == 0); // there are no loops AST::Ptr prev = res[aNode->assign()]; Retval_t result = process(aNode, res, worklist.skipEdges()); AST::Ptr post = res[aNode->assign()]; switch (result) { case FAILED: return FAILED; break; case WIDEN_NODE: // Okay... break; case FAILED_TRANSLATION: failedTranslation = true; break; case SKIPPED_INPUT: skippedInput = true; break; case SUCCESS: break; } // We've visited this node, freeing its children // to be visited in turn worklist.mark_done(aNode); if (post && !(post->equals(prev))) { expand_cerr << "Adding successors to list, as new expansion " << endl << "\t" << post->format() << endl << " != " << endl << "\t" << (prev ? prev->format() : "<NULL>") << endl; EdgeIterator oB, oE; aNode->outs(oB, oE); for (; oB != oE; ++oB) { if(worklist.skipEdges().find(*oB) == worklist.skipEdges().end()) { SliceNode::Ptr out = boost::static_pointer_cast<SliceNode>( (*oB)->target()); worklist.insert(out); } } } } if (failedTranslation) return FAILED_TRANSLATION; else if (skippedInput) return SKIPPED_INPUT; else return SUCCESS; }
AST::Ptr SimplifyRoot(AST::Ptr ast, Address addr) { if (ast->getID() == AST::V_RoseAST) { RoseAST::Ptr roseAST = boost::static_pointer_cast<RoseAST>(ast); switch (roseAST->val().op) { case ROSEOperation::invertOp: if (roseAST->child(0)->getID() == AST::V_RoseAST) { RoseAST::Ptr child = boost::static_pointer_cast<RoseAST>(roseAST->child(0)); if (child->val().op == ROSEOperation::invertOp) return child->child(0); } else if (roseAST->child(0)->getID() == AST::V_ConstantAST) { ConstantAST::Ptr child = boost::static_pointer_cast<ConstantAST>(roseAST->child(0)); size_t size = child->val().size; uint64_t val = child->val().val; if (size < 64) { uint64_t mask = (1ULL << size) - 1; val = (~val) & mask; } else val = ~val; return ConstantAST::create(Constant(val, size)); } break; case ROSEOperation::extendMSBOp: case ROSEOperation::extractOp: case ROSEOperation::signExtendOp: case ROSEOperation::concatOp: return roseAST->child(0); case ROSEOperation::addOp: // We simplify the addition as much as we can // Case 1: two constants if (roseAST->child(0)->getID() == AST::V_ConstantAST && roseAST->child(1)->getID() == AST::V_ConstantAST) { ConstantAST::Ptr child0 = boost::static_pointer_cast<ConstantAST>(roseAST->child(0)); ConstantAST::Ptr child1 = boost::static_pointer_cast<ConstantAST>(roseAST->child(1)); uint64_t val = child0->val().val + child1->val().val; size_t size; if (child0->val().size > child1->val().size) size = child0->val().size; else size = child1->val().size; return ConstantAST::create(Constant(val,size)); } // Case 2: anything adding zero stays the same if (roseAST->child(0)->getID() == AST::V_ConstantAST) { ConstantAST::Ptr child = boost::static_pointer_cast<ConstantAST>(roseAST->child(0)); if (child->val().val == 0) return roseAST->child(1); } if (roseAST->child(1)->getID() == AST::V_ConstantAST) { ConstantAST::Ptr child = boost::static_pointer_cast<ConstantAST>(roseAST->child(1)); if (child->val().val == 0) return roseAST->child(0); } // Case 3: if v + v * c = v * (c+1), where v is a variable and c is a constant if (roseAST->child(0)->getID() == AST::V_VariableAST && roseAST->child(1)->getID() == AST::V_RoseAST) { RoseAST::Ptr rOp = boost::static_pointer_cast<RoseAST>(roseAST->child(1)); if (rOp->val().op == ROSEOperation::uMultOp || rOp->val().op == ROSEOperation::sMultOp) { if (rOp->child(0)->getID() == AST::V_VariableAST && rOp->child(1)->getID() == AST::V_ConstantAST) { VariableAST::Ptr varAST1 = boost::static_pointer_cast<VariableAST>(roseAST->child(0)); VariableAST::Ptr varAST2 = boost::static_pointer_cast<VariableAST>(rOp->child(0)); if (varAST1->val().reg == varAST2->val().reg) { ConstantAST::Ptr oldC = boost::static_pointer_cast<ConstantAST>(rOp->child(1)); ConstantAST::Ptr newC = ConstantAST::create(Constant(oldC->val().val + 1, oldC->val().size)); RoseAST::Ptr newRoot = RoseAST::create(ROSEOperation(rOp->val()), varAST1, newC); return newRoot; } } } } break; case ROSEOperation::sMultOp: case ROSEOperation::uMultOp: if (roseAST->child(0)->getID() == AST::V_ConstantAST) { ConstantAST::Ptr child0 = boost::static_pointer_cast<ConstantAST>(roseAST->child(0)); if (child0->val().val == 1) return roseAST->child(1); } if (roseAST->child(1)->getID() == AST::V_ConstantAST) { ConstantAST::Ptr child1 = boost::static_pointer_cast<ConstantAST>(roseAST->child(1)); if (child1->val().val == 1) return roseAST->child(0); } break; case ROSEOperation::xorOp: if (roseAST->child(0)->getID() == AST::V_VariableAST && roseAST->child(1)->getID() == AST::V_VariableAST) { VariableAST::Ptr child0 = boost::static_pointer_cast<VariableAST>(roseAST->child(0)); VariableAST::Ptr child1 = boost::static_pointer_cast<VariableAST>(roseAST->child(1)); if (child0->val() == child1->val()) { return ConstantAST::create(Constant(0 , 32)); } } break; 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. if (roseAST->val().size == 8) return ast; else return RoseAST::create(ROSEOperation(ROSEOperation::derefOp), ast->child(0)); break; case ROSEOperation::shiftLOp: if (roseAST->child(0)->getID() == AST::V_ConstantAST && roseAST->child(1)->getID() == AST::V_ConstantAST) { ConstantAST::Ptr child0 = boost::static_pointer_cast<ConstantAST>(roseAST->child(0)); ConstantAST::Ptr child1 = boost::static_pointer_cast<ConstantAST>(roseAST->child(1)); return ConstantAST::create(Constant(child0->val().val << child1->val().val, 64)); } break; case ROSEOperation::andOp: if (roseAST->child(0)->getID() == AST::V_ConstantAST && roseAST->child(1)->getID() == AST::V_ConstantAST) { ConstantAST::Ptr child0 = boost::static_pointer_cast<ConstantAST>(roseAST->child(0)); ConstantAST::Ptr child1 = boost::static_pointer_cast<ConstantAST>(roseAST->child(1)); return ConstantAST::create(Constant(child0->val().val & child1->val().val, 64)); } break; case ROSEOperation::orOp: if (roseAST->child(0)->getID() == AST::V_ConstantAST && roseAST->child(1)->getID() == AST::V_ConstantAST) { ConstantAST::Ptr child0 = boost::static_pointer_cast<ConstantAST>(roseAST->child(0)); ConstantAST::Ptr child1 = boost::static_pointer_cast<ConstantAST>(roseAST->child(1)); return ConstantAST::create(Constant(child0->val().val | child1->val().val, 64)); } break; default: break; } } else if (ast->getID() == AST::V_VariableAST) { VariableAST::Ptr varAST = boost::static_pointer_cast<VariableAST>(ast); if (varAST->val().reg.absloc().isPC()) { MachRegister pc = varAST->val().reg.absloc().reg(); return ConstantAST::create(Constant(addr, getArchAddressWidth(pc.getArchitecture()) * 8)); } // We do not care about the address of the a-loc // because we will keep tracking the changes of // each a-loc. Also, this brings a benefit that // 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; }
AST::Ptr SimplifyAnAST(AST::Ptr ast, Address addr) { SimplifyVisitor sv(addr); ast->accept(&sv); return SimplifyRoot(ast, addr); }