summaryrefslogtreecommitdiff
path: root/tools/standalone_miri/value.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/standalone_miri/value.cpp')
-rw-r--r--tools/standalone_miri/value.cpp451
1 files changed, 258 insertions, 193 deletions
diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp
index e4a19196..44fd2d02 100644
--- a/tools/standalone_miri/value.cpp
+++ b/tools/standalone_miri/value.cpp
@@ -108,18 +108,194 @@ AllocationPtr::~AllocationPtr()
return os;
}
+
+void Allocation::check_bytes_valid(size_t ofs, size_t size) const
+{
+ if( !(ofs + size <= this->size()) ) {
+ LOG_FATAL("Out of range - " << ofs << "+" << size << " > " << this->size());
+ }
+ for(size_t i = ofs; i < ofs + size; i++)
+ {
+ if( !(this->mask[i/8] & (1 << i%8)) )
+ {
+ ::std::cerr << "ERROR: Invalid bytes in value" << ::std::endl;
+ throw "ERROR";
+ }
+ }
+}
+void Allocation::mark_bytes_valid(size_t ofs, size_t size)
+{
+ assert( ofs+size <= this->mask.size() * 8 );
+ for(size_t i = ofs; i < ofs + size; i++)
+ {
+ this->mask[i/8] |= (1 << i%8);
+ }
+}
+Value Allocation::read_value(size_t ofs, size_t size) const
+{
+ Value rv;
+ // TODO: Determine if this can become an inline allocation.
+ bool has_reloc = false;
+ for(const auto& r : this->relocations)
+ {
+ if( ofs <= r.slot_ofs && r.slot_ofs < ofs + size )
+ {
+ has_reloc = true;
+ }
+ }
+ if( has_reloc || size > sizeof(rv.direct_data.data) )
+ {
+ rv.allocation = Allocation::new_alloc(size);
+
+ rv.write_bytes(0, this->data_ptr() + ofs, size);
+
+ for(const auto& r : this->relocations)
+ {
+ if( ofs <= r.slot_ofs && r.slot_ofs < ofs + size )
+ {
+ rv.allocation.alloc().relocations.push_back({ r.slot_ofs - ofs, r.backing_alloc });
+ }
+ }
+ }
+ else
+ {
+ rv.direct_data.size = static_cast<uint8_t>(size);
+ rv.write_bytes(0, this->data_ptr() + ofs, size);
+ }
+ return rv;
+}
+void Allocation::read_bytes(size_t ofs, void* dst, size_t count) const
+{
+ if(ofs >= this->size() ) {
+ ::std::cerr << "Value::write_bytes - Out of bounds read, " << ofs << " >= " << this->size() << ::std::endl;
+ throw "ERROR";
+ }
+ if(count > this->size() ) {
+ ::std::cerr << "Value::write_bytes - Out of bounds read, count " << count << " > size " << this->size() << ::std::endl;
+ throw "ERROR";
+ }
+ if(ofs+count > this->size() ) {
+ ::std::cerr << "Value::write_bytes - Out of bounds read, " << ofs << "+" << count << " > size " << this->size() << ::std::endl;
+ throw "ERROR";
+ }
+ check_bytes_valid(ofs, count);
+
+
+ ::std::memcpy(dst, this->data_ptr() + ofs, count);
+}
+void Allocation::write_value(size_t ofs, Value v)
+{
+ if( v.allocation )
+ {
+ size_t v_size = v.allocation.alloc().size();
+ const auto& src_alloc = v.allocation.alloc();
+ // TODO: Just copy the validity from the source.
+ v.check_bytes_valid(0, v_size);
+
+ // Save relocations first, because `Foo = Foo` is valid.
+ ::std::vector<Relocation> new_relocs = src_alloc.relocations;
+ // - write_bytes removes any relocations in this region.
+ write_bytes(ofs, src_alloc.data_ptr(), v_size);
+
+ // Find any relocations that apply and copy those in.
+ // - Any relocations in the source within `v.meta.indirect_meta.offset` .. `v.meta.indirect_meta.offset + v_size`
+ if( !new_relocs.empty() )
+ {
+ // 2. Move the new relocations into this allocation
+ for(auto& r : new_relocs)
+ {
+ LOG_TRACE("Insert " << r.backing_alloc);
+ r.slot_ofs += ofs;
+ this->relocations.push_back( ::std::move(r) );
+ }
+ }
+ }
+ else
+ {
+ // TODO: Check validity of input, OR just copy the validity
+ v.check_bytes_valid(0, v.direct_data.size);
+ this->write_bytes(ofs, v.direct_data.data, v.direct_data.size);
+ }
+}
+void Allocation::write_bytes(size_t ofs, const void* src, size_t count)
+{
+ if(ofs >= this->size() ) {
+ ::std::cerr << "Value::write_bytes - Out of bounds write, " << ofs << " >= " << this->size() << ::std::endl;
+ throw "ERROR";
+ }
+ if(count > this->size() ) {
+ ::std::cerr << "Value::write_bytes - Out of bounds write, count " << count << " > size " << this->size() << ::std::endl;
+ throw "ERROR";
+ }
+ if(ofs+count > this->size() ) {
+ ::std::cerr << "Value::write_bytes - Out of bounds write, " << ofs << "+" << count << " > size " << this->size() << ::std::endl;
+ throw "ERROR";
+ }
+
+
+ // - Remove any relocations already within this region
+ auto& this_relocs = this->relocations;
+ for(auto it = this_relocs.begin(); it != this_relocs.end(); )
+ {
+ if( ofs <= it->slot_ofs && it->slot_ofs < ofs + count)
+ {
+ LOG_TRACE("Delete " << it->backing_alloc);
+ it = this_relocs.erase(it);
+ }
+ else
+ {
+ ++it;
+ }
+ }
+
+ ::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(0, &v, POINTER_SIZE);
+}
+::std::ostream& operator<<(::std::ostream& os, const Allocation& x)
+{
+ for(size_t i = 0; i < x.size(); i++)
+ {
+ if( i != 0 )
+ os << " ";
+
+ if( x.mask[i/8] & (1 << i%8) )
+ {
+ os << ::std::setw(2) << ::std::setfill('0') << (int)x.data_ptr()[i];
+ }
+ else
+ {
+ os << "--";
+ }
+ }
+
+ os << " {";
+ for(const auto& r : x.relocations)
+ {
+ if( 0 <= r.slot_ofs && r.slot_ofs < x.size() )
+ {
+ os << " @" << r.slot_ofs << "=" << r.backing_alloc;
+ }
+ }
+ os << " }";
+ return os;
+}
+
Value::Value()
{
- this->meta.direct_data.size = 0;
- this->meta.direct_data.mask[0] = 0;
- this->meta.direct_data.mask[1] = 0;
+ this->direct_data.size = 0;
+ this->direct_data.mask[0] = 0;
+ this->direct_data.mask[1] = 0;
}
Value::Value(::HIR::TypeRef ty)
{
size_t size = ty.get_size();
#if 1
// Support inline data if the data will fit within the inline region (which is the size of the metadata)
- if( ty.get_size() <= sizeof(this->meta.direct_data.data) )
+ if( ty.get_size() <= sizeof(this->direct_data.data) )
{
struct H
{
@@ -152,9 +328,9 @@ Value::Value(::HIR::TypeRef ty)
{
// Will fit in a inline allocation, nice.
//LOG_TRACE("No pointers in " << ty << ", storing inline");
- this->meta.direct_data.size = static_cast<uint8_t>(size);
- this->meta.direct_data.mask[0] = 0;
- this->meta.direct_data.mask[1] = 0;
+ this->direct_data.size = static_cast<uint8_t>(size);
+ this->direct_data.mask[0] = 0;
+ this->direct_data.mask[1] = 0;
return ;
}
}
@@ -163,8 +339,6 @@ Value::Value(::HIR::TypeRef ty)
// Fallback: Make a new allocation
//LOG_TRACE(" Creating allocation for " << ty);
this->allocation = Allocation::new_alloc(size);
- this->meta.indirect_meta.offset = 0;
- this->meta.indirect_meta.size = size;
}
Value Value::new_fnptr(const ::HIR::Path& fn_path)
{
@@ -176,44 +350,40 @@ Value Value::new_fnptr(const ::HIR::Path& fn_path)
return rv;
}
+void Value::create_allocation()
+{
+ assert(!this->allocation);
+ this->allocation = Allocation::new_alloc(this->direct_data.size);
+ this->allocation.alloc().mask[0] = this->direct_data.mask[0];
+ this->allocation.alloc().mask[1] = this->direct_data.mask[1];
+ ::std::memcpy(this->allocation.alloc().data.data(), this->direct_data.data, this->direct_data.size);
+}
void Value::check_bytes_valid(size_t ofs, size_t size) const
{
+ if( size == 0 )
+ return ;
if( this->allocation )
{
- const auto& alloc = this->allocation.alloc();
- if( ofs >= this->meta.indirect_meta.size || ofs+size > this->meta.indirect_meta.size ) {
- ::std::cerr << "ERROR: OOB read" << ::std::endl;
- throw "ERROR";
- }
- ofs += this->meta.indirect_meta.offset;
- //assert(ofs + size < alloc.size());
- for(size_t i = ofs; i < ofs + size; i++)
- {
- if( !(alloc.mask[i/8] & (1 << i%8)) )
- {
- ::std::cerr << "ERROR: Invalid bytes in value" << ::std::endl;
- throw "ERROR";
- }
- }
+ this->allocation.alloc().check_bytes_valid(ofs, size);
}
else
{
- if( size == 0 && this->meta.direct_data.size > 0 ) {
+ if( size == 0 && this->direct_data.size > 0 ) {
return ;
}
- if( ofs >= this->meta.direct_data.size ) {
- ::std::cerr << "ERROR: OOB read" << ::std::endl;
+ if( ofs >= this->direct_data.size ) {
+ LOG_ERROR("Read out of bounds " << ofs << "+" << size << " > " << int(this->direct_data.size));
throw "ERROR";
}
- if( ofs+size > this->meta.direct_data.size ) {
- ::std::cerr << "ERROR: OOB read" << ::std::endl;
+ if( ofs+size > this->direct_data.size ) {
+ LOG_ERROR("Read out of bounds " << ofs+size << " >= " << int(this->direct_data.size));
throw "ERROR";
}
for(size_t i = ofs; i < ofs + size; i++)
{
- if( !(this->meta.direct_data.mask[i/8] & (1 << i%8)) )
+ if( !(this->direct_data.mask[i/8] & (1 << i%8)) )
{
- ::std::cerr << "ERROR: Invalid bytes in value" << ::std::endl;
+ LOG_ERROR("Accessing invalid bytes in value");
throw "ERROR";
}
}
@@ -223,20 +393,13 @@ void Value::mark_bytes_valid(size_t ofs, size_t size)
{
if( this->allocation )
{
- auto& alloc = this->allocation.alloc();
- // TODO: Assert range.
- ofs += this->meta.indirect_meta.offset;
- assert( ofs+size <= alloc.mask.size() * 8 );
- for(size_t i = ofs; i < ofs + size; i++)
- {
- alloc.mask[i/8] |= (1 << i%8);
- }
+ this->allocation.alloc().mark_bytes_valid(ofs, size);
}
else
{
- for(size_t i = 0; i < this->meta.direct_data.size; i++)
+ for(size_t i = 0; i < this->direct_data.size; i++)
{
- this->meta.direct_data.mask[i/8] |= (1 << i%8);
+ this->direct_data.mask[i/8] |= (1 << i%8);
}
}
}
@@ -248,211 +411,113 @@ Value Value::read_value(size_t ofs, size_t size) const
check_bytes_valid(ofs, size);
if( this->allocation )
{
- const auto& alloc = this->allocation.alloc();
- // TODO: Determine if this can become an inline allocation.
- bool has_reloc = false;
- for(const auto& r : alloc.relocations)
- {
- if( this->meta.indirect_meta.offset+ofs <= r.slot_ofs && r.slot_ofs < this->meta.indirect_meta.offset + ofs + size )
- {
- has_reloc = true;
- }
- }
- if( has_reloc || size > sizeof(this->meta.direct_data.data) )
- {
- rv.allocation = Allocation::new_alloc(size);
- rv.meta.indirect_meta.offset = 0;
- rv.meta.indirect_meta.size = size;
-
- for(const auto& r : alloc.relocations)
- {
- if( this->meta.indirect_meta.offset+ofs <= r.slot_ofs && r.slot_ofs < this->meta.indirect_meta.offset + ofs + size )
- {
- rv.allocation.alloc().relocations.push_back({ r.slot_ofs - (this->meta.indirect_meta.offset+ofs), r.backing_alloc });
- }
- }
- }
- else
- {
- rv.meta.direct_data.size = static_cast<uint8_t>(size);
- }
- rv.write_bytes(0, this->data_ptr() + ofs, size);
+ rv = this->allocation.alloc().read_value(ofs, size);
}
else
{
// Inline can become inline.
- rv.meta.direct_data.size = static_cast<uint8_t>(size);
- rv.write_bytes(0, this->meta.direct_data.data+ofs, size);
+ rv.direct_data.size = static_cast<uint8_t>(size);
+ rv.write_bytes(0, this->direct_data.data+ofs, size);
}
LOG_DEBUG("RETURN " << rv);
return rv;
}
void Value::read_bytes(size_t ofs, void* dst, size_t count) const
{
- check_bytes_valid(ofs, count);
- throw "TODO";
-}
-
-void Value::write_bytes(size_t ofs, const void* src, size_t count)
-{
if( this->allocation )
{
- if(ofs >= this->meta.indirect_meta.size ) {
- ::std::cerr << "Value::write_bytes - Out of bounds write, " << ofs << " >= " << this->meta.indirect_meta.size << ::std::endl;
+ this->allocation.alloc().read_bytes(ofs, dst, count);
+ }
+ else
+ {
+ check_bytes_valid(ofs, count);
+
+ if(ofs >= this->direct_data.size )
throw "ERROR";
- }
- if(count > this->meta.indirect_meta.size ) {
- ::std::cerr << "Value::write_bytes - Out of bounds write, count " << count << " > size " << this->meta.indirect_meta.size << ::std::endl;
+ if(count > this->direct_data.size )
throw "ERROR";
- }
- if(ofs+count > this->meta.indirect_meta.size ) {
- ::std::cerr << "Value::write_bytes - Out of bounds write, " << ofs << "+" << count << " > size " << this->meta.indirect_meta.size << ::std::endl;
+ if(ofs+count > this->direct_data.size )
throw "ERROR";
- }
-
-
- // - Remove any relocations already within this region
- auto& this_relocs = this->allocation.alloc().relocations;
- for(auto it = this_relocs.begin(); it != this_relocs.end(); )
- {
- if( this->meta.indirect_meta.offset + ofs <= it->slot_ofs && it->slot_ofs < this->meta.indirect_meta.offset + ofs + count)
- {
- LOG_TRACE("Delete " << it->backing_alloc);
- it = this_relocs.erase(it);
- }
- else
- {
- ++it;
- }
- }
+ ::std::memcpy(dst, this->direct_data.data + ofs, count);
+ }
+}
+void Value::write_bytes(size_t ofs, const void* src, size_t count)
+{
+ if( count == 0 )
+ return ;
+ if( this->allocation )
+ {
+ this->allocation.alloc().write_bytes(ofs, src, count);
}
else
{
- if(ofs >= this->meta.direct_data.size )
+ if(ofs >= this->direct_data.size )
throw "ERROR";
- if(count > this->meta.direct_data.size )
+ if(count > this->direct_data.size )
throw "ERROR";
- if(ofs+count > this->meta.direct_data.size )
+ if(ofs+count > this->direct_data.size )
throw "ERROR";
+ ::std::memcpy(this->direct_data.data + ofs, src, count);
+ mark_bytes_valid(ofs, count);
}
- ::std::memcpy(this->data_ptr() + ofs, src, count);
- mark_bytes_valid(ofs, count);
}
void Value::write_value(size_t ofs, Value v)
{
- if( v.allocation )
+ if( this->allocation )
{
- size_t v_size = v.meta.indirect_meta.size;
- v.check_bytes_valid(0, v_size);
- const auto& src_alloc = v.allocation.alloc();
- write_bytes(ofs, v.data_ptr(), v_size);
- // Find any relocations that apply and copy those in.
- // - Any relocations in the source within `v.meta.indirect_meta.offset` .. `v.meta.indirect_meta.offset + v_size`
- ::std::vector<Relocation> new_relocs;
- for(const auto& r : src_alloc.relocations)
+ this->allocation.alloc().write_value(ofs, ::std::move(v));
+ }
+ else
+ {
+ if( v.allocation && !v.allocation.alloc().relocations.empty() )
{
- // TODO: Negative offsets in destination?
- if( v.meta.indirect_meta.offset <= r.slot_ofs && r.slot_ofs < v.meta.indirect_meta.offset + v_size )
- {
- LOG_TRACE("Copy " << r.backing_alloc);
- // Applicable, save for later
- new_relocs.push_back( r );
- }
+ this->create_allocation();
+ this->allocation.alloc().write_value(ofs, ::std::move(v));
}
- if( !new_relocs.empty() )
+ else
{
- if( !this->allocation ) {
- throw ::std::runtime_error("TODO: Writing value with a relocation into a slot without a relocation");
- }
- // 1. Remove any relocations already within this region
- auto& this_relocs = this->allocation.alloc().relocations;
- for(auto it = this_relocs.begin(); it != this_relocs.end(); )
- {
- if( this->meta.indirect_meta.offset + ofs <= it->slot_ofs && it->slot_ofs < this->meta.indirect_meta.offset + ofs + v_size)
- {
- LOG_TRACE("Delete " << it->backing_alloc);
- it = this_relocs.erase(it);
- }
- else
- {
- ++it;
- }
- }
- // 2. Move the new relocations into this allocation
- for(auto& r : new_relocs)
- {
- LOG_TRACE("Insert " << r.backing_alloc);
- r.slot_ofs -= v.meta.indirect_meta.offset;
- r.slot_ofs += this->meta.indirect_meta.offset + ofs;
- this_relocs.push_back( ::std::move(r) );
- }
+ v.check_bytes_valid(0, v.direct_data.size);
+ write_bytes(ofs, v.direct_data.data, v.direct_data.size);
}
}
- else
- {
- v.check_bytes_valid(0, v.meta.direct_data.size);
- write_bytes(ofs, v.meta.direct_data.data, v.meta.direct_data.size);
- }
}
-
-uint64_t Value::read_usize(size_t ofs) const
+void Value::write_usize(size_t ofs, uint64_t v)
{
- uint64_t v = 0;
- // TODO: Handle different pointer sizes
- this->read_bytes(0, &v, 8);
- return v;
+ this->write_bytes(0, &v, POINTER_SIZE);
}
::std::ostream& operator<<(::std::ostream& os, const Value& v)
{
- auto flags = os.flags();
- os << ::std::hex;
if( v.allocation )
{
- const auto& alloc = v.allocation.alloc();
- for(size_t i = 0; i < v.meta.indirect_meta.size; i++)
- {
- if( i != 0 )
- os << " ";
- size_t j = i + v.meta.indirect_meta.offset;
-
- if( alloc.mask[j/8] & (1 << i%8) )
- {
- os << ::std::setw(2) << ::std::setfill('0') << (int)alloc.data_ptr()[j];
- }
- else
- {
- os << "--";
- }
- }
-
- os << " {";
- for(const auto& r : alloc.relocations)
- {
- if( v.meta.indirect_meta.offset <= r.slot_ofs && r.slot_ofs < v.meta.indirect_meta.offset + v.meta.indirect_meta.size )
- {
- os << " @" << (r.slot_ofs - v.meta.indirect_meta.offset) << "=" << r.backing_alloc;
- }
- }
- os << " }";
+ os << v.allocation.alloc();
}
else
{
- for(size_t i = 0; i < v.meta.direct_data.size; i++)
+ auto flags = os.flags();
+ os << ::std::hex;
+ for(size_t i = 0; i < v.direct_data.size; i++)
{
if( i != 0 )
os << " ";
- if( v.meta.direct_data.mask[i/8] & (1 << i%8) )
+ if( v.direct_data.mask[i/8] & (1 << i%8) )
{
- os << ::std::setw(2) << ::std::setfill('0') << (int)v.meta.direct_data.data[i];
+ os << ::std::setw(2) << ::std::setfill('0') << (int)v.direct_data.data[i];
}
else
{
os << "--";
}
}
+ os.setf(flags);
}
- os.setf(flags);
return os;
+}
+
+uint64_t ValueRef::read_usize(size_t ofs) const
+{
+ uint64_t v = 0;
+ this->read_bytes(0, &v, POINTER_SIZE);
+ return v;
} \ No newline at end of file