diff options
author | John Hodge <tpg@mutabah.net> | 2018-03-04 21:20:00 +0800 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2018-03-17 18:52:16 +0800 |
commit | a8cd5861fdee9040a82654cc9d1fd41f98759d8b (patch) | |
tree | d5a05b794a422b4a3b25af874d6b155b9cf877d0 | |
parent | 5d78f1ba303a0e8196e62d4bd0c7708387164993 (diff) | |
download | mrust-a8cd5861fdee9040a82654cc9d1fd41f98759d8b.tar.gz |
Standalone MIRI - Filled with hacks, but advancing
-rw-r--r-- | tools/standalone_miri/debug.hpp | 19 | ||||
-rw-r--r-- | tools/standalone_miri/main.cpp | 166 | ||||
-rw-r--r-- | tools/standalone_miri/value.cpp | 37 | ||||
-rw-r--r-- | tools/standalone_miri/value.hpp | 15 |
4 files changed, 191 insertions, 46 deletions
diff --git a/tools/standalone_miri/debug.hpp b/tools/standalone_miri/debug.hpp index 342ea6fe..5afad96e 100644 --- a/tools/standalone_miri/debug.hpp +++ b/tools/standalone_miri/debug.hpp @@ -72,11 +72,26 @@ FunctionTrace<T,U> FunctionTrace_d(const char* fname, const char* file, unsigned return FunctionTrace<T,U>(fname, file, line, entry, exit); } +struct DebugExceptionTodo: + public ::std::exception +{ + const char* what() const { + return "TODO hit"; + } +}; +struct DebugExceptionError: + public ::std::exception +{ + const char* what() const { + return "error"; + } +}; + #define TRACE_FUNCTION_R(entry, exit) auto ftg##__LINE__ = FunctionTrace_d(__FUNCTION__,__FILE__,__LINE__,[&](DebugSink& FunctionTrace_ss){FunctionTrace_ss << entry;}, [&](DebugSink& FunctionTrace_ss) {FunctionTrace_ss << exit;} ) #define LOG_TRACE(strm) do { if(DebugSink::enabled(__FUNCTION__)) DebugSink::get(__FUNCTION__,__FILE__,__LINE__,DebugLevel::Trace) << strm; } while(0) #define LOG_DEBUG(strm) do { if(DebugSink::enabled(__FUNCTION__)) DebugSink::get(__FUNCTION__,__FILE__,__LINE__,DebugLevel::Debug) << strm; } while(0) -#define LOG_ERROR(strm) do { DebugSink::get(__FUNCTION__,__FILE__,__LINE__,DebugLevel::Error) << strm; exit(1); } while(0) +#define LOG_ERROR(strm) do { DebugSink::get(__FUNCTION__,__FILE__,__LINE__,DebugLevel::Error) << strm; throw DebugExceptionError{}; } while(0) #define LOG_FATAL(strm) do { DebugSink::get(__FUNCTION__,__FILE__,__LINE__,DebugLevel::Fatal) << strm; exit(1); } while(0) -#define LOG_TODO(strm) do { DebugSink::get(__FUNCTION__,__FILE__,__LINE__,DebugLevel::Bug) << "TODO: " << strm; abort(); } while(0) +#define LOG_TODO(strm) do { DebugSink::get(__FUNCTION__,__FILE__,__LINE__,DebugLevel::Bug) << "TODO: " << strm; throw DebugExceptionTodo{}; } while(0) #define LOG_BUG(strm) do { DebugSink::get(__FUNCTION__,__FILE__,__LINE__,DebugLevel::Bug) << "BUG: " << strm; abort(); } while(0) #define LOG_ASSERT(cnd,strm) do { if( !(cnd) ) { LOG_BUG("Assertion failure: " #cnd " - " << strm); } } while(0) diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index 3fc807c5..703a6fab 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -7,6 +7,10 @@ #include <algorithm> #include <iomanip> #include "debug.hpp" +#ifdef _WIN32 +# define NOMINMAX +# include <Windows.h> +#endif struct ProgramOptions { @@ -40,11 +44,24 @@ int main(int argc, const char* argv[]) val_argc.write_bytes(0, "\0\0\0", 4); val_argv.write_bytes(0, "\0\0\0\0\0\0\0", argv_ty.get_size()); - ::std::vector<Value> args; - args.push_back(::std::move(val_argc)); - args.push_back(::std::move(val_argv)); - auto rv = MIRI_Invoke( tree, tree.find_lang_item("start"), ::std::move(args) ); - ::std::cout << rv << ::std::endl; + try + { + ::std::vector<Value> args; + args.push_back(::std::move(val_argc)); + args.push_back(::std::move(val_argv)); + auto rv = MIRI_Invoke( tree, tree.find_lang_item("start"), ::std::move(args) ); + ::std::cout << rv << ::std::endl; + } + catch(const DebugExceptionTodo& /*e*/) + { + ::std::cerr << "TODO Hit" << ::std::endl; + return 1; + } + catch(const DebugExceptionError& /*e*/) + { + ::std::cerr << "Error encountered" << ::std::endl; + throw; + } return 0; } @@ -273,9 +290,20 @@ struct Ops { Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> args) { - TRACE_FUNCTION_R(path, ""); + Value ret; + TRACE_FUNCTION_R(path, path << " = " << ret); + + + // TODO: Support overriding certain functions + { + if( path == ::HIR::SimplePath { "std", { "sys", "imp", "c", "SetThreadStackGuarantee" } } ) + { + ret = Value(::HIR::TypeRef{RawType::I32}); + ret.write_i32(0, 120); // ERROR_CALL_NOT_IMPLEMENTED + return ret; + } + } - LOG_DEBUG(path); const auto& fcn = modtree.get_function(path); for(size_t i = 0; i < args.size(); i ++) { @@ -285,22 +313,25 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar if( fcn.external.link_name != "" ) { // External function! - return MIRI_Invoke_Extern(fcn.external.link_name, fcn.external.link_abi, ::std::move(args)); + ret = MIRI_Invoke_Extern(fcn.external.link_name, fcn.external.link_abi, ::std::move(args)); + return ret; } + ret = Value(fcn.ret_ty == RawType::Unreachable ? ::HIR::TypeRef() : fcn.ret_ty); + struct State { ModuleTree& modtree; const Function& fcn; - Value ret; + Value& ret; ::std::vector<Value> args; ::std::vector<Value> locals; ::std::vector<bool> drop_flags; - State(ModuleTree& modtree, const Function& fcn, ::std::vector<Value> args): + State(ModuleTree& modtree, const Function& fcn, Value& ret, ::std::vector<Value> args): modtree(modtree), fcn(fcn), - ret(fcn.ret_ty == RawType::Unreachable ? ::HIR::TypeRef() : fcn.ret_ty), + ret(ret), args(::std::move(args)), drop_flags(fcn.m_mir.drop_flags) { @@ -552,7 +583,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar } throw ""; } - } state { modtree, fcn, ::std::move(args) }; + } state { modtree, fcn, ret, ::std::move(args) }; size_t bb_idx = 0; for(;;) @@ -764,18 +795,75 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar // Can be an integer, or F32 (pointer is impossible atm) switch(src_ty.inner_type) { - case RawType::Unreachable: throw "BUG"; - case RawType::Composite: throw "ERROR"; - case RawType::TraitObject: throw "ERROR"; + case RawType::Unreachable: + LOG_BUG("Casting unreachable"); + case RawType::TraitObject: + case RawType::Str: + LOG_FATAL("Cast of unsized type - " << src_ty); case RawType::Function: LOG_ASSERT(re.type.inner_type == RawType::USize, ""); new_val = src_value.read_value(0, re.type.get_size()); break; - case RawType::Char: LOG_TODO("Cast char to integer (only u32)"); - case RawType::Str: throw "ERROR"; - case RawType::Unit: throw "ERROR"; - case RawType::Bool: throw "ERROR"; - case RawType::F64: throw "BUG"; + case RawType::Char: + LOG_TODO("Cast char to integer (only u32)"); + case RawType::Unit: + LOG_FATAL("Cast of unit"); + case RawType::Composite: { + const auto& dt = *src_ty.composite_type; + if( dt.variants.size() == 0 ) { + LOG_FATAL("Cast of composite - " << src_ty); + } + // TODO: Check that all variants have the same tag offset + LOG_ASSERT(dt.fields.size() == 1, ""); + LOG_ASSERT(dt.fields[0].first == 0, ""); + for(size_t i = 0; i < dt.variants.size(); i ++ ) { + LOG_ASSERT(dt.variants[i].base_field == 0, ""); + LOG_ASSERT(dt.variants[i].field_path.empty(), ""); + } + ::HIR::TypeRef tag_ty = dt.fields[0].second; + LOG_ASSERT(tag_ty.wrappers.empty(), ""); + switch(tag_ty.inner_type) + { + case RawType::USize: + dst_val = static_cast<uint64_t>( src_value.read_usize(0) ); + if(0) + case RawType::ISize: + dst_val = static_cast<uint64_t>( src_value.read_isize(0) ); + if(0) + case RawType::U8: + dst_val = static_cast<uint64_t>( src_value.read_u8 (0) ); + if(0) + case RawType::I8: + dst_val = static_cast<uint64_t>( src_value.read_i8 (0) ); + if(0) + case RawType::U16: + dst_val = static_cast<uint64_t>( src_value.read_u16(0) ); + if(0) + case RawType::I16: + dst_val = static_cast<uint64_t>( src_value.read_i16(0) ); + if(0) + case RawType::U32: + dst_val = static_cast<uint64_t>( src_value.read_u32(0) ); + if(0) + case RawType::I32: + dst_val = static_cast<uint64_t>( src_value.read_i32(0) ); + if(0) + case RawType::U64: + dst_val = static_cast<uint64_t>( src_value.read_u64(0) ); + if(0) + case RawType::I64: + dst_val = static_cast<uint64_t>( src_value.read_i64(0) ); + break; + default: + LOG_FATAL("Bad tag type in cast - " << tag_ty); + } + } if(0) + case RawType::Bool: + dst_val = static_cast<uint64_t>( src_value.read_u8 (0) ); + if(0) + case RawType::F64: + dst_val = static_cast<uint64_t>( src_value.read_f64(0) ); + if(0) case RawType::F32: dst_val = static_cast<uint64_t>( src_value.read_f32(0) ); if(0) @@ -889,21 +977,16 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar { switch(ty_l.inner_type) { - case RawType::U64: - res = res != 0 ? res : Ops::do_compare(v_l.read_u64(0), v_r.read_u64(0)); - break; - case RawType::U32: - res = res != 0 ? res : Ops::do_compare(v_l.read_u32(0), v_r.read_u32(0)); - break; - case RawType::U16: - res = res != 0 ? res : Ops::do_compare(v_l.read_u16(0), v_r.read_u16(0)); - break; - case RawType::U8: - res = res != 0 ? res : Ops::do_compare(v_l.read_u8(0), v_r.read_u8(0)); - break; - case RawType::USize: - res = res != 0 ? res : Ops::do_compare(v_l.read_usize(0), v_r.read_usize(0)); - break; + case RawType::U64: res = res != 0 ? res : Ops::do_compare(v_l.read_u64(0), v_r.read_u64(0)); break; + case RawType::U32: res = res != 0 ? res : Ops::do_compare(v_l.read_u32(0), v_r.read_u32(0)); break; + case RawType::U16: res = res != 0 ? res : Ops::do_compare(v_l.read_u16(0), v_r.read_u16(0)); break; + case RawType::U8 : res = res != 0 ? res : Ops::do_compare(v_l.read_u8 (0), v_r.read_u8 (0)); break; + case RawType::I64: res = res != 0 ? res : Ops::do_compare(v_l.read_i64(0), v_r.read_i64(0)); break; + case RawType::I32: res = res != 0 ? res : Ops::do_compare(v_l.read_i32(0), v_r.read_i32(0)); break; + case RawType::I16: res = res != 0 ? res : Ops::do_compare(v_l.read_i16(0), v_r.read_i16(0)); break; + case RawType::I8 : res = res != 0 ? res : Ops::do_compare(v_l.read_i8 (0), v_r.read_i8 (0)); break; + case RawType::USize: res = res != 0 ? res : Ops::do_compare(v_l.read_usize(0), v_r.read_usize(0)); break; + case RawType::ISize: res = res != 0 ? res : Ops::do_compare(v_l.read_isize(0), v_r.read_isize(0)); break; default: LOG_TODO("BinOp comparisons - " << se.src << " w/ " << ty_l); } @@ -1373,6 +1456,15 @@ Value MIRI_Invoke_Extern(const ::std::string& link_name, const ::std::string& ab rv.write_usize(0, 1); return rv; } +#ifdef _WIN32 + else if( link_name == "GetModuleHandleW" ) + { + const void* arg0 = (args.at(0).allocation ? args.at(0).allocation.alloc().data_ptr() : nullptr); + //extern void* GetModuleHandleW(const void* s); + + return Value::new_ffiptr(FFIPointer { "GetModuleHandleW", GetModuleHandleW(static_cast<LPCWSTR>(arg0)) }); + } +#endif // Allocators! else if( link_name == "__rust_allocate" ) { @@ -1596,8 +1688,8 @@ Value MIRI_Invoke_Intrinsic(const ModuleTree& modtree, const ::std::string& name case AllocationPtr::Ty::Function: LOG_FATAL("Attempt to copy* a function"); break; - case AllocationPtr::Ty::Unused2: - LOG_BUG("Unused tag"); + case AllocationPtr::Ty::FfiPointer: + LOG_BUG("Trying to copy from a FFI pointer"); break; } } diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp index 745e9b1b..168df328 100644 --- a/tools/standalone_miri/value.cpp +++ b/tools/standalone_miri/value.cpp @@ -31,6 +31,13 @@ AllocationPtr AllocationPtr::new_string(const ::std::string* ptr) rv.m_ptr = reinterpret_cast<void*>( reinterpret_cast<uintptr_t>(ptr) + static_cast<uintptr_t>(Ty::StdString) ); return rv; } +AllocationPtr AllocationPtr::new_ffi(FFIPointer info) +{ + AllocationPtr rv; + auto* ptr = new FFIPointer(info); + rv.m_ptr = reinterpret_cast<void*>( reinterpret_cast<uintptr_t>(ptr) + static_cast<uintptr_t>(Ty::FfiPointer) ); + return rv; +} AllocationPtr::AllocationPtr(const AllocationPtr& x): m_ptr(nullptr) { @@ -55,8 +62,12 @@ AllocationPtr::AllocationPtr(const AllocationPtr& x): // No ownership semantics, just clone the pointer m_ptr = x.m_ptr; break; - case Ty::Unused2: - throw "BUG"; + case Ty::FfiPointer: { + auto ptr_i = reinterpret_cast<uintptr_t>(new FFIPointer(x.ffi())); + assert( (ptr_i & 3) == 0 ); + m_ptr = reinterpret_cast<void*>( ptr_i + static_cast<uintptr_t>(Ty::FfiPointer) ); + assert(get_ty() == Ty::FfiPointer); + } break; } } else @@ -86,7 +97,9 @@ AllocationPtr::~AllocationPtr() case Ty::StdString: { // No ownership semantics } break; - case Ty::Unused2: { + case Ty::FfiPointer: { + auto* ptr = const_cast<FFIPointer*>(&ffi()); + delete ptr; } break; } } @@ -107,7 +120,8 @@ AllocationPtr::~AllocationPtr() case AllocationPtr::Ty::StdString: os << "\"" << x.str() << "\""; break; - case AllocationPtr::Ty::Unused2: + case AllocationPtr::Ty::FfiPointer: + os << "FFI " << x.ffi().source_function << " " << x.ffi().ptr_value; break; } } @@ -403,13 +417,24 @@ Value Value::new_fnptr(const ::HIR::Path& fn_path) rv.allocation.alloc().mask.at(0) = 0xFF; // TODO: Get pointer size and make that much valid instead of 8 bytes return rv; } +Value Value::new_ffiptr(FFIPointer ffi) +{ + Value rv( ::HIR::TypeRef(::HIR::CoreType { RawType::USize }) ); + rv.create_allocation(); + rv.allocation.alloc().relocations.push_back(Relocation { 0, AllocationPtr::new_ffi(ffi) }); + rv.allocation.alloc().data.at(0) = 0; + rv.allocation.alloc().mask.at(0) = 0xFF; // TODO: Get pointer size and make that much valid instead of 8 bytes + 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]; + if( this->direct_data.size > 0 ) + this->allocation.alloc().mask[0] = this->direct_data.mask[0]; + if( this->direct_data.size > 8 ) + 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 diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp index 03689215..ca15dea9 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -15,6 +15,12 @@ namespace HIR { class Allocation; struct Value; +struct FFIPointer +{ + const char* source_function; + void* ptr_value; +}; + class AllocationPtr { friend class Allocation; @@ -26,7 +32,7 @@ public: Allocation, Function, // m_ptr is a pointer to the function. StdString, - Unused2, + FfiPointer, }; private: @@ -44,6 +50,7 @@ public: static AllocationPtr new_fcn(::HIR::Path p); //static AllocationPtr new_rawdata(const void* buf, size_t len); static AllocationPtr new_string(const ::std::string* s); // NOTE: The string must have a stable pointer + static AllocationPtr new_ffi(FFIPointer info); AllocationPtr& operator=(const AllocationPtr& x) = delete; AllocationPtr& operator=(AllocationPtr&& x) { @@ -77,6 +84,11 @@ public: assert(get_ty() == Ty::StdString); return *static_cast<const ::std::string*>(get_ptr()); } + const FFIPointer& ffi() const { + assert(*this); + assert(get_ty() == Ty::FfiPointer); + return *static_cast<const FFIPointer*>(get_ptr()); + } Ty get_ty() const { return static_cast<Ty>( reinterpret_cast<uintptr_t>(m_ptr) & 3 ); @@ -172,6 +184,7 @@ struct Value Value(); Value(::HIR::TypeRef ty); static Value new_fnptr(const ::HIR::Path& fn_path); + static Value new_ffiptr(FFIPointer ffi); void create_allocation(); size_t size() const { return allocation ? allocation.alloc().size() : direct_data.size; } |