add very basic Android support

This commit is contained in:
Ralf Jung 2022-08-18 08:15:41 -04:00
parent af033ea428
commit a05a8eb805
13 changed files with 143 additions and 21 deletions

1
ci.sh
View File

@ -84,6 +84,7 @@ case $HOST_TARGET in
MIRI_TEST_TARGET=aarch64-apple-darwin run_tests MIRI_TEST_TARGET=aarch64-apple-darwin run_tests
MIRI_TEST_TARGET=i686-pc-windows-msvc 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 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 MIRI_TEST_TARGET=thumbv7em-none-eabihf MIRI_NO_STD=1 run_tests_minimal no_std # no_std embedded architecture
;; ;;
x86_64-apple-darwin) x86_64-apple-darwin)

View File

@ -1 +1 @@
8556e6620e4866526b3cea767ad8c20ae877a569 9c20b2a8cc7588decb6de25ac6a7912dcef24d65

View File

@ -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 /// Helper function used inside the shims of foreign functions to check that
/// `target_os` is a supported UNIX OS. /// `target_os` is a supported UNIX OS.
pub fn target_os_is_unix(target_os: &str) -> bool { pub fn target_os_is_unix(target_os: &str) -> bool {
matches!(target_os, "linux" | "macos" | "freebsd") matches!(target_os, "linux" | "macos" | "freebsd" | "android")
} }

View File

@ -232,13 +232,15 @@ pub struct PrimitiveLayouts<'tcx> {
pub u32: TyAndLayout<'tcx>, pub u32: TyAndLayout<'tcx>,
pub usize: TyAndLayout<'tcx>, pub usize: TyAndLayout<'tcx>,
pub bool: 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> { impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> {
fn new(layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Result<Self, LayoutError<'tcx>> { fn new(layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Result<Self, LayoutError<'tcx>> {
let tcx = layout_cx.tcx; let tcx = layout_cx.tcx;
let mut_raw_ptr = tcx.mk_ptr(TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Mut }); 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 { Ok(Self {
unit: layout_cx.layout_of(tcx.mk_unit())?, unit: layout_cx.layout_of(tcx.mk_unit())?,
i8: layout_cx.layout_of(tcx.types.i8)?, i8: layout_cx.layout_of(tcx.types.i8)?,
@ -251,6 +253,7 @@ fn new(layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Result<Self, LayoutError<'tcx
usize: layout_cx.layout_of(tcx.types.usize)?, usize: layout_cx.layout_of(tcx.types.usize)?,
bool: layout_cx.layout_of(tcx.types.bool)?, bool: layout_cx.layout_of(tcx.types.bool)?,
mut_raw_ptr: layout_cx.layout_of(mut_raw_ptr)?, mut_raw_ptr: layout_cx.layout_of(mut_raw_ptr)?,
const_raw_ptr: layout_cx.layout_of(const_raw_ptr)?,
}) })
} }
} }
@ -431,6 +434,17 @@ fn add_extern_static(
this.machine.extern_statics.try_insert(Symbol::intern(name), ptr).unwrap(); 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. /// Sets up the "extern statics" for this machine.
fn init_extern_statics(this: &mut MiriEvalContext<'mir, 'tcx>) -> InterpResult<'tcx> { fn init_extern_statics(this: &mut MiriEvalContext<'mir, 'tcx>) -> InterpResult<'tcx> {
match this.tcx.sess.target.os.as_ref() { 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). // syscall that we do support).
for name in &["__cxa_thread_atexit_impl", "getrandom", "statx", "__clock_gettime64"] for name in &["__cxa_thread_atexit_impl", "getrandom", "statx", "__clock_gettime64"]
{ {
let layout = this.machine.layouts.usize; let val = ImmTy::from_int(0, this.machine.layouts.usize);
let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?; Self::alloc_extern_static(this, name, val)?;
this.write_scalar(Scalar::from_machine_usize(0, this), &place.into())?;
Self::add_extern_static(this, name, place.ptr);
} }
} }
"freebsd" => { "freebsd" => {
@ -461,13 +473,27 @@ fn init_extern_statics(this: &mut MiriEvalContext<'mir, 'tcx>) -> InterpResult<'
this.machine.env_vars.environ.unwrap().ptr, 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" => { "windows" => {
// "_tls_used" // "_tls_used"
// This is some obscure hack that is part of the Windows TLS story. It's a `u8`. // This is some obscure hack that is part of the Windows TLS story. It's a `u8`.
let layout = this.machine.layouts.u8; let val = ImmTy::from_int(0, this.machine.layouts.u8);
let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?; Self::alloc_extern_static(this, "_tls_used", val)?;
this.write_scalar(Scalar::from_u8(0), &place.into())?;
Self::add_extern_static(this, "_tls_used", place.ptr);
} }
_ => {} // No "extern statics" supported on this target _ => {} // No "extern statics" supported on this target
} }

View File

@ -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<Dlsym>> {
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<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(())
}
}

View File

@ -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)
}
}

View File

@ -0,0 +1,2 @@
pub mod dlsym;
pub mod foreign_items;

View File

@ -2,15 +2,17 @@
use rustc_target::spec::abi::Abi; use rustc_target::spec::abi::Abi;
use crate::*; use crate::*;
use shims::unix::android::dlsym as android;
use shims::unix::freebsd::dlsym as freebsd; use shims::unix::freebsd::dlsym as freebsd;
use shims::unix::linux::dlsym as linux; use shims::unix::linux::dlsym as linux;
use shims::unix::macos::dlsym as macos; use shims::unix::macos::dlsym as macos;
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub enum Dlsym { pub enum Dlsym {
Android(android::Dlsym),
FreeBsd(freebsd::Dlsym),
Linux(linux::Dlsym), Linux(linux::Dlsym),
MacOs(macos::Dlsym), MacOs(macos::Dlsym),
FreeBsd(freebsd::Dlsym),
} }
impl Dlsym { impl Dlsym {
@ -18,10 +20,11 @@ impl Dlsym {
// should become a NULL pointer (pretend it does not exist). // should become a NULL pointer (pretend it does not exist).
pub fn from_str<'tcx>(name: &str, target_os: &str) -> InterpResult<'tcx, Option<Dlsym>> { pub fn from_str<'tcx>(name: &str, target_os: &str) -> InterpResult<'tcx, Option<Dlsym>> {
Ok(match target_os { 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), "linux" => linux::Dlsym::from_str(name)?.map(Dlsym::Linux),
"macos" => macos::Dlsym::from_str(name)?.map(Dlsym::MacOs), "macos" => macos::Dlsym::from_str(name)?.map(Dlsym::MacOs),
"freebsd" => freebsd::Dlsym::from_str(name)?.map(Dlsym::FreeBsd), _ => panic!("unsupported Unix OS {target_os}"),
_ => unreachable!(),
}) })
} }
} }
@ -41,10 +44,12 @@ fn call_dlsym(
this.check_abi(abi, Abi::C { unwind: false })?; this.check_abi(abi, Abi::C { unwind: false })?;
match dlsym { match dlsym {
Dlsym::Linux(dlsym) => linux::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), Dlsym::Android(dlsym) =>
Dlsym::MacOs(dlsym) => macos::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), android::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret),
Dlsym::FreeBsd(dlsym) => Dlsym::FreeBsd(dlsym) =>
freebsd::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), 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),
} }
} }
} }

View File

@ -24,6 +24,7 @@ fn emulate_foreign_item_by_name(
) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
let this = self.eval_context_mut(); let this = self.eval_context_mut();
#[rustfmt::skip]
match link_name.as_str() { match link_name.as_str() {
// Environment related shims // Environment related shims
"getenv" => { "getenv" => {
@ -588,11 +589,13 @@ fn emulate_foreign_item_by_name(
// Platform-specific shims // 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), "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), "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), _ => panic!("unsupported Unix OS {target_os}"),
_ => unreachable!(),
} }
} }
}; };

View File

@ -28,5 +28,9 @@ fn call_dlsym(
assert!(this.tcx.sess.target.os == "freebsd"); assert!(this.tcx.sess.target.os == "freebsd");
match dlsym {} match dlsym {}
//trace!("{:?}", this.dump_place(**dest));
//this.go_to_block(ret);
//Ok(())
} }
} }

View File

@ -32,5 +32,9 @@ fn call_dlsym(
assert!(this.tcx.sess.target.os == "linux"); assert!(this.tcx.sess.target.os == "linux");
match dlsym {} match dlsym {}
//trace!("{:?}", this.dump_place(**dest));
//this.go_to_block(ret);
//Ok(())
} }
} }

View File

@ -5,6 +5,7 @@
mod sync; mod sync;
mod thread; mod thread;
mod android;
mod freebsd; mod freebsd;
mod linux; mod linux;
mod macos; mod macos;

View File

@ -45,7 +45,7 @@ fn call_dlsym(
Dlsym::NtWriteFile => { Dlsym::NtWriteFile => {
if !this.frame_in_std() { if !this.frame_in_std() {
throw_unsup_format!( 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 { if byte_offset != 0 {
throw_unsup_format!( throw_unsup_format!(
"NtWriteFile ByteOffset paremeter is non-null, which is unsupported" "`NtWriteFile` `ByteOffset` paremeter is non-null, which is unsupported"
); );
} }