//===-- Memory.cpp --------------------------------------------------------===// // // The KLEE Symbolic Virtual Machine // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Common.h" #include "Memory.h" #include "klee/Expr.h" #include "klee/Machine.h" #include "klee/Solver.h" #include "klee/util/BitArray.h" #include "ObjectHolder.h" #include <llvm/Function.h> #include <llvm/Instruction.h> #include <llvm/Value.h> #include "llvm/Support/CommandLine.h" #include <iostream> #include <cassert> #include <sstream> using namespace llvm; using namespace klee; namespace { cl::opt<bool> UseConstantArrays("use-constant-arrays", cl::init(true)); } /***/ ObjectHolder::ObjectHolder(const ObjectHolder &b) : os(b.os) { if (os) ++os->refCount; } ObjectHolder::ObjectHolder(ObjectState *_os) : os(_os) { if (os) ++os->refCount; } ObjectHolder::~ObjectHolder() { if (os && --os->refCount==0) delete os; } ObjectHolder &ObjectHolder::operator=(const ObjectHolder &b) { if (b.os) ++b.os->refCount; if (os && --os->refCount==0) delete os; os = b.os; return *this; } /***/ int MemoryObject::counter = 0; MemoryObject::~MemoryObject() { } void MemoryObject::getAllocInfo(std::string &result) const { std::ostringstream info; info << "MO" << id << "[" << size << "]"; if (allocSite) { info << " allocated at "; if (const Instruction *i = dyn_cast<Instruction>(allocSite)) { info << i->getParent()->getParent()->getName() << "():"; info << *i; } else if (const GlobalValue *gv = dyn_cast<GlobalValue>(allocSite)) { info << "global:" << gv->getName(); } else { info << "value:" << *allocSite; } } else { info << " (no allocation info)"; } result = info.str(); } /***/ ObjectState::ObjectState(const MemoryObject *mo) : copyOnWriteOwner(0), refCount(0), object(mo), concreteStore(new uint8_t[mo->size]), concreteMask(0), flushMask(0), knownSymbolics(0), updates(0, 0), size(mo->size), readOnly(false) { if (!UseConstantArrays) { // FIXME: Leaked. static unsigned id = 0; const Array *array = new Array("tmp_arr" + llvm::utostr(++id), size); updates = UpdateList(array, 0); } } ObjectState::ObjectState(const MemoryObject *mo, const Array *array) : copyOnWriteOwner(0), refCount(0), object(mo), concreteStore(new uint8_t[mo->size]), concreteMask(0), flushMask(0), knownSymbolics(0), updates(array, 0), size(mo->size), readOnly(false) { makeSymbolic(); } ObjectState::ObjectState(const ObjectState &os) : copyOnWriteOwner(0), refCount(0), object(os.object), concreteStore(new uint8_t[os.size]), concreteMask(os.concreteMask ? new BitArray(*os.concreteMask, os.size) : 0), flushMask(os.flushMask ? new BitArray(*os.flushMask, os.size) : 0), knownSymbolics(0), updates(os.updates), size(os.size), readOnly(false) { assert(!os.readOnly && "no need to copy read only object?"); if (os.knownSymbolics) { knownSymbolics = new ref<Expr>[size]; for (unsigned i=0; i<size; i++) knownSymbolics[i] = os.knownSymbolics[i]; } memcpy(concreteStore, os.concreteStore, size*sizeof(*concreteStore)); } ObjectState::~ObjectState() { if (concreteMask) delete concreteMask; if (flushMask) delete flushMask; if (knownSymbolics) delete[] knownSymbolics; delete[] concreteStore; } /***/ const UpdateList &ObjectState::getUpdates() const { // Constant arrays are created lazily. if (!updates.root) { // Collect the list of writes, with the oldest writes first. // FIXME: We should be able to do this more efficiently, we just need to be // careful to get the interaction with the cache right. In particular we // should avoid creating UpdateNode instances we never use. unsigned NumWrites = updates.head ? updates.head->getSize() : 0; std::vector< std::pair< ref<Expr>, ref<Expr> > > Writes(NumWrites); const UpdateNode *un = updates.head; for (unsigned i = NumWrites; i != 0; un = un->next) { --i; Writes[i] = std::make_pair(un->index, un->value); } std::vector< ref<ConstantExpr> > Contents(size); // Initialize to zeros. for (unsigned i = 0, e = size; i != e; ++i) Contents[i] = ConstantExpr::create(0, Expr::Int8); // Pull off as many concrete writes as we can. unsigned Begin = 0, End = Writes.size(); for (; Begin != End; ++Begin) { // Push concrete writes into the constant array. ConstantExpr *Index = dyn_cast<ConstantExpr>(Writes[Begin].first); if (!Index) break; ConstantExpr *Value = dyn_cast<ConstantExpr>(Writes[Begin].second); if (!Value) break; Contents[Index->getZExtValue()] = Value; } // FIXME: We should unique these, there is no good reason to create multiple // ones. // Start a new update list. // FIXME: Leaked. static unsigned id = 0; const Array *array = new Array("const_arr" + llvm::utostr(++id), size, &Contents[0], &Contents[0] + Contents.size()); updates = UpdateList(array, 0); // Apply the remaining (non-constant) writes. for (; Begin != End; ++Begin) updates.extend(Writes[Begin].first, Writes[Begin].second); } return updates; } void ObjectState::makeConcrete() { if (concreteMask) delete concreteMask; if (flushMask) delete flushMask; if (knownSymbolics) delete[] knownSymbolics; concreteMask = 0; flushMask = 0; knownSymbolics = 0; } void ObjectState::makeSymbolic() { assert(!updates.head && "XXX makeSymbolic of objects with symbolic values is unsupported"); // XXX simplify this, can just delete various arrays I guess for (unsigned i=0; i<size; i++) { markByteSymbolic(i); setKnownSymbolic(i, 0); markByteFlushed(i); } } void ObjectState::initializeToZero() { makeConcrete(); memset(concreteStore, 0, size); } void ObjectState::initializeToRandom() { makeConcrete(); for (unsigned i=0; i<size; i++) { // randomly selected by 256 sided die concreteStore[i] = 0xAB; } } /* Cache Invariants -- isByteKnownSymbolic(i) => !isByteConcrete(i) isByteConcrete(i) => !isByteKnownSymbolic(i) !isByteFlushed(i) => (isByteConcrete(i) || isByteKnownSymbolic(i)) */ void ObjectState::fastRangeCheckOffset(ref<Expr> offset, unsigned *base_r, unsigned *size_r) const { *base_r = 0; *size_r = size; } void ObjectState::flushRangeForRead(unsigned rangeBase, unsigned rangeSize) const { if (!flushMask) flushMask = new BitArray(size, true); for (unsigned offset=rangeBase; offset<rangeBase+rangeSize; offset++) { if (!isByteFlushed(offset)) { if (isByteConcrete(offset)) { updates.extend(ConstantExpr::create(offset, kMachinePointerType), ConstantExpr::create(concreteStore[offset], Expr::Int8)); } else { assert(isByteKnownSymbolic(offset) && "invalid bit set in flushMask"); updates.extend(ConstantExpr::create(offset, kMachinePointerType), knownSymbolics[offset]); } flushMask->unset(offset); } } } void ObjectState::flushRangeForWrite(unsigned rangeBase, unsigned rangeSize) { if (!flushMask) flushMask = new BitArray(size, true); for (unsigned offset=rangeBase; offset<rangeBase+rangeSize; offset++) { if (!isByteFlushed(offset)) { if (isByteConcrete(offset)) { updates.extend(ConstantExpr::create(offset, kMachinePointerType), ConstantExpr::create(concreteStore[offset], Expr::Int8)); markByteSymbolic(offset); } else { assert(isByteKnownSymbolic(offset) && "invalid bit set in flushMask"); updates.extend(ConstantExpr::create(offset, kMachinePointerType), knownSymbolics[offset]); setKnownSymbolic(offset, 0); } flushMask->unset(offset); } else { // flushed bytes that are written over still need // to be marked out if (isByteConcrete(offset)) { markByteSymbolic(offset); } else if (isByteKnownSymbolic(offset)) { setKnownSymbolic(offset, 0); } } } } bool ObjectState::isByteConcrete(unsigned offset) const { return !concreteMask || concreteMask->get(offset); } bool ObjectState::isByteFlushed(unsigned offset) const { return flushMask && !flushMask->get(offset); } bool ObjectState::isByteKnownSymbolic(unsigned offset) const { return knownSymbolics && knownSymbolics[offset].get(); } void ObjectState::markByteConcrete(unsigned offset) { if (concreteMask) concreteMask->set(offset); } void ObjectState::markByteSymbolic(unsigned offset) { if (!concreteMask) concreteMask = new BitArray(size, true); concreteMask->unset(offset); } void ObjectState::markByteUnflushed(unsigned offset) { if (flushMask) flushMask->set(offset); } void ObjectState::markByteFlushed(unsigned offset) { if (!flushMask) { flushMask = new BitArray(size, false); } else { flushMask->unset(offset); } } void ObjectState::setKnownSymbolic(unsigned offset, Expr *value /* can be null */) { if (knownSymbolics) { knownSymbolics[offset] = value; } else { if (value) { knownSymbolics = new ref<Expr>[size]; knownSymbolics[offset] = value; } } } /***/ ref<Expr> ObjectState::read8(unsigned offset) const { if (isByteConcrete(offset)) { return ConstantExpr::create(concreteStore[offset], Expr::Int8); } else if (isByteKnownSymbolic(offset)) { return knownSymbolics[offset]; } else { assert(isByteFlushed(offset) && "unflushed byte without cache value"); return ReadExpr::create(getUpdates(), ConstantExpr::create(offset, kMachinePointerType)); } } ref<Expr> ObjectState::read8(ref<Expr> offset) const { assert(!isa<ConstantExpr>(offset) && "constant offset passed to symbolic read8"); unsigned base, size; fastRangeCheckOffset(offset, &base, &size); flushRangeForRead(base, size); if (size>4096) { std::string allocInfo; object->getAllocInfo(allocInfo); klee_warning_once(0, "flushing %d bytes on read, may be slow and/or crash: %s", size, allocInfo.c_str()); } return ReadExpr::create(getUpdates(), offset); } void ObjectState::write8(unsigned offset, uint8_t value) { //assert(read_only == false && "writing to read-only object!"); concreteStore[offset] = value; setKnownSymbolic(offset, 0); markByteConcrete(offset); markByteUnflushed(offset); } void ObjectState::write8(unsigned offset, ref<Expr> value) { // can happen when ExtractExpr special cases if (ConstantExpr *CE = dyn_cast<ConstantExpr>(value)) { write8(offset, (uint8_t) CE->getZExtValue(8)); } else { setKnownSymbolic(offset, value.get()); markByteSymbolic(offset); markByteUnflushed(offset); } } void ObjectState::write8(ref<Expr> offset, ref<Expr> value) { assert(!isa<ConstantExpr>(offset) && "constant offset passed to symbolic write8"); unsigned base, size; fastRangeCheckOffset(offset, &base, &size); flushRangeForWrite(base, size); if (size>4096) { std::string allocInfo; object->getAllocInfo(allocInfo); klee_warning_once(0, "flushing %d bytes on read, may be slow and/or crash: %s", size, allocInfo.c_str()); } updates.extend(offset, value); } /***/ ref<Expr> ObjectState::read(ref<Expr> offset, Expr::Width width) const { if (ConstantExpr *CE = dyn_cast<ConstantExpr>(offset)) { return read((unsigned) CE->getConstantValue(), width); } else { switch (width) { default: assert(0 && "invalid type"); case Expr::Bool: return read1(offset); case Expr::Int8: return read8(offset); case Expr::Int16: return read16(offset); case Expr::Int32: return read32(offset); case Expr::Int64: return read64(offset); } } } ref<Expr> ObjectState::read(unsigned offset, Expr::Width width) const { switch (width) { default: assert(0 && "invalid type"); case Expr::Bool: return read1(offset); case Expr::Int8: return read8(offset); case Expr::Int16: return read16(offset); case Expr::Int32: return read32(offset); case Expr::Int64: return read64(offset); } } ref<Expr> ObjectState::read1(unsigned offset) const { return ExtractExpr::createByteOff(read8(offset), 0, Expr::Bool); } ref<Expr> ObjectState::read1(ref<Expr> offset) const { return ExtractExpr::createByteOff(read8(offset), 0, Expr::Bool); } ref<Expr> ObjectState::read16(unsigned offset) const { if (kMachineByteOrder == machine::MSB) { return ConcatExpr::create(read8(offset+0), read8(offset+1)); } else { return ConcatExpr::create(read8(offset+1), read8(offset+0)); } } ref<Expr> ObjectState::read16(ref<Expr> offset) const { if (kMachineByteOrder == machine::MSB) { return ConcatExpr::create (read8(AddExpr::create(offset, ConstantExpr::create(0, kMachinePointerType))), read8(AddExpr::create(offset, ConstantExpr::create(1, kMachinePointerType)))); } else { return ConcatExpr::create (read8(AddExpr::create(offset, ConstantExpr::create(1, kMachinePointerType))), read8(AddExpr::create(offset, ConstantExpr::create(0, kMachinePointerType)))); } } ref<Expr> ObjectState::read32(unsigned offset) const { if (kMachineByteOrder == machine::MSB) { return ConcatExpr::create4(read8(offset+0), read8(offset+1), read8(offset+2), read8(offset+3)); } else { return ConcatExpr::create4(read8(offset+3), read8(offset+2), read8(offset+1), read8(offset+0)); } } ref<Expr> ObjectState::read32(ref<Expr> offset) const { if (kMachineByteOrder == machine::MSB) { return ConcatExpr::create4 (read8(AddExpr::create(offset, ConstantExpr::create(0, kMachinePointerType))), read8(AddExpr::create(offset, ConstantExpr::create(1, kMachinePointerType))), read8(AddExpr::create(offset, ConstantExpr::create(2, kMachinePointerType))), read8(AddExpr::create(offset, ConstantExpr::create(3, kMachinePointerType)))); } else { return ConcatExpr::create4 (read8(AddExpr::create(offset, ConstantExpr::create(3, kMachinePointerType))), read8(AddExpr::create(offset, ConstantExpr::create(2, kMachinePointerType))), read8(AddExpr::create(offset, ConstantExpr::create(1, kMachinePointerType))), read8(AddExpr::create(offset, ConstantExpr::create(0, kMachinePointerType)))); } } ref<Expr> ObjectState::read64(unsigned offset) const { if (kMachineByteOrder == machine::MSB) { return ConcatExpr::create8(read8(offset+0), read8(offset+1), read8(offset+2), read8(offset+3), read8(offset+4), read8(offset+5), read8(offset+6), read8(offset+7)); } else { return ConcatExpr::create8(read8(offset+7), read8(offset+6), read8(offset+5), read8(offset+4), read8(offset+3), read8(offset+2), read8(offset+1), read8(offset+0)); } } ref<Expr> ObjectState::read64(ref<Expr> offset) const { if (kMachineByteOrder == machine::MSB) { return ConcatExpr::create8 (read8(AddExpr::create(offset, ConstantExpr::create(0, kMachinePointerType))), read8(AddExpr::create(offset, ConstantExpr::create(1, kMachinePointerType))), read8(AddExpr::create(offset, ConstantExpr::create(2, kMachinePointerType))), read8(AddExpr::create(offset, ConstantExpr::create(3, kMachinePointerType))), read8(AddExpr::create(offset, ConstantExpr::create(4, kMachinePointerType))), read8(AddExpr::create(offset, ConstantExpr::create(5, kMachinePointerType))), read8(AddExpr::create(offset, ConstantExpr::create(6, kMachinePointerType))), read8(AddExpr::create(offset, ConstantExpr::create(7, kMachinePointerType)))); } else { return ConcatExpr::create8 (read8(AddExpr::create(offset, ConstantExpr::create(7, kMachinePointerType))), read8(AddExpr::create(offset, ConstantExpr::create(6, kMachinePointerType))), read8(AddExpr::create(offset, ConstantExpr::create(5, kMachinePointerType))), read8(AddExpr::create(offset, ConstantExpr::create(4, kMachinePointerType))), read8(AddExpr::create(offset, ConstantExpr::create(3, kMachinePointerType))), read8(AddExpr::create(offset, ConstantExpr::create(2, kMachinePointerType))), read8(AddExpr::create(offset, ConstantExpr::create(1, kMachinePointerType))), read8(AddExpr::create(offset, ConstantExpr::create(0, kMachinePointerType)))); } } void ObjectState::write(ref<Expr> offset, ref<Expr> value) { Expr::Width w = value->getWidth(); if (ConstantExpr *CE = dyn_cast<ConstantExpr>(offset)) { write(CE->getConstantValue(), value); } else { switch(w) { case Expr::Bool: write1(offset, value); break; case Expr::Int8: write8(offset, value); break; case Expr::Int16: write16(offset, value); break; case Expr::Int32: write32(offset, value); break; case Expr::Int64: write64(offset, value); break; default: assert(0 && "invalid number of bytes in write"); } } } void ObjectState::write(unsigned offset, ref<Expr> value) { Expr::Width w = value->getWidth(); if (ConstantExpr *CE = dyn_cast<ConstantExpr>(value)) { uint64_t val = CE->getConstantValue(); switch(w) { case Expr::Bool: case Expr::Int8: write8(offset, val); break; case Expr::Int16: write16(offset, val); break; case Expr::Int32: write32(offset, val); break; case Expr::Int64: write64(offset, val); break; default: assert(0 && "invalid number of bytes in write"); } } else { switch(w) { case Expr::Bool: write1(offset, value); break; case Expr::Int8: write8(offset, value); break; case Expr::Int16: write16(offset, value); break; case Expr::Int32: write32(offset, value); break; case Expr::Int64: write64(offset, value); break; default: assert(0 && "invalid number of bytes in write"); } } } void ObjectState::write1(unsigned offset, ref<Expr> value) { write8(offset, ZExtExpr::create(value, Expr::Int8)); } void ObjectState::write1(ref<Expr> offset, ref<Expr> value) { write8(offset, ZExtExpr::create(value, Expr::Int8)); } void ObjectState::write16(unsigned offset, uint16_t value) { if (kMachineByteOrder == machine::MSB) { write8(offset+0, (uint8_t) (value >> 8)); write8(offset+1, (uint8_t) (value >> 0)); } else { write8(offset+1, (uint8_t) (value >> 8)); write8(offset+0, (uint8_t) (value >> 0)); } } void ObjectState::write16(unsigned offset, ref<Expr> value) { if (kMachineByteOrder == machine::MSB) { write8(offset+0, ExtractExpr::createByteOff(value, 1)); write8(offset+1, ExtractExpr::createByteOff(value, 0)); } else { write8(offset+1, ExtractExpr::createByteOff(value, 1)); write8(offset+0, ExtractExpr::createByteOff(value, 0)); } } void ObjectState::write16(ref<Expr> offset, ref<Expr> value) { if (kMachineByteOrder == machine::MSB) { write8(AddExpr::create(offset, ConstantExpr::create(0, kMachinePointerType)), ExtractExpr::createByteOff(value,1)); write8(AddExpr::create(offset, ConstantExpr::create(0, kMachinePointerType)), ExtractExpr::createByteOff(value,0)); } else { write8(AddExpr::create(offset, ConstantExpr::create(1, kMachinePointerType)), ExtractExpr::createByteOff(value,1)); write8(AddExpr::create(offset, ConstantExpr::create(0, kMachinePointerType)), ExtractExpr::createByteOff(value,0)); } } void ObjectState::write32(unsigned offset, uint32_t value) { if (kMachineByteOrder == machine::MSB) { write8(offset+0, (uint8_t) (value >> 24)); write8(offset+1, (uint8_t) (value >> 16)); write8(offset+2, (uint8_t) (value >> 8)); write8(offset+3, (uint8_t) (value >> 0)); } else { write8(offset+3, (uint8_t) (value >> 24)); write8(offset+2, (uint8_t) (value >> 16)); write8(offset+1, (uint8_t) (value >> 8)); write8(offset+0, (uint8_t) (value >> 0)); } } void ObjectState::write32(unsigned offset, ref<Expr> value) { if (kMachineByteOrder == machine::MSB) { write8(offset+0, ExtractExpr::createByteOff(value, 3)); write8(offset+1, ExtractExpr::createByteOff(value, 2)); write8(offset+2, ExtractExpr::createByteOff(value, 1)); write8(offset+3, ExtractExpr::createByteOff(value, 0)); } else { write8(offset+3, ExtractExpr::createByteOff(value, 3)); write8(offset+2, ExtractExpr::createByteOff(value, 2)); write8(offset+1, ExtractExpr::createByteOff(value, 1)); write8(offset+0, ExtractExpr::createByteOff(value, 0)); } } void ObjectState::write32(ref<Expr> offset, ref<Expr> value) { if (kMachineByteOrder == machine::MSB) { write8(AddExpr::create(offset, ConstantExpr::create(0, kMachinePointerType)), ExtractExpr::createByteOff(value,3)); write8(AddExpr::create(offset, ConstantExpr::create(1, kMachinePointerType)), ExtractExpr::createByteOff(value,2)); write8(AddExpr::create(offset, ConstantExpr::create(2, kMachinePointerType)), ExtractExpr::createByteOff(value,1)); write8(AddExpr::create(offset, ConstantExpr::create(3, kMachinePointerType)), ExtractExpr::createByteOff(value,0)); } else { write8(AddExpr::create(offset, ConstantExpr::create(3, kMachinePointerType)), ExtractExpr::createByteOff(value,3)); write8(AddExpr::create(offset, ConstantExpr::create(2, kMachinePointerType)), ExtractExpr::createByteOff(value,2)); write8(AddExpr::create(offset, ConstantExpr::create(1, kMachinePointerType)), ExtractExpr::createByteOff(value,1)); write8(AddExpr::create(offset, ConstantExpr::create(0, kMachinePointerType)), ExtractExpr::createByteOff(value,0)); } } void ObjectState::write64(unsigned offset, uint64_t value) { if (kMachineByteOrder == machine::MSB) { write8(offset+0, (uint8_t) (value >> 56)); write8(offset+1, (uint8_t) (value >> 48)); write8(offset+2, (uint8_t) (value >> 40)); write8(offset+3, (uint8_t) (value >> 32)); write8(offset+4, (uint8_t) (value >> 24)); write8(offset+5, (uint8_t) (value >> 16)); write8(offset+6, (uint8_t) (value >> 8)); write8(offset+7, (uint8_t) (value >> 0)); } else { write8(offset+7, (uint8_t) (value >> 56)); write8(offset+6, (uint8_t) (value >> 48)); write8(offset+5, (uint8_t) (value >> 40)); write8(offset+4, (uint8_t) (value >> 32)); write8(offset+3, (uint8_t) (value >> 24)); write8(offset+2, (uint8_t) (value >> 16)); write8(offset+1, (uint8_t) (value >> 8)); write8(offset+0, (uint8_t) (value >> 0)); } } void ObjectState::write64(unsigned offset, ref<Expr> value) { if (kMachineByteOrder == machine::MSB) { write8(offset+0, ExtractExpr::createByteOff(value, 7)); write8(offset+1, ExtractExpr::createByteOff(value, 6)); write8(offset+2, ExtractExpr::createByteOff(value, 5)); write8(offset+3, ExtractExpr::createByteOff(value, 4)); write8(offset+4, ExtractExpr::createByteOff(value, 3)); write8(offset+5, ExtractExpr::createByteOff(value, 2)); write8(offset+6, ExtractExpr::createByteOff(value, 1)); write8(offset+7, ExtractExpr::createByteOff(value, 0)); } else { write8(offset+7, ExtractExpr::createByteOff(value, 7)); write8(offset+6, ExtractExpr::createByteOff(value, 6)); write8(offset+5, ExtractExpr::createByteOff(value, 5)); write8(offset+4, ExtractExpr::createByteOff(value, 4)); write8(offset+3, ExtractExpr::createByteOff(value, 3)); write8(offset+2, ExtractExpr::createByteOff(value, 2)); write8(offset+1, ExtractExpr::createByteOff(value, 1)); write8(offset+0, ExtractExpr::createByteOff(value, 0)); } } void ObjectState::write64(ref<Expr> offset, ref<Expr> value) { if (kMachineByteOrder == machine::MSB) { write8(AddExpr::create(offset, ConstantExpr::create(0, kMachinePointerType)), ExtractExpr::createByteOff(value,7)); write8(AddExpr::create(offset, ConstantExpr::create(1, kMachinePointerType)), ExtractExpr::createByteOff(value,6)); write8(AddExpr::create(offset, ConstantExpr::create(2, kMachinePointerType)), ExtractExpr::createByteOff(value,5)); write8(AddExpr::create(offset, ConstantExpr::create(3, kMachinePointerType)), ExtractExpr::createByteOff(value,4)); write8(AddExpr::create(offset, ConstantExpr::create(4, kMachinePointerType)), ExtractExpr::createByteOff(value,3)); write8(AddExpr::create(offset, ConstantExpr::create(5, kMachinePointerType)), ExtractExpr::createByteOff(value,2)); write8(AddExpr::create(offset, ConstantExpr::create(6, kMachinePointerType)), ExtractExpr::createByteOff(value,1)); write8(AddExpr::create(offset, ConstantExpr::create(7, kMachinePointerType)), ExtractExpr::createByteOff(value,0)); } else { write8(AddExpr::create(offset, ConstantExpr::create(7, kMachinePointerType)), ExtractExpr::createByteOff(value,7)); write8(AddExpr::create(offset, ConstantExpr::create(6, kMachinePointerType)), ExtractExpr::createByteOff(value,6)); write8(AddExpr::create(offset, ConstantExpr::create(5, kMachinePointerType)), ExtractExpr::createByteOff(value,5)); write8(AddExpr::create(offset, ConstantExpr::create(4, kMachinePointerType)), ExtractExpr::createByteOff(value,4)); write8(AddExpr::create(offset, ConstantExpr::create(3, kMachinePointerType)), ExtractExpr::createByteOff(value,3)); write8(AddExpr::create(offset, ConstantExpr::create(2, kMachinePointerType)), ExtractExpr::createByteOff(value,2)); write8(AddExpr::create(offset, ConstantExpr::create(1, kMachinePointerType)), ExtractExpr::createByteOff(value,1)); write8(AddExpr::create(offset, ConstantExpr::create(0, kMachinePointerType)), ExtractExpr::createByteOff(value,0)); } } void ObjectState::print() { llvm::cerr << "-- ObjectState --\n"; llvm::cerr << "\tMemoryObject ID: " << object->id << "\n"; llvm::cerr << "\tRoot Object: " << updates.root << "\n"; llvm::cerr << "\tSize: " << size << "\n"; llvm::cerr << "\tBytes:\n"; for (unsigned i=0; i<size; i++) { llvm::cerr << "\t\t["<<i<<"]" << " concrete? " << isByteConcrete(i) << " known-sym? " << isByteKnownSymbolic(i) << " flushed? " << isByteFlushed(i) << " = "; ref<Expr> e = read8(i); llvm::cerr << e << "\n"; } llvm::cerr << "\tUpdates:\n"; for (const UpdateNode *un=updates.head; un; un=un->next) { llvm::cerr << "\t\t[" << un->index << "] = " << un->value << "\n"; } }