summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Hodge <tpg@mutabah.net>2018-03-04 21:20:00 +0800
committerJohn Hodge <tpg@mutabah.net>2018-03-17 18:52:16 +0800
commita8cd5861fdee9040a82654cc9d1fd41f98759d8b (patch)
treed5a05b794a422b4a3b25af874d6b155b9cf877d0
parent5d78f1ba303a0e8196e62d4bd0c7708387164993 (diff)
downloadmrust-a8cd5861fdee9040a82654cc9d1fd41f98759d8b.tar.gz
Standalone MIRI - Filled with hacks, but advancing
-rw-r--r--tools/standalone_miri/debug.hpp19
-rw-r--r--tools/standalone_miri/main.cpp166
-rw-r--r--tools/standalone_miri/value.cpp37
-rw-r--r--tools/standalone_miri/value.hpp15
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; }