summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Hodge <tpg@ucc.asn.au>2019-08-04 13:00:02 +0800
committerJohn Hodge <tpg@ucc.asn.au>2019-08-04 13:00:02 +0800
commit982826e4b309979bee8fe10f6ff537b4922e6316 (patch)
tree4be2ab029181b5d4e867f06078f489e8895abb17
parent4afb6ca5c167c8757bddf6dc44dd0f8bce7f8490 (diff)
downloadmrust-982826e4b309979bee8fe10f6ff537b4922e6316.tar.gz
Standalone MIRI - General improvements
-rw-r--r--tools/standalone_miri/miri.cpp96
-rw-r--r--tools/standalone_miri/value.cpp27
-rw-r--r--tools/standalone_miri/value.hpp6
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) )