From a05a8eb805166dcc5408175f16c46303b76c871d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Aug 2022 08:15:41 -0400 Subject: [PATCH] add very basic Android support --- ci.sh | 1 + rust-version | 2 +- src/helpers.rs | 2 +- src/machine.rs | 44 +++++++++++++++----- src/shims/unix/android/dlsym.rs | 53 +++++++++++++++++++++++++ src/shims/unix/android/foreign_items.rs | 23 +++++++++++ src/shims/unix/android/mod.rs | 2 + src/shims/unix/dlsym.rs | 15 ++++--- src/shims/unix/foreign_items.rs | 9 +++-- src/shims/unix/freebsd/dlsym.rs | 4 ++ src/shims/unix/linux/dlsym.rs | 4 ++ src/shims/unix/mod.rs | 1 + src/shims/windows/dlsym.rs | 4 +- 13 files changed, 143 insertions(+), 21 deletions(-) create mode 100644 src/shims/unix/android/dlsym.rs create mode 100644 src/shims/unix/android/foreign_items.rs create mode 100644 src/shims/unix/android/mod.rs diff --git a/ci.sh b/ci.sh index 51cec8fe161..d1a8db183d1 100755 --- a/ci.sh +++ b/ci.sh @@ -84,6 +84,7 @@ case $HOST_TARGET in 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=aarch64-linux-android run_tests_minimal hello integer vec MIRI_TEST_TARGET=thumbv7em-none-eabihf MIRI_NO_STD=1 run_tests_minimal no_std # no_std embedded architecture ;; x86_64-apple-darwin) diff --git a/rust-version b/rust-version index 7317986eaea..45dbb37c86a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8556e6620e4866526b3cea767ad8c20ae877a569 +9c20b2a8cc7588decb6de25ac6a7912dcef24d65 diff --git a/src/helpers.rs b/src/helpers.rs index 7c9f8740eb4..d63bf97ad51 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -954,5 +954,5 @@ pub fn get_local_crates(tcx: TyCtxt<'_>) -> Vec { /// 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") } diff --git a/src/machine.rs b/src/machine.rs index 4ebf7dceab8..d45f5de381f 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -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> { 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 @@ fn new(layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Result, + 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 @@ fn init_extern_statics(this: &mut MiriEvalContext<'mir, 'tcx>) -> InterpResult<' // 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 @@ fn init_extern_statics(this: &mut MiriEvalContext<'mir, 'tcx>) -> InterpResult<' 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 } diff --git a/src/shims/unix/android/dlsym.rs b/src/shims/unix/android/dlsym.rs new file mode 100644 index 00000000000..a6b24d0fa50 --- /dev/null +++ b/src/shims/unix/android/dlsym.rs @@ -0,0 +1,53 @@ +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> { + Ok(match &*name { + "signal" => Some(Dlsym::signal), + _ => 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, + ) -> 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(()) + } +} diff --git a/src/shims/unix/android/foreign_items.rs b/src/shims/unix/android/foreign_items.rs new file mode 100644 index 00000000000..cde98b31e03 --- /dev/null +++ b/src/shims/unix/android/foreign_items.rs @@ -0,0 +1,23 @@ +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(); + match link_name.as_str() { + _ => return Ok(EmulateByNameResult::NotSupported), + } + //Ok(EmulateByNameResult::NeedsJumping) + } +} diff --git a/src/shims/unix/android/mod.rs b/src/shims/unix/android/mod.rs new file mode 100644 index 00000000000..434f5f30b5a --- /dev/null +++ b/src/shims/unix/android/mod.rs @@ -0,0 +1,2 @@ +pub mod dlsym; +pub mod foreign_items; diff --git a/src/shims/unix/dlsym.rs b/src/shims/unix/dlsym.rs index a806c16e28b..fee12822917 100644 --- a/src/shims/unix/dlsym.rs +++ b/src/shims/unix/dlsym.rs @@ -2,15 +2,17 @@ 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> { 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 @@ fn call_dlsym( 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), } } } diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 877a144963a..58b0997c6c0 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -24,6 +24,7 @@ fn emulate_foreign_item_by_name( ) -> 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 @@ fn emulate_foreign_item_by_name( // 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}"), } } }; diff --git a/src/shims/unix/freebsd/dlsym.rs b/src/shims/unix/freebsd/dlsym.rs index 74c322c666d..ebc1998f1b5 100644 --- a/src/shims/unix/freebsd/dlsym.rs +++ b/src/shims/unix/freebsd/dlsym.rs @@ -28,5 +28,9 @@ fn call_dlsym( assert!(this.tcx.sess.target.os == "freebsd"); match dlsym {} + + //trace!("{:?}", this.dump_place(**dest)); + //this.go_to_block(ret); + //Ok(()) } } diff --git a/src/shims/unix/linux/dlsym.rs b/src/shims/unix/linux/dlsym.rs index 44d51c4a0b3..f5cf1e0071a 100644 --- a/src/shims/unix/linux/dlsym.rs +++ b/src/shims/unix/linux/dlsym.rs @@ -32,5 +32,9 @@ fn call_dlsym( assert!(this.tcx.sess.target.os == "linux"); match dlsym {} + + //trace!("{:?}", this.dump_place(**dest)); + //this.go_to_block(ret); + //Ok(()) } } diff --git a/src/shims/unix/mod.rs b/src/shims/unix/mod.rs index 35380fc06d7..6fefb054f3c 100644 --- a/src/shims/unix/mod.rs +++ b/src/shims/unix/mod.rs @@ -5,6 +5,7 @@ mod sync; mod thread; +mod android; mod freebsd; mod linux; mod macos; diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index eab5f99c878..e14c2a86b09 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -45,7 +45,7 @@ fn call_dlsym( 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 @@ fn call_dlsym( 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" ); }