diff options
-rw-r--r-- | tools/standalone_miri/value.cpp | 82 | ||||
-rw-r--r-- | tools/standalone_miri/value.hpp | 132 |
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; } |