diff options
author | John Hodge <tpg@ucc.asn.au> | 2019-08-04 13:00:02 +0800 |
---|---|---|
committer | John Hodge <tpg@ucc.asn.au> | 2019-08-04 13:00:02 +0800 |
commit | 982826e4b309979bee8fe10f6ff537b4922e6316 (patch) | |
tree | 4be2ab029181b5d4e867f06078f489e8895abb17 | |
parent | 4afb6ca5c167c8757bddf6dc44dd0f8bce7f8490 (diff) | |
download | mrust-982826e4b309979bee8fe10f6ff537b4922e6316.tar.gz |
Standalone MIRI - General improvements
-rw-r--r-- | tools/standalone_miri/miri.cpp | 96 | ||||
-rw-r--r-- | tools/standalone_miri/value.cpp | 27 | ||||
-rw-r--r-- | tools/standalone_miri/value.hpp | 6 |
3 files changed, 121 insertions, 8 deletions
diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index 2131ffe6..674c7e6d 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -516,7 +516,12 @@ struct MirHelpers LOG_BUG("Constant::Const in mmir"); } break; TU_ARM(c, Bytes, ce) { - LOG_TODO("Constant::Bytes"); + ty = ::HIR::TypeRef(RawType::U8).wrap(TypeWrapper::Ty::Slice, 0).wrap(TypeWrapper::Ty::Borrow, 0); + Value val = Value(ty); + val.write_ptr(0, 0, RelocationPtr::new_ffi(FFIPointer::new_const_bytes(ce.data(), ce.size()))); + val.write_usize(POINTER_SIZE, ce.size()); + LOG_DEBUG(c << " = " << val); + return val; } break; TU_ARM(c, StaticString, ce) { ty = ::HIR::TypeRef(RawType::Str).wrap(TypeWrapper::Ty::Borrow, 0); @@ -1104,7 +1109,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) case ::MIR::eBinOp::BIT_SHR: { LOG_ASSERT(ty_l.get_wrapper() == nullptr, "Bitwise operator on non-primitive - " << ty_l); LOG_ASSERT(ty_r.get_wrapper() == nullptr, "Bitwise operator with non-primitive - " << ty_r); - size_t max_bits = ty_r.get_size() * 8; + size_t max_bits = ty_l.get_size() * 8; uint8_t shift; auto check_cast_u = [&](auto v){ LOG_ASSERT(0 <= v && v <= max_bits, "Shift out of range - " << v); return static_cast<uint8_t>(v); }; auto check_cast_s = [&](auto v){ LOG_ASSERT(v <= static_cast<int64_t>(max_bits), "Shift out of range - " << v); return static_cast<uint8_t>(v); }; @@ -1121,7 +1126,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) case RawType::USize: shift = check_cast_u(v_r.read_usize(0)); break; case RawType::ISize: shift = check_cast_s(v_r.read_isize(0)); break; default: - LOG_TODO("BinOp shift rhs unknown type - " << se.src << " w/ " << ty_r); + LOG_TODO("BinOp shift RHS unknown type - " << se.src << " w/ " << ty_r); } new_val = Value(ty_l); switch(ty_l.inner_type) @@ -1132,9 +1137,11 @@ bool InterpreterThread::step_one(Value& out_thread_result) case RawType::U16: new_val.write_u16(0, Ops::do_bitwise(v_l.read_u16(0), static_cast<uint16_t>(shift), re.op)); break; case RawType::U8 : new_val.write_u8 (0, Ops::do_bitwise(v_l.read_u8 (0), static_cast<uint8_t >(shift), re.op)); break; case RawType::USize: new_val.write_usize(0, Ops::do_bitwise(v_l.read_usize(0), static_cast<uint64_t>(shift), re.op)); break; - // TODO: Is signed allowed? + // Is signed allowed? (yes) + // - What's the exact semantics? For now assuming it's unsigned+reinterpret + case RawType::ISize: new_val.write_usize(0, Ops::do_bitwise(v_l.read_usize(0), static_cast<uint64_t>(shift), re.op)); break; default: - LOG_TODO("BinOp shift rhs unknown type - " << se.src << " w/ " << ty_r); + LOG_TODO("BinOp shift LHS unknown type - " << se.src << " w/ " << ty_l); } } break; case ::MIR::eBinOp::BIT_AND: @@ -1170,16 +1177,45 @@ bool InterpreterThread::step_one(Value& out_thread_result) default: LOG_TODO("BinOp bitwise - " << se.src << " w/ " << ty_l); } + // If the LHS had a relocation, propagate it over + if( auto r = v_l.get_relocation(0) ) + { + LOG_DEBUG("- Restore relocation " << r); + new_val.create_allocation(); + new_val.allocation->set_reloc(0, ::std::min(POINTER_SIZE, new_val.size()), r); + } break; default: LOG_ASSERT(ty_l == ty_r, "BinOp type mismatch - " << ty_l << " != " << ty_r); auto val_l = PrimitiveValueVirt::from_value(ty_l, v_l); auto val_r = PrimitiveValueVirt::from_value(ty_r, v_r); + RelocationPtr new_val_reloc; switch(re.op) { - case ::MIR::eBinOp::ADD: val_l.get().add( val_r.get() ); break; - case ::MIR::eBinOp::SUB: val_l.get().subtract( val_r.get() ); break; + case ::MIR::eBinOp::ADD: + LOG_ASSERT(!v_r.get_relocation(0), "RHS of `+` has a relocation"); + new_val_reloc = v_l.get_relocation(0); + val_l.get().add( val_r.get() ); + break; + case ::MIR::eBinOp::SUB: + if( auto r = v_l.get_relocation(0) ) + { + if( v_r.get_relocation(0) ) + { + // Pointer difference, no relocation in output + } + else + { + new_val_reloc = ::std::move(r); + } + } + else + { + LOG_ASSERT(!v_r.get_relocation(0), "RHS of `-` has a relocation but LHS does not"); + } + val_l.get().subtract( val_r.get() ); + break; case ::MIR::eBinOp::MUL: val_l.get().multiply( val_r.get() ); break; case ::MIR::eBinOp::DIV: val_l.get().divide( val_r.get() ); break; case ::MIR::eBinOp::MOD: val_l.get().modulo( val_r.get() ); break; @@ -1189,6 +1225,11 @@ bool InterpreterThread::step_one(Value& out_thread_result) } new_val = Value(ty_l); val_l.get().write_to_value(new_val, 0); + if( new_val_reloc ) + { + new_val.create_allocation(); + new_val.allocation->set_reloc(0, ::std::min(POINTER_SIZE, new_val.size()), ::std::move(new_val_reloc)); + } break; } } break; @@ -2011,6 +2052,11 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c { rv = Value::new_i32(0); } + else if( link_name == "pthread_rwlock_unlock" ) + { + // TODO: Check that this thread holds the lock? + rv = Value::new_i32(0); + } else if( link_name == "pthread_mutexattr_init" || link_name == "pthread_mutexattr_settype" || link_name == "pthread_mutexattr_destroy" ) { rv = Value::new_i32(0); @@ -2062,6 +2108,20 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c { rv = Value::new_i32(0); } + // - Time + else if( link_name == "clock_gettime" ) + { + // int clock_gettime(clockid_t clk_id, struct timespec *tp); + auto clk_id = args.at(0).read_u32(0); + auto tp_vr = args.at(1).read_pointer_valref_mut(0, sizeof(struct timespec)); + + LOG_DEBUG("clock_gettime(" << clk_id << ", " << tp_vr); + int rv_i = clock_gettime(clk_id, reinterpret_cast<struct timespec*>(tp_vr.data_ptr_mut())); + if(rv_i == 0) + tp_vr.mark_bytes_valid(0, tp_vr.m_size); + LOG_DEBUG("= " << rv_i << " (" << tp_vr << ")"); + rv = Value::new_i32(rv_i); + } // - Linux extensions else if( link_name == "open64" ) { @@ -2097,6 +2157,14 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c { rv = Value::new_ffiptr(FFIPointer::new_const_bytes(&errno, sizeof(errno))); } + else if( link_name == "syscall" ) + { + auto num = args.at(0).read_u32(0); + + LOG_DEBUG("syscall(" << num << ", ...) - hack return ENOSYS"); + errno = ENOSYS; + rv = Value::new_i64(-1); + } #endif // std C else if( link_name == "signal" ) @@ -2411,6 +2479,20 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const :: rv = Value(ty_params.tys.at(0)); rv.mark_bytes_valid(0, rv.size()); } + else if( name == "write_bytes" ) + { + auto& dst_ptr_v = args.at(0); + auto byte = args.at(1).read_u8(0); + auto count = args.at(2).read_usize(0); + + LOG_DEBUG("'write_bytes'(" << dst_ptr_v << ", " << byte << ", " << count << ")"); + + if( count > 0 ) + { + auto dst_vr = dst_ptr_v.read_pointer_valref_mut(0, count); + memset(dst_vr.data_ptr_mut(), byte, count); + } + } // - Unsized stuff else if( name == "size_of_val" ) { diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp index 01f0fbbc..232613b7 100644 --- a/tools/standalone_miri/value.cpp +++ b/tools/standalone_miri/value.cpp @@ -540,7 +540,27 @@ void Allocation::write_bytes(size_t ofs, const void* src, size_t count) void Allocation::write_ptr(size_t ofs, size_t ptr_ofs, RelocationPtr reloc) { this->write_usize(ofs, ptr_ofs); - this->relocations.push_back(Relocation { ofs, /*POINTER_SIZE,*/ ::std::move(reloc) }); + this->set_reloc(ofs, POINTER_SIZE, ::std::move(reloc)); +} +void Allocation::set_reloc(size_t ofs, size_t len, RelocationPtr reloc) +{ + LOG_ASSERT(ofs % POINTER_SIZE == 0, ""); + LOG_ASSERT(len == POINTER_SIZE, ""); + // Delete any existing relocation at this position + for(auto it = this->relocations.begin(); it != this->relocations.end();) + { + if( ofs <= it->slot_ofs && it->slot_ofs < ofs + len ) + { + // Slot starts in this updated region + // - TODO: Split in half? + it = this->relocations.erase(it); + continue ; + } + // TODO: What if the slot ends in the new region? + // What if the new region is in the middle of the slot + ++ it; + } + this->relocations.push_back(Relocation { ofs, /*len,*/ ::std::move(reloc) }); } ::std::ostream& operator<<(::std::ostream& os, const Allocation& x) { @@ -664,6 +684,11 @@ Value Value::new_i32(int32_t v) { rv.write_i32(0, v); return rv; } +Value Value::new_i64(int64_t v) { + auto rv = Value( ::HIR::TypeRef(RawType::I64) ); + rv.write_i64(0, v); + return rv; +} void Value::create_allocation() { diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp index ebae2699..19df8540 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -289,6 +289,8 @@ public: void write_value(size_t ofs, Value v); void write_bytes(size_t ofs, const void* src, size_t count) override; void write_ptr(size_t ofs, size_t ptr_ofs, RelocationPtr reloc) override; + + void set_reloc(size_t ofs, size_t len, RelocationPtr reloc); }; extern ::std::ostream& operator<<(::std::ostream& os, const Allocation& x); @@ -320,6 +322,7 @@ struct Value: static Value new_isize(int64_t v); static Value new_u32(uint32_t v); static Value new_i32(int32_t v); + static Value new_i64(int64_t v); void create_allocation(); size_t size() const { return allocation ? allocation->size() : direct_data.size; } @@ -365,6 +368,9 @@ struct ValueRef: { 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) ) |