about summary refs log tree commit diff homepage
path: root/lib/Core/Memory.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Core/Memory.cpp')
-rw-r--r--lib/Core/Memory.cpp812
1 files changed, 812 insertions, 0 deletions
diff --git a/lib/Core/Memory.cpp b/lib/Core/Memory.cpp
new file mode 100644
index 00000000..cd563551
--- /dev/null
+++ b/lib/Core/Memory.cpp
@@ -0,0 +1,812 @@
+//===-- 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 <iostream>
+#include <cassert>
+#include <sstream>
+
+using namespace llvm;
+using namespace klee;
+
+/***/
+
+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;
+
+extern "C" void vc_DeleteExpr(void*);
+
+MemoryObject::~MemoryObject() {
+  // FIXME: This shouldn't be necessary. Array's should be ref-counted
+  // just like everything else, and the interaction with the STP array
+  // should hide at least inside the Expr/Solver layers.
+  if (array) {
+    if (array->stpInitialArray) {
+      ::vc_DeleteExpr(array->stpInitialArray);
+      array->stpInitialArray = 0;
+    }
+    delete array;
+  }
+}
+
+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, unsigned _size)
+  : copyOnWriteOwner(0),
+    refCount(0),
+    object(mo),
+    concreteStore(new uint8_t[_size]),
+    concreteMask(0),
+    flushMask(0),
+    knownSymbolics(0),
+    size(_size),
+    updates(mo->array, false, 0),
+    readOnly(false) {
+}
+
+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),
+    size(os.size),
+    updates(os.updates),
+    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;
+}
+
+/***/
+
+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");
+  updates.isRooted = true;
+
+  // 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(updates, 
+                            ConstantExpr::create(offset, kMachinePointerType));
+  }    
+}
+
+ref<Expr> ObjectState::read8(ref<Expr> offset) const {
+  assert(!offset.isConstant() && "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(updates, 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 (value.isConstant()) {
+    write8(offset, (uint8_t) value.getConstantValue());
+  } else {
+    setKnownSymbolic(offset, value.get());
+      
+    markByteSymbolic(offset);
+    markByteUnflushed(offset);
+  }
+}
+
+void ObjectState::write8(ref<Expr> offset, ref<Expr> value) {
+  assert(!offset.isConstant() && "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 (offset.isConstant()) {
+    return read((unsigned) offset.getConstantValue(), width);
+  } else { 
+    switch (width) {
+    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);
+    default: assert(0 && "invalid type");
+    }
+  }
+}
+
+ref<Expr> ObjectState::read(unsigned offset, Expr::Width width) const {
+  switch (width) {
+  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);
+  default: assert(0 && "invalid type");
+  }
+}
+
+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 (offset.isConstant()) {
+    write(offset.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 (value.isConstant()) {
+    uint64_t val = value.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 << "\tIs Rooted? " << updates.isRooted << "\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";
+  }
+}