/** Emit type name for term. */ std::string YicesSolver::get_typename(const SymbolicExpr::Ptr &expr) { ASSERT_not_null(expr); if (expr->isScalar()) return "(bitvector " + StringUtility::numberToString(expr->nBits()) + ")"; return ("(-> (bitvector " + StringUtility::numberToString(expr->domainWidth()) + ")" " (bitvector " + StringUtility::numberToString(expr->nBits()) + "))"); }
void RiscOperators::writeRegister(RegisterDescriptor reg, const BaseSemantics::SValuePtr &value) { SymbolicExpr::Ptr expr = SValue::promote(value)->get_expression(); if (expr->isLeafNode()) { std::string comment = commentForVariable(reg, "write"); State::promote(currentState())->varComment(expr->isLeafNode()->toString(), comment); } Super::writeRegister(reg, value); }
BaseSemantics::SValuePtr RiscOperators::readRegister(RegisterDescriptor reg, const BaseSemantics::SValuePtr &dflt) { SValuePtr retval = SValue::promote(Super::readRegister(reg, dflt)); SymbolicExpr::Ptr expr = retval->get_expression(); if (expr->isLeafNode()) { std::string comment = commentForVariable(reg, "read"); State::promote(currentState())->varComment(expr->isLeafNode()->toString(), comment); } return retval; }
/** Generate a Yices "assert" statement for an expression. */ void YicesSolver::out_assert(std::ostream &o, const SymbolicExpr::Ptr &tn) { o <<"(assert "; if (tn->isNumber() && 1==tn->nBits()) { if (tn->toInt()) { o <<"true"; } else { o <<"false"; } } else { out_expr(o, tn); } o <<")\n"; }
std::string RiscOperators::commentForVariable(const BaseSemantics::SValuePtr &addr, const std::string &accessMode, size_t byteNumber, size_t nBytes) const { std::string varComment = "first " + accessMode + " at "; if (pathInsnIndex_ != (size_t)(-1)) varComment += "path position #" + StringUtility::numberToString(pathInsnIndex_) + ", "; varComment += "instruction " + unparseInstructionWithAddress(currentInstruction()); // Sometimes we can save useful information about the address. if (nBytes != 1) { SymbolicExpr::Ptr addrExpr = SValue::promote(addr)->get_expression(); if (SymbolicExpr::LeafPtr addrLeaf = addrExpr->isLeafNode()) { if (addrLeaf->isNumber()) { varComment += "\n"; if (nBytes > 1) { varComment += StringUtility::numberToString(byteNumber) + " of " + StringUtility::numberToString(nBytes) + " bytes starting "; } varComment += "at address " + addrLeaf->toString(); } } else if (SymbolicExpr::InteriorPtr addrINode = addrExpr->isInteriorNode()) { if (addrINode->getOperator() == SymbolicExpr::OP_ADD && addrINode->nChildren() == 2 && addrINode->child(0)->isLeafNode() && addrINode->child(0)->isLeafNode()->isVariable() && addrINode->child(1)->isLeafNode() && addrINode->child(1)->isLeafNode()->isNumber()) { SymbolicExpr::LeafPtr base = addrINode->child(0)->isLeafNode(); SymbolicExpr::LeafPtr offset = addrINode->child(1)->isLeafNode(); varComment += "\n"; if (nBytes > 1) { varComment += StringUtility::numberToString(byteNumber) + " of " + StringUtility::numberToString(nBytes) + " bytes starting "; } varComment += "at address "; if (base->comment().empty()) { varComment = base->toString(); } else { varComment += base->comment(); } Sawyer::Container::BitVector tmp = offset->bits(); if (tmp.get(tmp.size()-1)) { varComment += " - 0x" + tmp.negate().toHex(); } else { varComment += " + 0x" + tmp.toHex(); } } } } return varComment; }
SymbolicExpr::VisitAction preVisit(const SymbolicExpr::Ptr &node) { if (!seen.insert(getRawPointer(node)).second) return SymbolicExpr::TRUNCATE; // already processed this subexpression if (SymbolicExpr::LeafPtr leaf = node->isLeafNode()) { if (leaf->isVariable()) { if (defns->find(leaf->nameId()) == defns->end()) { defns->insert(leaf->nameId()); yices_type bvtype = yices_mk_bitvector_type(self->context, leaf->nBits()); ASSERT_not_null(bvtype); std::string name = "v" + StringUtility::numberToString(leaf->nameId()); yices_var_decl vdecl __attribute__((unused)) = yices_mk_var_decl(self->context, name.c_str(), bvtype); ASSERT_not_null(vdecl); } } else if (leaf->isMemory()) { if (defns->find(leaf->nameId()) == defns->end()) { defns->insert(leaf->nameId()); yices_type domain = yices_mk_bitvector_type(self->context, leaf->domainWidth()); yices_type range = yices_mk_bitvector_type(self->context, leaf->nBits()); yices_type ftype = yices_mk_function_type(self->context, &domain, 1, range); ASSERT_not_null(ftype); std::string name = "m" + StringUtility::numberToString(leaf->nameId()); yices_var_decl vdecl __attribute__((unused)) = yices_mk_var_decl(self->context, name.c_str(), ftype); ASSERT_not_null(vdecl); } } } return SymbolicExpr::CONTINUE; }
/** Output a decimal number. */ void YicesSolver::out_number(std::ostream &o, const SymbolicExpr::Ptr &tn) { SymbolicExpr::LeafPtr ln = tn->isLeafNode(); ASSERT_require(ln && ln->isNumber()); o <<ln->toInt(); }
/** Output for arithmetic right shift. Yices doesn't have a sign-extending right shift, therefore we implement it in terms of * other operations. (OP_ASR ShiftAmount Vector) becomes * * (ite (= (mk-bv 1 1) (bv-extract [VectorSize-1] [VectorSize-1] Vector)) ;; vector's sign bit * (bv-shift-right1 Vector [ShiftAmount]) * (bv-shift-right0 Vector [ShiftAmount])) * * where [VectorSize], [VectorSize-1], and [ShiftAmount] are numeric constants. */ void YicesSolver::out_asr(std::ostream &o, const SymbolicExpr::InteriorPtr &in) { ASSERT_require(in && 2==in->nChildren()); SymbolicExpr::Ptr vector = in->child(1); uint64_t vector_size = vector->nBits(); ASSERT_require(in->child(0)->isNumber()); uint64_t shift_amount = in->child(0)->toInt(); o <<"(ite (= (mk-bv 1 1) (bv-extract " <<(vector_size-1) <<" " <<(vector_size-1) <<" "; out_expr(o, vector); o <<")) (bv-shift-right1 "; out_expr(o, vector); o <<" " <<shift_amount <<") (bv-shift-right0 "; out_expr(o, vector); o <<" " <<shift_amount <<"))"; }
/** Read memory. * * If multi-path is enabled, then return a new memory expression that describes the process of reading a value from the * specified address; otherwise, actually read the value and return it. In any case, record some information about the * address that's being read if we've never seen it before. */ BaseSemantics::SValuePtr RiscOperators::readMemory(RegisterDescriptor segreg, const BaseSemantics::SValuePtr &addr, const BaseSemantics::SValuePtr &dflt_, const BaseSemantics::SValuePtr &cond) { BaseSemantics::SValuePtr dflt = dflt_; const size_t nBytes = dflt->get_width() / 8; if (cond->is_number() && !cond->get_number()) return dflt_; // If we know the address and that memory exists, then read the memory to obtain the default value. uint8_t buf[8]; if (addr->is_number() && nBytes < sizeof(buf) && nBytes == partitioner_->memoryMap()->at(addr->get_number()).limit(nBytes).read(buf).size()) { // FIXME[Robb P. Matzke 2015-05-25]: assuming little endian uint64_t value = 0; for (size_t i=0; i<nBytes; ++i) value |= (uint64_t)buf[i] << (8*i); dflt = number_(dflt->get_width(), value); } // Read from the symbolic state, and update the state with the default from real memory if known. BaseSemantics::SValuePtr retval = Super::readMemory(segreg, addr, dflt, cond); if (!currentInstruction()) return retval; // not called from dispatcher on behalf of an instruction // Save a description of the variable SymbolicExpr::Ptr valExpr = SValue::promote(retval)->get_expression(); if (valExpr->isLeafNode() && valExpr->isLeafNode()->isVariable()) { std::string comment = commentForVariable(addr, "read"); State::promote(currentState())->varComment(valExpr->isLeafNode()->toString(), comment); } // Save a description for its addresses for (size_t i=0; i<nBytes; ++i) { SValuePtr va = SValue::promote(add(addr, number_(addr->get_width(), i))); if (va->get_expression()->isLeafNode()) { std::string comment = commentForVariable(addr, "read", i, nBytes); State::promote(currentState())->varComment(va->get_expression()->isLeafNode()->toString(), comment); } } return retval; }
/** Write value to memory. * * If multi-path is enabled, then return a new memory expression that updates memory with a new address/value pair; * otherwise update the memory directly. In any case, record some information about the address that was written if we've * never seen it before. */ void RiscOperators::writeMemory(RegisterDescriptor segreg, const BaseSemantics::SValuePtr &addr, const BaseSemantics::SValuePtr &value, const BaseSemantics::SValuePtr &cond) { if (cond->is_number() && !cond->get_number()) return; Super::writeMemory(segreg, addr, value, cond); // Save a description of the variable SymbolicExpr::Ptr valExpr = SValue::promote(value)->get_expression(); if (valExpr->isLeafNode() && valExpr->isLeafNode()->isVariable()) { std::string comment = commentForVariable(addr, "write"); State::promote(currentState())->varComment(valExpr->isLeafNode()->toString(), comment); } // Save a description for its addresses size_t nBytes = value->get_width() / 8; for (size_t i=0; i<nBytes; ++i) { SValuePtr va = SValue::promote(add(addr, number_(addr->get_width(), i))); if (va->get_expression()->isLeafNode()) { std::string comment = commentForVariable(addr, "read", i, nBytes); State::promote(currentState())->varComment(va->get_expression()->isLeafNode()->toString(), comment); } } }
SymbolicExpr::VisitAction preVisit(const SymbolicExpr::Ptr &node) { if (!seen.insert(getRawPointer(node)).second) return SymbolicExpr::TRUNCATE; // already processed this subexpression if (SymbolicExpr::LeafPtr leaf = node->isLeafNode()) { if ((leaf->isVariable() || leaf->isMemory()) && !leaf->comment().empty()) { if (!commented) { o <<"\n" <<";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n" <<"; Variable comments\n" <<";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n"; commented = true; } o <<"\n; " <<leaf->toString() <<": " <<StringUtility::prefixLines(leaf->comment(), "; ", false) <<"\n"; } } return SymbolicExpr::CONTINUE; }
SymbolicExpr::VisitAction preVisit(const SymbolicExpr::Ptr &node) { if (!seen.insert(getRawPointer(node)).second) return SymbolicExpr::TRUNCATE; // already processed this subexpression if (SymbolicExpr::LeafPtr leaf = node->isLeafNode()) { if (leaf->isVariable()) { if (defns->find(leaf->nameId())==defns->end()) { defns->insert(leaf->nameId()); o <<"\n"; if (!leaf->comment().empty()) o <<StringUtility::prefixLines(leaf->comment(), "; ") <<"\n"; o <<"(define v" <<leaf->nameId() <<"::" <<get_typename(leaf) <<")\n"; } } else if (leaf->isMemory()) { if (defns->find(leaf->nameId())==defns->end()) { defns->insert(leaf->nameId()); o <<"\n"; if (!leaf->comment().empty()) o <<StringUtility::prefixLines(leaf->comment(), "; ") <<"\n"; o <<"(define m" <<leaf->nameId() <<"::" <<get_typename(leaf) <<")\n"; } } } return SymbolicExpr::CONTINUE; }
/** Output for one expression. */ void YicesSolver::out_expr(std::ostream &o, const SymbolicExpr::Ptr &tn) { SymbolicExpr::LeafPtr ln = tn->isLeafNode(); SymbolicExpr::InteriorPtr in = tn->isInteriorNode(); std::string subExprName; if (termNames.getOptional(tn).assignTo(subExprName)) { o <<subExprName; } else if (ln) { if (ln->isNumber()) { if (ln->nBits() <= 64) { o <<"(mk-bv " <<ln->nBits() <<" " <<ln->toInt() <<")"; } else { o <<"0b" <<ln->bits().toBinary(); } } else if (ln->isMemory()) { o <<"m" <<ln->nameId(); } else { ASSERT_require(ln->isVariable()); o <<"v" <<ln->nameId(); } } else { ASSERT_not_null(in); switch (in->getOperator()) { case SymbolicExpr::OP_ADD: out_la(o, "bv-add", in, false); break; case SymbolicExpr::OP_AND: out_la(o, "and", in, true); break; case SymbolicExpr::OP_ASR: out_asr(o, in); break; case SymbolicExpr::OP_BV_AND: out_la(o, "bv-and", in, true); break; case SymbolicExpr::OP_BV_OR: out_la(o, "bv-or", in, false); break; case SymbolicExpr::OP_BV_XOR: out_la(o, "bv-xor", in, false); break; case SymbolicExpr::OP_EQ: out_binary(o, "=", in); break; case SymbolicExpr::OP_CONCAT: out_la(o, "bv-concat", in); break; case SymbolicExpr::OP_EXTRACT: out_extract(o, in); break; case SymbolicExpr::OP_INVERT: out_unary(o, "bv-not", in); break; case SymbolicExpr::OP_ITE: out_ite(o, in); break; case SymbolicExpr::OP_LSSB: throw Exception("OP_LSSB not implemented"); case SymbolicExpr::OP_MSSB: throw Exception("OP_MSSB not implemented"); case SymbolicExpr::OP_NE: out_binary(o, "/=", in); break; case SymbolicExpr::OP_NEGATE: out_unary(o, "bv-neg", in); break; case SymbolicExpr::OP_NOOP: o<<"0b1"; break; case SymbolicExpr::OP_OR: out_la(o, "or", in, false); break; case SymbolicExpr::OP_READ: out_read(o, in); break; case SymbolicExpr::OP_ROL: throw Exception("OP_ROL not implemented"); case SymbolicExpr::OP_ROR: throw Exception("OP_ROR not implemented"); case SymbolicExpr::OP_SDIV: throw Exception("OP_SDIV not implemented"); case SymbolicExpr::OP_SET: out_set(o, in); break; case SymbolicExpr::OP_SEXTEND: out_sext(o, in); break; case SymbolicExpr::OP_SLT: out_binary(o, "bv-slt", in); break; case SymbolicExpr::OP_SLE: out_binary(o, "bv-sle", in); break; case SymbolicExpr::OP_SHL0: out_shift(o, "bv-shift-left", in, false); break; case SymbolicExpr::OP_SHL1: out_shift(o, "bv-shift-left", in, true); break; case SymbolicExpr::OP_SHR0: out_shift(o, "bv-shift-right", in, false); break; case SymbolicExpr::OP_SHR1: out_shift(o, "bv-shift-right", in, true); break; case SymbolicExpr::OP_SGE: out_binary(o, "bv-sge", in); break; case SymbolicExpr::OP_SGT: out_binary(o, "bv-sgt", in); break; case SymbolicExpr::OP_SMOD: throw Exception("OP_SMOD not implemented"); case SymbolicExpr::OP_SMUL: out_mult(o, in); break; case SymbolicExpr::OP_UDIV: throw Exception("OP_UDIV not implemented"); case SymbolicExpr::OP_UEXTEND: out_uext(o, in); break; case SymbolicExpr::OP_UGE: out_binary(o, "bv-ge", in); break; case SymbolicExpr::OP_UGT: out_binary(o, "bv-gt", in); break; case SymbolicExpr::OP_ULE: out_binary(o, "bv-le", in); break; case SymbolicExpr::OP_ULT: out_binary(o, "bv-lt", in); break; case SymbolicExpr::OP_UMOD: throw Exception("OP_UMOD not implemented"); case SymbolicExpr::OP_UMUL: out_mult(o, in); break; case SymbolicExpr::OP_WRITE: out_write(o, in); break; case SymbolicExpr::OP_ZEROP: out_zerop(o, in); break; } } }
int main(int argc, char *argv[]) { bool testSerialization = false; parseCommandLine(argc, argv, testSerialization /*in,out*/); unsigned lineNumber = 0; while (1) { // Prompt for and read a line containing one expression ++lineNumber; #ifdef ROSE_HAVE_LIBREADLINE char *line = readline("> "); if (!line) break; add_history(line); #else char *line = NULL; size_t linesz = 0; printf("> "); ssize_t nread = rose_getline(&line, &linesz, stdin); if (nread <= 0) break; while (nread > 0 && isspace(line[nread-1])) line[--nread] = '\0'; #endif // Parse the expression try { SymbolicExpr::Ptr expr = symbolicParser().parse(line); std::cout <<"Parsed value = " <<*expr <<"\n\n"; #ifdef ROSE_HAVE_BOOST_SERIALIZATION_LIB if (testSerialization) { std::cout <<"Serializing\n"; std::ostringstream oss; boost::archive::text_oarchive out(oss); out.template register_type<SymbolicExpr::Interior>(); out.template register_type<SymbolicExpr::Leaf>(); out <<expr; std::cout <<"Deserializing\n"; std::istringstream iss(oss.str()); boost::archive::text_iarchive in(iss); SymbolicExpr::Ptr expr2; in.template register_type<SymbolicExpr::Interior>(); in.template register_type<SymbolicExpr::Leaf>(); in >>expr2; std::cout <<"Restored value = " <<*expr2 <<"\n\n"; if (!expr->isEquivalentTo(expr2)) std::cerr <<"error: serialization failed structural equivalence test\n"; } #endif } catch (const SymbolicExprParser::SyntaxError &e) { std::cerr <<e <<"\n"; if (e.lineNumber != 0) { std::cerr <<" input: " <<line <<"\n" <<" here---" <<std::string(e.columnNumber, '-') <<"^\n\n"; } } catch (const rose::FailedAssertion &e) { std::cerr <<"\n"; // message has already been printed. } free(line); } }