summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tools/standalone_miri/hir_sim.cpp48
-rw-r--r--tools/standalone_miri/hir_sim.hpp1
-rw-r--r--tools/standalone_miri/main.cpp2
-rw-r--r--tools/standalone_miri/miri.cpp123
-rw-r--r--tools/standalone_miri/module_tree.cpp45
-rw-r--r--tools/standalone_miri/module_tree.hpp11
-rw-r--r--tools/standalone_miri/value.cpp1
-rw-r--r--tools/standalone_miri/value.hpp37
8 files changed, 236 insertions, 32 deletions
diff --git a/tools/standalone_miri/hir_sim.cpp b/tools/standalone_miri/hir_sim.cpp
index 085c045f..a666dfee 100644
--- a/tools/standalone_miri/hir_sim.cpp
+++ b/tools/standalone_miri/hir_sim.cpp
@@ -77,6 +77,7 @@ size_t HIR::TypeRef::get_size(size_t ofs) const
return 0;
case RawType::Composite:
// NOTE: Don't care if the type has metadata
+ LOG_ASSERT(this->composite_type->populated, "Getting size of non-defined type - " << *this);
return this->composite_type->size;
case RawType::Unreachable:
LOG_BUG("Attempting to get size of an unreachable type, " << *this);
@@ -111,6 +112,53 @@ size_t HIR::TypeRef::get_size(size_t ofs) const
throw "";
}
}
+size_t HIR::TypeRef::get_align(size_t ofs) const
+{
+ if( const auto* w = this->get_wrapper(ofs) )
+ {
+ LOG_TODO("get_align " << *this);
+ }
+ else
+ {
+ switch(this->inner_type)
+ {
+ case RawType::Unit:
+ return 1;
+ case RawType::Composite:
+ // NOTE: Don't care if the type has metadata
+ LOG_ASSERT(this->composite_type->populated, "Getting alignment of non-defined type - " << *this);
+ return this->composite_type->alignment;
+ case RawType::TraitObject:
+ case RawType::Str:
+ return 1;
+ case RawType::U8: case RawType::I8:
+ return 1;
+ case RawType::U16: case RawType::I16:
+ return 2;
+ case RawType::U32: case RawType::I32:
+ return 4;
+ case RawType::U64: case RawType::I64:
+ return 8;
+ case RawType::U128: case RawType::I128:
+ return 16;
+
+ case RawType::Bool:
+ return 1;
+ case RawType::Char:
+ return 4;
+
+ case RawType::F32:
+ return 4;
+ case RawType::F64:
+ return 8;
+
+ case RawType::Function: // This should probably be invalid?
+ case RawType::USize:
+ case RawType::ISize:
+ return POINTER_SIZE;
+ }
+ }
+}
bool HIR::TypeRef::has_slice_meta(size_t& out_inner_size) const
{
if( const auto* w = this->get_wrapper() )
diff --git a/tools/standalone_miri/hir_sim.hpp b/tools/standalone_miri/hir_sim.hpp
index cedbf3b9..9483f1bb 100644
--- a/tools/standalone_miri/hir_sim.hpp
+++ b/tools/standalone_miri/hir_sim.hpp
@@ -128,6 +128,7 @@ namespace HIR {
}
size_t get_size(size_t ofs=0) const;
+ size_t get_align(size_t ofs=0) const;
// Returns true if this (unsized) type is a wrapper around a slice
// - Fills `out_inner_size` with the size of the slice element
diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp
index 4da6c7fc..8ee118f7 100644
--- a/tools/standalone_miri/main.cpp
+++ b/tools/standalone_miri/main.cpp
@@ -51,6 +51,7 @@ int main(int argc, const char* argv[])
try
{
tree.load_file(opts.infile);
+ tree.validate();
}
catch(const DebugExceptionTodo& /*e*/)
{
@@ -71,6 +72,7 @@ int main(int argc, const char* argv[])
return 1;
}
+
// Create argc/argv based on input arguments
auto argv_alloc = Allocation::new_alloc((1 + opts.args.size()) * POINTER_SIZE, "argv");
argv_alloc->write_usize(0 * POINTER_SIZE, Allocation::PTR_BASE);
diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp
index 2deb421b..906949b6 100644
--- a/tools/standalone_miri/miri.cpp
+++ b/tools/standalone_miri/miri.cpp
@@ -1487,11 +1487,15 @@ bool InterpreterThread::step_one(Value& out_thread_result)
alloc = RelocationPtr::new_alloc( v.m_value->allocation );
}
size_t ofs = v.m_offset;
- assert(ty.get_meta_type() == RawType::Unreachable);
+ //LOG_ASSERT(ty.get_meta_type() == RawType::Unreachable, "Dropping an unsized type with Statement::Drop - " << ty);
- auto ptr_ty = ty.wrapped(TypeWrapper::Ty::Borrow, 2);
+ auto ptr_ty = ty.wrapped(TypeWrapper::Ty::Borrow, /*BorrowTy::Unique*/2);
auto ptr_val = Value::new_pointer(ptr_ty, Allocation::PTR_BASE + ofs, ::std::move(alloc));
+ if( v.m_metadata )
+ {
+ ptr_val.write_value(POINTER_SIZE, *v.m_metadata);
+ }
if( !drop_value(ptr_val, ty, /*shallow=*/se.kind == ::MIR::eDropKind::SHALLOW) )
{
@@ -1805,8 +1809,17 @@ bool InterpreterThread::call_path(Value& ret, const ::HIR::Path& path, ::std::ve
if( fcn.external.link_name != "" )
{
- // External function!
- return this->call_extern(ret, fcn.external.link_name, fcn.external.link_abi, ::std::move(args));
+ // TODO: Search for a function with both code and this link name
+ if(const auto* ext_fcn = m_modtree.get_ext_function(fcn.external.link_name.c_str()))
+ {
+ this->m_stack.push_back(StackFrame(*ext_fcn, ::std::move(args)));
+ return false;
+ }
+ else
+ {
+ // External function!
+ return this->call_extern(ret, fcn.external.link_name, fcn.external.link_abi, ::std::move(args));
+ }
}
this->m_stack.push_back(StackFrame(fcn, ::std::move(args)));
@@ -1932,6 +1945,10 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c
return false;
}
}
+ else if( link_name == "panic_impl" )
+ {
+ LOG_TODO("panic_impl");
+ }
else if( link_name == "__rust_start_panic" )
{
LOG_TODO("__rust_start_panic");
@@ -2121,6 +2138,22 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c
{
rv = Value::new_i32(0);
}
+ else if( link_name == "pthread_attr_setstacksize" )
+ {
+ // Lie and return succeess
+ rv = Value::new_i32(0);
+ }
+ else if( link_name == "pthread_create" )
+ {
+ auto thread_handle_out = args.at(0).read_pointer_valref_mut(0, sizeof(pthread_t));
+ auto attrs = args.at(1).read_pointer_const(0, sizeof(pthread_attr_t));
+ auto fcn_path = args.at(2).get_relocation(0).fcn();
+ LOG_ASSERT(args.at(2).read_usize(0) == Allocation::PTR_BASE, "");
+ auto arg = args.at(3);
+ LOG_NOTICE("TODO: pthread_create(" << thread_handle_out << ", " << attrs << ", " << fcn_path << ", " << arg << ")");
+ // TODO: Create a new interpreter context with this thread, use co-operative scheduling
+ rv = Value::new_i32(EPERM);
+ }
else if( link_name == "pthread_cond_init" || link_name == "pthread_cond_destroy" )
{
rv = Value::new_i32(0);
@@ -2230,6 +2263,15 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c
errno = ENOSYS;
rv = Value::new_i64(-1);
}
+ else if( link_name == "dlsym" )
+ {
+ auto handle = args.at(0).read_usize(0);
+ const char* name = FfiHelpers::read_cstr(args.at(1), 0);
+
+ LOG_DEBUG("dlsym(0x" << ::std::hex << handle << ", '" << name << "')");
+ LOG_NOTICE("dlsym stubbed to zero");
+ rv = Value::new_usize(0);
+ }
#endif
// std C
else if( link_name == "signal" )
@@ -2347,6 +2389,21 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const ::
rv = Value::with_size(POINTER_SIZE, false);
rv.write_usize(0, it - type_ids.begin());
}
+ else if( name == "type_name" )
+ {
+ const auto& ty_T = ty_params.tys.at(0);
+
+ static ::std::map<HIR::TypeRef, ::std::string> s_type_names;
+ auto it = s_type_names.find(ty_T);
+ if( it == s_type_names.end() )
+ {
+ it = s_type_names.insert( ::std::make_pair(ty_T, FMT_STRING(ty_T)) ).first;
+ }
+
+ rv = Value::with_size(2*POINTER_SIZE, /*needs_alloc=*/true);
+ rv.write_ptr(0*POINTER_SIZE, Allocation::PTR_BASE, RelocationPtr::new_string(&it->second));
+ rv.write_usize(1*POINTER_SIZE, 0);
+ }
else if( name == "discriminant_value" )
{
const auto& ty = ty_params.tys.at(0);
@@ -2582,7 +2639,12 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const ::
}
else if( ity->inner_type == RawType::TraitObject )
{
- LOG_TODO("size_of_val - Trait Object - " << ty);
+ auto vtable_ty = meta_ty.get_inner();
+ LOG_DEBUG("> vtable_ty = " << vtable_ty << " (size= " << vtable_ty.get_size() << ")");
+ auto vtable = val.deref(POINTER_SIZE, vtable_ty);
+ LOG_DEBUG("> vtable = " << vtable);
+ auto size = vtable.read_usize(1*POINTER_SIZE);
+ flex_size = size;
}
else
{
@@ -2596,6 +2658,40 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const ::
rv.write_usize(0, ty.get_size());
}
}
+ else if( name == "min_align_of_val" )
+ {
+ /*const*/ auto& val = args.at(0);
+ const auto& ty = ty_params.tys.at(0);
+ rv = Value(::HIR::TypeRef(RawType::USize));
+ size_t fixed_size = 0; // unused
+ size_t flex_align = 0;
+ if( const auto* ity = ty.get_unsized_type(fixed_size) )
+ {
+ if( const auto* w = ity->get_wrapper() )
+ {
+ LOG_ASSERT(w->type == TypeWrapper::Ty::Slice, "align_of_val on wrapped type that isn't a slice - " << *ity);
+ flex_align = ity->get_inner().get_align();
+ }
+ else if( ity->inner_type == RawType::Str )
+ {
+ flex_align = 1;
+ }
+ else if( ity->inner_type == RawType::TraitObject )
+ {
+ const auto meta_ty = ty.get_meta_type();
+ auto vtable_ty = meta_ty.get_inner();
+ LOG_DEBUG("> vtable_ty = " << vtable_ty << " (size= " << vtable_ty.get_size() << ")");
+ auto vtable = val.deref(POINTER_SIZE, vtable_ty);
+ LOG_DEBUG("> vtable = " << vtable);
+ flex_align = vtable.read_usize(2*POINTER_SIZE);
+ }
+ else
+ {
+ LOG_BUG("Inner unsized type unknown - " << *ity);
+ }
+ }
+ rv.write_usize(0, ::std::max( ty.get_align(), flex_align ));
+ }
else if( name == "drop_in_place" )
{
auto& val = args.at(0);
@@ -2739,6 +2835,7 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const ::
// TODO: Use a ValueRef instead?
bool InterpreterThread::drop_value(Value ptr, const ::HIR::TypeRef& ty, bool is_shallow/*=false*/)
{
+ TRACE_FUNCTION_R(ptr << ": " << ty << (is_shallow ? " (shallow)" : ""), "");
// TODO: After the drop is done, flag the backing allocation for `ptr` as freed
if( is_shallow )
{
@@ -2836,7 +2933,21 @@ bool InterpreterThread::drop_value(Value ptr, const ::HIR::TypeRef& ty, bool is_
}
else if( ty.inner_type == RawType::TraitObject )
{
- LOG_TODO("Drop - " << ty << " - trait object");
+ // Get the drop glue from the vtable (first entry)
+ auto inner_ptr = ptr.read_value(0, POINTER_SIZE);
+ auto vtable = ptr.deref(POINTER_SIZE, ty.get_meta_type().get_inner());
+ auto drop_r = vtable.get_relocation(0);
+ if( drop_r )
+ {
+ LOG_ASSERT(drop_r.get_ty() == RelocationPtr::Ty::Function, "");
+ auto fcn = drop_r.fcn();
+ static Value tmp;
+ return this->call_path(tmp, fcn, { ::std::move(inner_ptr) });
+ }
+ else
+ {
+ // None
+ }
}
else
{
diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp
index 29b822de..7fab4d88 100644
--- a/tools/standalone_miri/module_tree.cpp
+++ b/tools/standalone_miri/module_tree.cpp
@@ -57,6 +57,24 @@ void ModuleTree::load_file(const ::std::string& path)
// Keep going!
}
}
+void ModuleTree::validate()
+{
+ TRACE_FUNCTION_R("", "");
+ for(const auto& dt : this->data_types)
+ {
+ //LOG_ASSERT(dt.second->populated, "Type " << dt.first << " never defined");
+ }
+
+ for(const auto& fcn : this->functions)
+ {
+ // TODO: This doesn't actually happen yet (this combination can't be parsed)
+ if( fcn.second.external.link_name != "" && !fcn.second.m_mir.blocks.empty() )
+ {
+ LOG_DEBUG(fcn.first << " = '" << fcn.second.external.link_name << "'");
+ ext_functions.insert(::std::make_pair( fcn.second.external.link_name, &fcn.second ));
+ }
+ }
+}
// Parse a single item from a .mir file
bool Parser::parse_one()
{
@@ -185,6 +203,7 @@ bool Parser::parse_one()
//LOG_TRACE("type " << p);
auto rv = DataType {};
+ rv.populated = true;
rv.my_path = p;
lex.check_consume('{');
@@ -1259,15 +1278,29 @@ RawType Parser::parse_core_type()
}
lex.consume_if(')');
+ // Ignore marker traits.
+
auto rv = ::HIR::TypeRef(RawType::TraitObject);
if( base_trait != ::HIR::GenericPath() )
{
// Generate vtable path
auto vtable_path = base_trait;
vtable_path.m_simplepath.ents.back() += "#vtable";
- // - TODO: Associated types?
+ if( atys.size() > 1 )
+ {
+ LOG_TODO("Handle multiple ATYs in vtable path");
+ }
+ else if( atys.size() == 1 )
+ {
+ vtable_path.m_params.tys.push_back( ::std::move(atys[0].second) );
+ }
+ // - TODO: Associated types? (Need to ensure ordering is correct)
rv.composite_type = this->get_composite( ::std::move(vtable_path) );
}
+ else
+ {
+ // TODO: vtable for empty trait?
+ }
return rv;
}
else if( lex.next() == TokenClass::Ident )
@@ -1286,6 +1319,7 @@ const DataType* Parser::get_composite(::HIR::GenericPath gp)
{
// TODO: Later on need to check if the type is valid.
auto v = ::std::make_unique<DataType>(DataType {});
+ v->populated = false;
v->my_path = gp;
auto ir = tree.data_types.insert(::std::make_pair( ::std::move(gp), ::std::move(v)) );
it = ir.first;
@@ -1315,6 +1349,15 @@ const Function* ModuleTree::get_function_opt(const ::HIR::Path& p) const
}
return &it->second;
}
+const Function* ModuleTree::get_ext_function(const char* name) const
+{
+ auto it = ext_functions.find(name);
+ if( it == ext_functions.end() )
+ {
+ return nullptr;
+ }
+ return it->second;
+}
Static& ModuleTree::get_static(const ::HIR::Path& p)
{
auto it = statics.find(p);
diff --git a/tools/standalone_miri/module_tree.hpp b/tools/standalone_miri/module_tree.hpp
index 653104df..6637c2d4 100644
--- a/tools/standalone_miri/module_tree.hpp
+++ b/tools/standalone_miri/module_tree.hpp
@@ -48,14 +48,18 @@ class ModuleTree
// Hack: Tuples are stored as `::""::<A,B,C,...>`
::std::map<::HIR::GenericPath, ::std::unique_ptr<DataType>> data_types;
+
+ ::std::map<::std::string, const Function*> ext_functions;
public:
ModuleTree();
void load_file(const ::std::string& path);
+ void validate();
::HIR::SimplePath find_lang_item(const char* name) const;
const Function& get_function(const ::HIR::Path& p) const;
const Function* get_function_opt(const ::HIR::Path& p) const;
+ const Function* get_ext_function(const char* name) const;
Static& get_static(const ::HIR::Path& p);
Static* get_static_opt(const ::HIR::Path& p);
@@ -67,16 +71,15 @@ public:
// struct/union/enum
struct DataType
{
+ bool populated;
::HIR::GenericPath my_path;
- // TODO: Store the name of this type for logging?
-
- // TODO: Metadata type! (indicates an unsized wrapper)
- // TODO: Drop glue
size_t alignment;
size_t size;
+ // Drop glue
::HIR::Path drop_glue;
+ // Metadata type! (indicates an unsized wrapper)
::HIR::TypeRef dst_meta;
// Offset and datatype
diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp
index 319f516b..16842d82 100644
--- a/tools/standalone_miri/value.cpp
+++ b/tools/standalone_miri/value.cpp
@@ -299,6 +299,7 @@ ValueRef ValueCommonRead::read_pointer_valref_mut(size_t rd_ofs, size_t size)
LOG_ASSERT(ofs >= Allocation::PTR_BASE, "Invalid pointer read");
ofs -= Allocation::PTR_BASE;
auto reloc = get_relocation(rd_ofs);
+ LOG_DEBUG("ValueCommonRead::read_pointer_valref_mut(" << ofs << "+" << size << ", reloc=" << reloc << ")");
if( !reloc )
{
LOG_ERROR("Getting ValRef to null pointer (no relocation)");
diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp
index f4ac2d36..1ba3382e 100644
--- a/tools/standalone_miri/value.hpp
+++ b/tools/standalone_miri/value.hpp
@@ -363,42 +363,41 @@ struct ValueRef:
size_t m_size; // Size in bytes of the referenced value
::std::shared_ptr<Value> m_metadata;
+ static bool in_bounds(size_t ofs, size_t size, size_t max_size) {
+ if( size == 0 ) {
+ return ofs <= max_size;
+ }
+ if( ofs > 0 && !(ofs < max_size) )
+ return false;
+ if( !(size <= max_size) )
+ return false;
+ return ofs + size <= max_size;
+ }
+
ValueRef(RelocationPtr ptr, size_t ofs, size_t size):
m_alloc(ptr),
m_value(nullptr),
m_offset(ofs),
m_size(size)
{
- struct H {
- static bool in_bounds(size_t ofs, size_t size, size_t max_size) {
- if( size == 0 ) {
- return ofs <= max_size;
- }
- if( ofs > 0 && !(ofs < max_size) )
- return false;
- if( !(size <= max_size) )
- return false;
- return ofs + size <= max_size;
- }
- };
if( m_alloc )
{
switch(m_alloc.get_ty())
{
case RelocationPtr::Ty::Allocation:
- if( !H::in_bounds(ofs, size, m_alloc.alloc().size()) )
+ if( !in_bounds(ofs, size, m_alloc.alloc().size()) )
{
LOG_ERROR("ValueRef exceeds bounds of " << m_alloc << " - " << ofs << "+" << size << " > " << m_alloc.alloc().size());
}
break;
case RelocationPtr::Ty::StdString:
- if( !H::in_bounds(ofs, size, m_alloc.str().size()) )
+ if( !in_bounds(ofs, size, m_alloc.str().size()) )
{
LOG_ERROR("ValueRef exceeds bounds of string - " << ofs << "+" << size << " > " << m_alloc.str().size());
}
break;
case RelocationPtr::Ty::FfiPointer:
- if( !H::in_bounds(ofs, size, m_alloc.ffi().get_size()) )
+ if( !in_bounds(ofs, size, m_alloc.ffi().get_size()) )
{
LOG_ERROR("ValueRef exceeds bounds of FFI buffer - " << ofs << "+" << size << " > " << m_alloc.ffi().get_size());
}
@@ -482,9 +481,7 @@ struct ValueRef:
void read_bytes(size_t ofs, void* dst, size_t size) const {
if( size == 0 )
return ;
- assert(ofs < m_size);
- assert(size <= m_size);
- assert(ofs+size <= m_size);
+ LOG_ASSERT(in_bounds(ofs, size, m_size), "read_bytes(" << ofs << "+" << size << " > " << m_size <<")");
if( m_alloc ) {
switch(m_alloc.get_ty())
{
@@ -507,9 +504,7 @@ struct ValueRef:
void check_bytes_valid(size_t ofs, size_t size) const {
if( size == 0 )
return ;
- assert(ofs < m_size);
- assert(size <= m_size);
- assert(ofs+size <= m_size);
+ LOG_ASSERT(in_bounds(ofs, size, m_size), "check_bytes_valid(" << ofs << "+" << size << " > " << m_size <<")");
if( m_alloc ) {
switch(m_alloc.get_ty())
{