#ifndef SHADOW_H
#define SHADOW_H
#include <algorithm>
#include <cassert>
#include <cstring>
#include <iterator>
#include <map>
#include <Runtime.h>
constexpr uintptr_t kPageSize = 4096;
constexpr uintptr_t pageStart(uintptr_t addr) {
return (addr & ~(kPageSize - 1));
}
constexpr uintptr_t pageOffset(uintptr_t addr) {
return (addr & (kPageSize - 1));
}
extern std::map<uintptr_t, SymExpr *> g_shadow_pages;
class ReadShadowIterator
: public std::iterator<std::bidirectional_iterator_tag, SymExpr> {
public:
explicit ReadShadowIterator(uintptr_t address)
: std::iterator<std::bidirectional_iterator_tag, SymExpr>(),
address_(address), shadow_(getShadow(address)) {}
ReadShadowIterator &operator++() {
auto previousAddress = address_++;
if (shadow_ != nullptr)
shadow_++;
if (pageStart(address_) != pageStart(previousAddress))
shadow_ = getShadow(address_);
return *this;
}
ReadShadowIterator &operator--() {
auto previousAddress = address_--;
if (shadow_ != nullptr)
shadow_--;
if (pageStart(address_) != pageStart(previousAddress))
shadow_ = getShadow(address_);
return *this;
}
SymExpr operator*() {
assert((shadow_ == nullptr || *shadow_ == nullptr ||
_sym_bits_helper(*shadow_) == 8) &&
"Shadow memory always represents bytes");
return shadow_ != nullptr ? *shadow_ : nullptr;
}
bool operator==(const ReadShadowIterator &other) const {
return (address_ == other.address_);
}
bool operator!=(const ReadShadowIterator &other) const {
return !(*this == other);
}
protected:
static SymExpr *getShadow(uintptr_t address) {
if (auto shadowPageIt = g_shadow_pages.find(pageStart(address));
shadowPageIt != g_shadow_pages.end())
return shadowPageIt->second + pageOffset(address);
return nullptr;
}
uintptr_t address_;
SymExpr *shadow_;
};
class NonNullReadShadowIterator : public ReadShadowIterator {
public:
explicit NonNullReadShadowIterator(uintptr_t address)
: ReadShadowIterator(address) {}
SymExpr operator*() {
if (auto *symbolicResult = ReadShadowIterator::operator*())
return symbolicResult;
return _sym_build_integer(*reinterpret_cast<const uint8_t *>(address_), 8);
}
};
class WriteShadowIterator : public ReadShadowIterator {
public:
WriteShadowIterator(uintptr_t address) : ReadShadowIterator(address) {
shadow_ = getOrCreateShadow(address);
}
WriteShadowIterator &operator++() {
auto previousAddress = address_++;
shadow_++;
if (pageStart(address_) != pageStart(previousAddress))
shadow_ = getOrCreateShadow(address_);
return *this;
}
WriteShadowIterator &operator--() {
auto previousAddress = address_--;
shadow_--;
if (pageStart(address_) != pageStart(previousAddress))
shadow_ = getOrCreateShadow(address_);
return *this;
}
SymExpr &operator*() { return *shadow_; }
protected:
static SymExpr *getOrCreateShadow(uintptr_t address) {
if (auto *shadow = getShadow(address))
return shadow;
auto *newShadow =
static_cast<SymExpr *>(malloc(kPageSize * sizeof(SymExpr)));
memset(newShadow, 0, kPageSize * sizeof(SymExpr));
g_shadow_pages[pageStart(address)] = newShadow;
return newShadow + pageOffset(address);
}
};
struct ReadOnlyShadow {
template <typename T>
ReadOnlyShadow(T *addr, size_t len)
: address_(reinterpret_cast<uintptr_t>(addr)), length_(len) {}
ReadShadowIterator begin() const { return ReadShadowIterator(address_); }
ReadShadowIterator end() const {
return ReadShadowIterator(address_ + length_);
}
NonNullReadShadowIterator begin_non_null() const {
return NonNullReadShadowIterator(address_);
}
NonNullReadShadowIterator end_non_null() const {
return NonNullReadShadowIterator(address_ + length_);
}
uintptr_t address_;
size_t length_;
};
template <typename T> struct ReadWriteShadow {
ReadWriteShadow(T *addr, size_t len)
: address_(reinterpret_cast<uintptr_t>(addr)), length_(len) {}
WriteShadowIterator begin() { return WriteShadowIterator(address_); }
WriteShadowIterator end() { return WriteShadowIterator(address_ + length_); }
uintptr_t address_;
size_t length_;
};
template <typename T> bool isConcrete(T *addr, size_t nbytes) {
auto byteBuf = reinterpret_cast<uintptr_t>(addr);
if (pageStart(byteBuf) == pageStart(byteBuf + nbytes) &&
!g_shadow_pages.count(pageStart(byteBuf)))
return true;
ReadOnlyShadow shadow(addr, nbytes);
return std::all_of(shadow.begin(), shadow.end(),
[](SymExpr expr) { return (expr == nullptr); });
}
#endif