summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tools/standalone_miri/value.cpp82
-rw-r--r--tools/standalone_miri/value.hpp132
2 files changed, 133 insertions, 81 deletions
diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp
index beff8a38..af462e40 100644
--- a/tools/standalone_miri/value.cpp
+++ b/tools/standalone_miri/value.cpp
@@ -150,6 +150,68 @@ size_t AllocationPtr::get_size() const
return os;
}
+uint64_t ValueCommon::read_usize(size_t ofs) const
+{
+ uint64_t v = 0;
+ this->read_bytes(ofs, &v, POINTER_SIZE);
+ return v;
+}
+void ValueCommon::write_usize(size_t ofs, uint64_t v)
+{
+ this->write_bytes(ofs, &v, POINTER_SIZE);
+}
+void* ValueCommon::read_pointer_unsafe(size_t rd_ofs, size_t req_valid, size_t& out_size, bool& out_is_mut) const
+{
+ auto ofs = read_usize(rd_ofs);
+ auto reloc = get_relocation(rd_ofs);
+ if( !reloc )
+ {
+ if( ofs != 0 ) {
+ LOG_FATAL("Read a non-zero offset with no relocation");
+ }
+ out_is_mut = false;
+ out_size = 0;
+ return nullptr;
+ }
+ else
+ {
+ switch(reloc.get_ty())
+ {
+ case AllocationPtr::Ty::Allocation: {
+ auto& a = reloc.alloc();
+ if( ofs > a.size() )
+ LOG_FATAL("Out-of-bounds pointer");
+ if( ofs + req_valid > a.size() )
+ LOG_FATAL("Out-of-bounds pointer (" << ofs << " + " << req_valid << " > " << a.size());
+ a.check_bytes_valid( ofs, req_valid );
+ out_size = a.size() - ofs;
+ out_is_mut = true;
+ return a.data_ptr() + ofs;
+ }
+ case AllocationPtr::Ty::StdString: {
+ const auto& s = reloc.str();
+ if( ofs > s.size() )
+ LOG_FATAL("Out-of-bounds pointer");
+ if( ofs + req_valid > s.size() )
+ LOG_FATAL("Out-of-bounds pointer (" << ofs << " + " << req_valid << " > " << s.size());
+ out_size = s.size() - ofs;
+ out_is_mut = false;
+ return const_cast<void*>( static_cast<const void*>(s.data() + ofs) );
+ }
+ case AllocationPtr::Ty::Function:
+ LOG_FATAL("read_pointer w/ function");
+ case AllocationPtr::Ty::FfiPointer:
+ if( req_valid )
+ LOG_FATAL("Can't request valid data from a FFI pointer");
+ // TODO: Have an idea of mutability and available size from FFI
+ out_size = 0;
+ out_is_mut = false;
+ return reloc.ffi().ptr_value /* + ofs */;
+ }
+ throw "";
+ }
+}
+
void Allocation::resize(size_t new_size)
{
@@ -371,10 +433,6 @@ void Allocation::write_bytes(size_t ofs, const void* src, size_t count)
::std::memcpy(this->data_ptr() + ofs, src, count);
mark_bytes_valid(ofs, count);
}
-void Allocation::write_usize(size_t ofs, uint64_t v)
-{
- this->write_bytes(ofs, &v, POINTER_SIZE);
-}
::std::ostream& operator<<(::std::ostream& os, const Allocation& x)
{
auto flags = os.flags();
@@ -651,10 +709,6 @@ void Value::write_value(size_t ofs, Value v)
}
}
}
-void Value::write_usize(size_t ofs, uint64_t v)
-{
- this->write_bytes(ofs, &v, POINTER_SIZE);
-}
::std::ostream& operator<<(::std::ostream& os, const Value& v)
{
@@ -775,15 +829,3 @@ uint64_t ValueRef::read_usize(size_t ofs) const
this->read_bytes(ofs, &v, POINTER_SIZE);
return v;
}
-uint64_t Value::read_usize(size_t ofs) const
-{
- uint64_t v = 0;
- this->read_bytes(ofs, &v, POINTER_SIZE);
- return v;
-}
-uint64_t Allocation::read_usize(size_t ofs) const
-{
- uint64_t v = 0;
- this->read_bytes(ofs, &v, POINTER_SIZE);
- return v;
-} \ No newline at end of file
diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp
index fb5cc5ae..95f8b508 100644
--- a/tools/standalone_miri/value.hpp
+++ b/tools/standalone_miri/value.hpp
@@ -110,7 +110,60 @@ struct Relocation
size_t slot_ofs;
AllocationPtr backing_alloc;
};
-class Allocation
+
+struct ValueCommon
+{
+ virtual AllocationPtr get_relocation(size_t ofs) const = 0;
+ virtual void read_bytes(size_t ofs, void* dst, size_t count) const = 0;
+ virtual void write_bytes(size_t ofs, const void* src, size_t count) = 0;
+
+ void write_u8 (size_t ofs, uint8_t v) { write_bytes(ofs, &v, 1); }
+ void write_u16(size_t ofs, uint16_t v) { write_bytes(ofs, &v, 2); }
+ void write_u32(size_t ofs, uint32_t v) { write_bytes(ofs, &v, 4); }
+ void write_u64(size_t ofs, uint64_t v) { write_bytes(ofs, &v, 8); }
+ void write_i8 (size_t ofs, int8_t v) { write_u8 (ofs, static_cast<uint8_t >(v)); }
+ void write_i16(size_t ofs, int16_t v) { write_u16(ofs, static_cast<uint16_t>(v)); }
+ void write_i32(size_t ofs, int32_t v) { write_u32(ofs, static_cast<uint32_t>(v)); }
+ void write_i64(size_t ofs, int64_t v) { write_u64(ofs, static_cast<uint64_t>(v)); }
+ void write_f32(size_t ofs, float v) { write_bytes(ofs, &v, 4); }
+ void write_f64(size_t ofs, double v) { write_bytes(ofs, &v, 8); }
+ void write_usize(size_t ofs, uint64_t v);
+ void write_isize(size_t ofs, int64_t v) { write_usize(ofs, static_cast<uint64_t>(v)); }
+
+ uint8_t read_u8(size_t ofs) const { uint8_t rv; read_bytes(ofs, &rv, 1); return rv; }
+ uint16_t read_u16(size_t ofs) const { uint16_t rv; read_bytes(ofs, &rv, 2); return rv; }
+ uint32_t read_u32(size_t ofs) const { uint32_t rv; read_bytes(ofs, &rv, 4); return rv; }
+ uint64_t read_u64(size_t ofs) const { uint64_t rv; read_bytes(ofs, &rv, 8); return rv; }
+ int8_t read_i8(size_t ofs) const { return static_cast<int8_t>(read_u8(ofs)); }
+ int16_t read_i16(size_t ofs) const { return static_cast<int16_t>(read_u16(ofs)); }
+ int32_t read_i32(size_t ofs) const { return static_cast<int32_t>(read_u32(ofs)); }
+ int64_t read_i64(size_t ofs) const { return static_cast<int64_t>(read_u64(ofs)); }
+ float read_f32(size_t ofs) const { float rv; read_bytes(ofs, &rv, 4); return rv; }
+ double read_f64(size_t ofs) const { double rv; read_bytes(ofs, &rv, 8); return rv; }
+ uint64_t read_usize(size_t ofs) const;
+ int64_t read_isize(size_t ofs) const { return static_cast<int64_t>(read_usize(ofs)); }
+
+ /// Read a pointer from the value, requiring at least `req_valid` valid bytes, saves avaliable space in `size`
+ void* read_pointer_unsafe(size_t rd_ofs, size_t req_valid, size_t& size, bool& is_mut) const;
+ /// Read a pointer, requiring `req_len` valid bytes
+ const void* read_pointer_const(size_t rd_ofs, size_t req_len) const {
+ size_t tmp;
+ bool is_mut;
+ return read_pointer_unsafe(rd_ofs, req_len, tmp, is_mut);
+ }
+ /// Read a pointer, not requiring that the target be initialised
+ void* read_pointer_uninit(size_t rd_ofs, size_t& out_size) {
+ bool is_mut;
+ void* rv = read_pointer_unsafe(rd_ofs, 0, out_size, is_mut);
+ if(!is_mut)
+ throw "";
+ //LOG_FATAL("Attempting to get an uninit pointer to immutable data");
+ return rv;
+ }
+};
+
+class Allocation:
+ public ValueCommon
{
friend class AllocationPtr;
size_t refcount;
@@ -126,7 +179,7 @@ public:
::std::vector<uint8_t> mask;
::std::vector<Relocation> relocations;
- AllocationPtr get_relocation(size_t ofs) const {
+ AllocationPtr get_relocation(size_t ofs) const override {
for(const auto& r : relocations) {
if(r.slot_ofs == ofs)
return r.backing_alloc;
@@ -144,41 +197,15 @@ public:
void mark_bytes_valid(size_t ofs, size_t size);
Value read_value(size_t ofs, size_t size) const;
- void read_bytes(size_t ofs, void* dst, size_t count) const;
+ void read_bytes(size_t ofs, void* dst, size_t count) const override;
void write_value(size_t ofs, Value v);
- void write_bytes(size_t ofs, const void* src, size_t count);
-
- // TODO: Make this block common
- void write_u8 (size_t ofs, uint8_t v) { write_bytes(ofs, &v, 1); }
- void write_u16(size_t ofs, uint16_t v) { write_bytes(ofs, &v, 2); }
- void write_u32(size_t ofs, uint32_t v) { write_bytes(ofs, &v, 4); }
- void write_u64(size_t ofs, uint64_t v) { write_bytes(ofs, &v, 8); }
- void write_i8 (size_t ofs, int8_t v) { write_u8 (ofs, static_cast<uint8_t >(v)); }
- void write_i16(size_t ofs, int16_t v) { write_u16(ofs, static_cast<uint16_t>(v)); }
- void write_i32(size_t ofs, int32_t v) { write_u32(ofs, static_cast<uint32_t>(v)); }
- void write_i64(size_t ofs, int64_t v) { write_u64(ofs, static_cast<uint64_t>(v)); }
- void write_f32(size_t ofs, float v) { write_bytes(ofs, &v, 4); }
- void write_f64(size_t ofs, double v) { write_bytes(ofs, &v, 8); }
- void write_usize(size_t ofs, uint64_t v);
- void write_isize(size_t ofs, int64_t v) { write_usize(ofs, static_cast<uint64_t>(v)); }
-
- uint8_t read_u8(size_t ofs) const { uint8_t rv; read_bytes(ofs, &rv, 1); return rv; }
- uint16_t read_u16(size_t ofs) const { uint16_t rv; read_bytes(ofs, &rv, 2); return rv; }
- uint32_t read_u32(size_t ofs) const { uint32_t rv; read_bytes(ofs, &rv, 4); return rv; }
- uint64_t read_u64(size_t ofs) const { uint64_t rv; read_bytes(ofs, &rv, 8); return rv; }
- int8_t read_i8(size_t ofs) const { return static_cast<int8_t>(read_u8(ofs)); }
- int16_t read_i16(size_t ofs) const { return static_cast<int16_t>(read_u16(ofs)); }
- int32_t read_i32(size_t ofs) const { return static_cast<int32_t>(read_u32(ofs)); }
- int64_t read_i64(size_t ofs) const { return static_cast<int64_t>(read_u64(ofs)); }
- float read_f32(size_t ofs) const { float rv; read_bytes(ofs, &rv, 4); return rv; }
- double read_f64(size_t ofs) const { double rv; read_bytes(ofs, &rv, 8); return rv; }
- uint64_t read_usize(size_t ofs) const;
- int64_t read_isize(size_t ofs) const { return static_cast<int64_t>(read_usize(ofs)); }
+ void write_bytes(size_t ofs, const void* src, size_t count) override;
};
extern ::std::ostream& operator<<(::std::ostream& os, const Allocation& x);
-struct Value
+struct Value:
+ public ValueCommon
{
// If NULL, data is direct
AllocationPtr allocation;
@@ -197,46 +224,27 @@ struct Value
void create_allocation();
size_t size() const { return allocation ? allocation.alloc().size() : direct_data.size; }
+ AllocationPtr get_relocation(size_t ofs) const override {
+ if( this->allocation && this->allocation.is_alloc() )
+ return this->allocation.alloc().get_relocation(ofs);
+ else
+ return AllocationPtr();
+ }
+
void check_bytes_valid(size_t ofs, size_t size) const;
void mark_bytes_valid(size_t ofs, size_t size);
Value read_value(size_t ofs, size_t size) const;
- void read_bytes(size_t ofs, void* dst, size_t count) const;
+ void read_bytes(size_t ofs, void* dst, size_t count) const override;
void write_value(size_t ofs, Value v);
- void write_bytes(size_t ofs, const void* src, size_t count);
-
- // TODO: Make this block common
- void write_u8 (size_t ofs, uint8_t v) { write_bytes(ofs, &v, 1); }
- void write_u16(size_t ofs, uint16_t v) { write_bytes(ofs, &v, 2); }
- void write_u32(size_t ofs, uint32_t v) { write_bytes(ofs, &v, 4); }
- void write_u64(size_t ofs, uint64_t v) { write_bytes(ofs, &v, 8); }
- void write_i8 (size_t ofs, int8_t v) { write_u8 (ofs, static_cast<uint8_t >(v)); }
- void write_i16(size_t ofs, int16_t v) { write_u16(ofs, static_cast<uint16_t>(v)); }
- void write_i32(size_t ofs, int32_t v) { write_u32(ofs, static_cast<uint32_t>(v)); }
- void write_i64(size_t ofs, int64_t v) { write_u64(ofs, static_cast<uint64_t>(v)); }
- void write_f32(size_t ofs, float v) { write_bytes(ofs, &v, 4); }
- void write_f64(size_t ofs, double v) { write_bytes(ofs, &v, 8); }
- void write_usize(size_t ofs, uint64_t v);
- void write_isize(size_t ofs, int64_t v) { write_usize(ofs, static_cast<uint64_t>(v)); }
-
- uint8_t read_u8(size_t ofs) const { uint8_t rv; read_bytes(ofs, &rv, 1); return rv; }
- uint16_t read_u16(size_t ofs) const { uint16_t rv; read_bytes(ofs, &rv, 2); return rv; }
- uint32_t read_u32(size_t ofs) const { uint32_t rv; read_bytes(ofs, &rv, 4); return rv; }
- uint64_t read_u64(size_t ofs) const { uint64_t rv; read_bytes(ofs, &rv, 8); return rv; }
- int8_t read_i8(size_t ofs) const { return static_cast<int8_t>(read_u8(ofs)); }
- int16_t read_i16(size_t ofs) const { return static_cast<int16_t>(read_u16(ofs)); }
- int32_t read_i32(size_t ofs) const { return static_cast<int32_t>(read_u32(ofs)); }
- int64_t read_i64(size_t ofs) const { return static_cast<int64_t>(read_u64(ofs)); }
- float read_f32(size_t ofs) const { float rv; read_bytes(ofs, &rv, 4); return rv; }
- double read_f64(size_t ofs) const { double rv; read_bytes(ofs, &rv, 8); return rv; }
- uint64_t read_usize(size_t ofs) const;
- int64_t read_isize(size_t ofs) const { return static_cast<int64_t>(read_usize(ofs)); }
+ void write_bytes(size_t ofs, const void* src, size_t count) override;
};
extern ::std::ostream& operator<<(::std::ostream& os, const Value& v);
// A read-only reference to a value (to write, you have to go through it)
struct ValueRef
+ //:public ValueCommon
{
// Either an AllocationPtr, or a Value pointer
AllocationPtr m_alloc;
@@ -352,6 +360,8 @@ struct ValueRef
m_value->read_bytes(m_offset + ofs, dst, size);
}
}
+
+ // TODO: Figure out how to make this use `ValueCommon` when it can't write.
uint8_t read_u8(size_t ofs) const { uint8_t rv; read_bytes(ofs, &rv, 1); return rv; }
uint16_t read_u16(size_t ofs) const { uint16_t rv; read_bytes(ofs, &rv, 2); return rv; }
uint32_t read_u32(size_t ofs) const { uint32_t rv; read_bytes(ofs, &rv, 4); return rv; }