Skip to content

Commit

Permalink
Auto merge of #2493 - RalfJung:android, r=RalfJung
Browse files Browse the repository at this point in the history
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 #2011.
Fixes #2010.
  • Loading branch information
bors committed Aug 18, 2022
2 parents af033ea + 5e10f14 commit 339500f
Show file tree
Hide file tree
Showing 15 changed files with 160 additions and 23 deletions.
3 changes: 2 additions & 1 deletion ci.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion rust-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
8556e6620e4866526b3cea767ad8c20ae877a569
9c20b2a8cc7588decb6de25ac6a7912dcef24d65
2 changes: 1 addition & 1 deletion src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
)]
Expand Down
44 changes: 35 additions & 9 deletions src/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)?,
Expand All @@ -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)?,
})
}
}
Expand Down Expand Up @@ -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() {
Expand All @@ -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" => {
Expand All @@ -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
}
Expand Down
54 changes: 54 additions & 0 deletions src/shims/unix/android/dlsym.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 26 additions & 0 deletions src/shims/unix/android/foreign_items.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 2 additions & 0 deletions src/shims/unix/android/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod dlsym;
pub mod foreign_items;
15 changes: 10 additions & 5 deletions src/shims/unix/dlsym.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,29 @@ 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 {
// 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, 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}"),
})
}
}
Expand All @@ -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),
}
}
}
9 changes: 6 additions & 3 deletions src/shims/unix/foreign_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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" => {
Expand Down Expand Up @@ -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}"),
}
}
};
Expand Down
4 changes: 4 additions & 0 deletions src/shims/unix/freebsd/dlsym.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(())
}
}
12 changes: 11 additions & 1 deletion src/shims/unix/freebsd/foreign_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {}

Expand All @@ -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" => {
Expand Down
4 changes: 4 additions & 0 deletions src/shims/unix/linux/dlsym.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(())
}
}
1 change: 1 addition & 0 deletions src/shims/unix/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod fs;
mod sync;
mod thread;

mod android;
mod freebsd;
mod linux;
mod macos;
Expand Down
4 changes: 2 additions & 2 deletions src/shims/windows/dlsym.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"
);
}

Expand All @@ -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"
);
}

Expand Down

0 comments on commit 339500f

Please sign in to comment.