diff options
-rw-r--r-- | tools/standalone_miri/hir_sim.cpp | 48 | ||||
-rw-r--r-- | tools/standalone_miri/hir_sim.hpp | 1 | ||||
-rw-r--r-- | tools/standalone_miri/main.cpp | 2 | ||||
-rw-r--r-- | tools/standalone_miri/miri.cpp | 123 | ||||
-rw-r--r-- | tools/standalone_miri/module_tree.cpp | 45 | ||||
-rw-r--r-- | tools/standalone_miri/module_tree.hpp | 11 | ||||
-rw-r--r-- | tools/standalone_miri/value.cpp | 1 | ||||
-rw-r--r-- | tools/standalone_miri/value.hpp | 37 |
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()) { |