Auto merge of #2493 - RalfJung:android, r=RalfJung
add very basic Android support This is just enough to print to stdout. I won't push this any further, but having these basics should hopefully make it easier for others to do so. Also slightly improve threading support on FreeBSD while we are at it. Partially based on https://github.com/rust-lang/miri/pull/2011. Fixes https://github.com/rust-lang/miri/issues/2010.
This commit is contained in:
commit
339500f060
3
ci.sh
3
ci.sh
@ -83,7 +83,8 @@ case $HOST_TARGET in
|
||||
MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests
|
||||
MIRI_TEST_TARGET=aarch64-apple-darwin run_tests
|
||||
MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests
|
||||
MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec data_race env/var
|
||||
MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple atomic data_race env/var
|
||||
MIRI_TEST_TARGET=aarch64-linux-android run_tests_minimal hello integer vec panic/panic
|
||||
MIRI_TEST_TARGET=thumbv7em-none-eabihf MIRI_NO_STD=1 run_tests_minimal no_std # no_std embedded architecture
|
||||
;;
|
||||
x86_64-apple-darwin)
|
||||
|
@ -1 +1 @@
|
||||
8556e6620e4866526b3cea767ad8c20ae877a569
|
||||
9c20b2a8cc7588decb6de25ac6a7912dcef24d65
|
||||
|
@ -954,5 +954,5 @@ pub fn get_local_crates(tcx: TyCtxt<'_>) -> Vec<CrateNum> {
|
||||
/// Helper function used inside the shims of foreign functions to check that
|
||||
/// `target_os` is a supported UNIX OS.
|
||||
pub fn target_os_is_unix(target_os: &str) -> bool {
|
||||
matches!(target_os, "linux" | "macos" | "freebsd")
|
||||
matches!(target_os, "linux" | "macos" | "freebsd" | "android")
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
clippy::derive_hash_xor_eq,
|
||||
clippy::too_many_arguments,
|
||||
clippy::type_complexity,
|
||||
clippy::single_element_loop,
|
||||
// We are not implementing queries here so it's fine
|
||||
rustc::potential_query_instability
|
||||
)]
|
||||
|
@ -232,13 +232,15 @@ pub struct PrimitiveLayouts<'tcx> {
|
||||
pub u32: TyAndLayout<'tcx>,
|
||||
pub usize: TyAndLayout<'tcx>,
|
||||
pub bool: TyAndLayout<'tcx>,
|
||||
pub mut_raw_ptr: TyAndLayout<'tcx>,
|
||||
pub mut_raw_ptr: TyAndLayout<'tcx>, // *mut ()
|
||||
pub const_raw_ptr: TyAndLayout<'tcx>, // *const ()
|
||||
}
|
||||
|
||||
impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> {
|
||||
fn new(layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Result<Self, LayoutError<'tcx>> {
|
||||
let tcx = layout_cx.tcx;
|
||||
let mut_raw_ptr = tcx.mk_ptr(TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Mut });
|
||||
let const_raw_ptr = tcx.mk_ptr(TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Not });
|
||||
Ok(Self {
|
||||
unit: layout_cx.layout_of(tcx.mk_unit())?,
|
||||
i8: layout_cx.layout_of(tcx.types.i8)?,
|
||||
@ -251,6 +253,7 @@ impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> {
|
||||
usize: layout_cx.layout_of(tcx.types.usize)?,
|
||||
bool: layout_cx.layout_of(tcx.types.bool)?,
|
||||
mut_raw_ptr: layout_cx.layout_of(mut_raw_ptr)?,
|
||||
const_raw_ptr: layout_cx.layout_of(const_raw_ptr)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -431,6 +434,17 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> {
|
||||
this.machine.extern_statics.try_insert(Symbol::intern(name), ptr).unwrap();
|
||||
}
|
||||
|
||||
fn alloc_extern_static(
|
||||
this: &mut MiriEvalContext<'mir, 'tcx>,
|
||||
name: &str,
|
||||
val: ImmTy<'tcx, Provenance>,
|
||||
) -> InterpResult<'tcx> {
|
||||
let place = this.allocate(val.layout, MiriMemoryKind::ExternStatic.into())?;
|
||||
this.write_immediate(*val, &place.into())?;
|
||||
Self::add_extern_static(this, name, place.ptr);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Sets up the "extern statics" for this machine.
|
||||
fn init_extern_statics(this: &mut MiriEvalContext<'mir, 'tcx>) -> InterpResult<'tcx> {
|
||||
match this.tcx.sess.target.os.as_ref() {
|
||||
@ -447,10 +461,8 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> {
|
||||
// syscall that we do support).
|
||||
for name in &["__cxa_thread_atexit_impl", "getrandom", "statx", "__clock_gettime64"]
|
||||
{
|
||||
let layout = this.machine.layouts.usize;
|
||||
let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?;
|
||||
this.write_scalar(Scalar::from_machine_usize(0, this), &place.into())?;
|
||||
Self::add_extern_static(this, name, place.ptr);
|
||||
let val = ImmTy::from_int(0, this.machine.layouts.usize);
|
||||
Self::alloc_extern_static(this, name, val)?;
|
||||
}
|
||||
}
|
||||
"freebsd" => {
|
||||
@ -461,13 +473,27 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> {
|
||||
this.machine.env_vars.environ.unwrap().ptr,
|
||||
);
|
||||
}
|
||||
"android" => {
|
||||
// "signal"
|
||||
let layout = this.machine.layouts.const_raw_ptr;
|
||||
let dlsym = Dlsym::from_str("signal".as_bytes(), &this.tcx.sess.target.os)?
|
||||
.expect("`signal` must be an actual dlsym on android");
|
||||
let ptr = this.create_fn_alloc_ptr(FnVal::Other(dlsym));
|
||||
let val = ImmTy::from_scalar(Scalar::from_pointer(ptr, this), layout);
|
||||
Self::alloc_extern_static(this, "signal", val)?;
|
||||
// A couple zero-initialized pointer-sized extern statics.
|
||||
// Most of them are for weak symbols, which we all set to null (indicating that the
|
||||
// symbol is not supported, and triggering fallback code.)
|
||||
for name in &["bsd_signal"] {
|
||||
let val = ImmTy::from_int(0, this.machine.layouts.usize);
|
||||
Self::alloc_extern_static(this, name, val)?;
|
||||
}
|
||||
}
|
||||
"windows" => {
|
||||
// "_tls_used"
|
||||
// This is some obscure hack that is part of the Windows TLS story. It's a `u8`.
|
||||
let layout = this.machine.layouts.u8;
|
||||
let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?;
|
||||
this.write_scalar(Scalar::from_u8(0), &place.into())?;
|
||||
Self::add_extern_static(this, "_tls_used", place.ptr);
|
||||
let val = ImmTy::from_int(0, this.machine.layouts.u8);
|
||||
Self::alloc_extern_static(this, "_tls_used", val)?;
|
||||
}
|
||||
_ => {} // No "extern statics" supported on this target
|
||||
}
|
||||
|
54
src/shims/unix/android/dlsym.rs
Normal file
54
src/shims/unix/android/dlsym.rs
Normal file
@ -0,0 +1,54 @@
|
||||
use rustc_middle::mir;
|
||||
|
||||
use crate::helpers::check_arg_count;
|
||||
use crate::*;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum Dlsym {
|
||||
signal,
|
||||
}
|
||||
|
||||
impl Dlsym {
|
||||
// Returns an error for unsupported symbols, and None if this symbol
|
||||
// should become a NULL pointer (pretend it does not exist).
|
||||
pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option<Dlsym>> {
|
||||
Ok(match name {
|
||||
"signal" => Some(Dlsym::signal),
|
||||
"android_set_abort_message" => None,
|
||||
_ => throw_unsup_format!("unsupported Android dlsym: {}", name),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
|
||||
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
|
||||
fn call_dlsym(
|
||||
&mut self,
|
||||
dlsym: Dlsym,
|
||||
args: &[OpTy<'tcx, Provenance>],
|
||||
dest: &PlaceTy<'tcx, Provenance>,
|
||||
ret: Option<mir::BasicBlock>,
|
||||
) -> InterpResult<'tcx> {
|
||||
let this = self.eval_context_mut();
|
||||
let ret = ret.expect("we don't support any diverging dlsym");
|
||||
assert!(this.tcx.sess.target.os == "android");
|
||||
|
||||
match dlsym {
|
||||
Dlsym::signal => {
|
||||
if !this.frame_in_std() {
|
||||
throw_unsup_format!(
|
||||
"`signal` support is crude and just enough for libstd to work"
|
||||
);
|
||||
}
|
||||
|
||||
let &[ref _sig, ref _func] = check_arg_count(args)?;
|
||||
this.write_null(dest)?;
|
||||
}
|
||||
}
|
||||
|
||||
log::trace!("{:?}", this.dump_place(**dest));
|
||||
this.go_to_block(ret);
|
||||
Ok(())
|
||||
}
|
||||
}
|
26
src/shims/unix/android/foreign_items.rs
Normal file
26
src/shims/unix/android/foreign_items.rs
Normal file
@ -0,0 +1,26 @@
|
||||
use rustc_span::Symbol;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
use crate::*;
|
||||
use shims::foreign_items::EmulateByNameResult;
|
||||
|
||||
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
|
||||
|
||||
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
|
||||
fn emulate_foreign_item_by_name(
|
||||
&mut self,
|
||||
link_name: Symbol,
|
||||
_abi: Abi,
|
||||
_args: &[OpTy<'tcx, Provenance>],
|
||||
_dest: &PlaceTy<'tcx, Provenance>,
|
||||
) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
|
||||
let _this = self.eval_context_mut();
|
||||
#[allow(clippy::match_single_binding)]
|
||||
match link_name.as_str() {
|
||||
_ => return Ok(EmulateByNameResult::NotSupported),
|
||||
}
|
||||
|
||||
#[allow(unreachable_code)]
|
||||
Ok(EmulateByNameResult::NeedsJumping)
|
||||
}
|
||||
}
|
2
src/shims/unix/android/mod.rs
Normal file
2
src/shims/unix/android/mod.rs
Normal file
@ -0,0 +1,2 @@
|
||||
pub mod dlsym;
|
||||
pub mod foreign_items;
|
@ -2,15 +2,17 @@ use rustc_middle::mir;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
use crate::*;
|
||||
use shims::unix::android::dlsym as android;
|
||||
use shims::unix::freebsd::dlsym as freebsd;
|
||||
use shims::unix::linux::dlsym as linux;
|
||||
use shims::unix::macos::dlsym as macos;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum Dlsym {
|
||||
Android(android::Dlsym),
|
||||
FreeBsd(freebsd::Dlsym),
|
||||
Linux(linux::Dlsym),
|
||||
MacOs(macos::Dlsym),
|
||||
FreeBsd(freebsd::Dlsym),
|
||||
}
|
||||
|
||||
impl Dlsym {
|
||||
@ -18,10 +20,11 @@ impl Dlsym {
|
||||
// should become a NULL pointer (pretend it does not exist).
|
||||
pub fn from_str<'tcx>(name: &str, target_os: &str) -> InterpResult<'tcx, Option<Dlsym>> {
|
||||
Ok(match target_os {
|
||||
"android" => android::Dlsym::from_str(name)?.map(Dlsym::Android),
|
||||
"freebsd" => freebsd::Dlsym::from_str(name)?.map(Dlsym::FreeBsd),
|
||||
"linux" => linux::Dlsym::from_str(name)?.map(Dlsym::Linux),
|
||||
"macos" => macos::Dlsym::from_str(name)?.map(Dlsym::MacOs),
|
||||
"freebsd" => freebsd::Dlsym::from_str(name)?.map(Dlsym::FreeBsd),
|
||||
_ => unreachable!(),
|
||||
_ => panic!("unsupported Unix OS {target_os}"),
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -41,10 +44,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
this.check_abi(abi, Abi::C { unwind: false })?;
|
||||
|
||||
match dlsym {
|
||||
Dlsym::Linux(dlsym) => linux::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret),
|
||||
Dlsym::MacOs(dlsym) => macos::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret),
|
||||
Dlsym::Android(dlsym) =>
|
||||
android::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret),
|
||||
Dlsym::FreeBsd(dlsym) =>
|
||||
freebsd::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret),
|
||||
Dlsym::Linux(dlsym) => linux::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret),
|
||||
Dlsym::MacOs(dlsym) => macos::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
#[rustfmt::skip]
|
||||
match link_name.as_str() {
|
||||
// Environment related shims
|
||||
"getenv" => {
|
||||
@ -588,11 +589,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
|
||||
// Platform-specific shims
|
||||
_ => {
|
||||
match this.tcx.sess.target.os.as_ref() {
|
||||
let target_os = &*this.tcx.sess.target.os;
|
||||
match target_os {
|
||||
"android" => return shims::unix::android::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
|
||||
"freebsd" => return shims::unix::freebsd::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
|
||||
"linux" => return shims::unix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
|
||||
"macos" => return shims::unix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
|
||||
"freebsd" => return shims::unix::freebsd::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest),
|
||||
_ => unreachable!(),
|
||||
_ => panic!("unsupported Unix OS {target_os}"),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -28,5 +28,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
assert!(this.tcx.sess.target.os == "freebsd");
|
||||
|
||||
match dlsym {}
|
||||
|
||||
//trace!("{:?}", this.dump_place(**dest));
|
||||
//this.go_to_block(ret);
|
||||
//Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ use rustc_target::spec::abi::Abi;
|
||||
|
||||
use crate::*;
|
||||
use shims::foreign_items::EmulateByNameResult;
|
||||
use shims::unix::thread::EvalContextExt as _;
|
||||
|
||||
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
|
||||
|
||||
@ -16,12 +17,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
|
||||
let this = self.eval_context_mut();
|
||||
match link_name.as_str() {
|
||||
// Linux's `pthread_getattr_np` equivalent
|
||||
// Threading
|
||||
"pthread_attr_get_np" if this.frame_in_std() => {
|
||||
let [_thread, _attr] =
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
this.write_null(dest)?;
|
||||
}
|
||||
"pthread_set_name_np" => {
|
||||
let [thread, name] =
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let res = this.pthread_setname_np(
|
||||
this.read_scalar(thread)?.check_init()?,
|
||||
this.read_scalar(name)?.check_init()?,
|
||||
)?;
|
||||
this.write_scalar(res, dest)?;
|
||||
}
|
||||
|
||||
// errno
|
||||
"__error" => {
|
||||
|
@ -32,5 +32,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
assert!(this.tcx.sess.target.os == "linux");
|
||||
|
||||
match dlsym {}
|
||||
|
||||
//trace!("{:?}", this.dump_place(**dest));
|
||||
//this.go_to_block(ret);
|
||||
//Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ mod fs;
|
||||
mod sync;
|
||||
mod thread;
|
||||
|
||||
mod android;
|
||||
mod freebsd;
|
||||
mod linux;
|
||||
mod macos;
|
||||
|
@ -45,7 +45,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
Dlsym::NtWriteFile => {
|
||||
if !this.frame_in_std() {
|
||||
throw_unsup_format!(
|
||||
"NtWriteFile support is crude and just enough for stdout to work"
|
||||
"`NtWriteFile` support is crude and just enough for stdout to work"
|
||||
);
|
||||
}
|
||||
|
||||
@ -68,7 +68,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
|
||||
if byte_offset != 0 {
|
||||
throw_unsup_format!(
|
||||
"NtWriteFile ByteOffset paremeter is non-null, which is unsupported"
|
||||
"`NtWriteFile` `ByteOffset` paremeter is non-null, which is unsupported"
|
||||
);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user