Skip to main content

miri/shims/unix/android/
foreign_items.rs

1use rustc_middle::ty::Ty;
2use rustc_span::Symbol;
3use rustc_target::callconv::FnAbi;
4
5use crate::shims::unix::env::EvalContextExt as _;
6use crate::shims::unix::linux_like::epoll::EvalContextExt as _;
7use crate::shims::unix::linux_like::eventfd::EvalContextExt as _;
8use crate::shims::unix::linux_like::syscall::syscall;
9use crate::shims::unix::linux_like::thread::prctl;
10use crate::shims::unix::*;
11use crate::*;
12
13pub fn is_dyn_sym(name: &str) -> bool {
14    matches!(name, "gettid")
15}
16
17impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
18pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
19    fn emulate_foreign_item_inner(
20        &mut self,
21        link_name: Symbol,
22        abi: &FnAbi<'tcx, Ty<'tcx>>,
23        args: &[OpTy<'tcx>],
24        dest: &MPlaceTy<'tcx>,
25    ) -> InterpResult<'tcx, EmulateItemResult> {
26        let ecx = self.eval_context_mut();
27        match link_name.as_str() {
28            // File related shims
29            "pread64" => {
30                let [fd, buf, count, offset] = &ecx.check_shim_sig(
31                    shim_sig!(extern "C" fn(i32, *_, usize, libc::off64_t) -> isize),
32                    (link_name, abi, args),
33                )?;
34                let fd = ecx.read_scalar(fd)?.to_i32()?;
35                let buf = ecx.read_pointer(buf)?;
36                let count = ecx.read_target_usize(count)?;
37                let offset = ecx.read_scalar(offset)?.to_int(offset.layout.size)?;
38                ecx.read(fd, buf, count, Some(offset), dest)?;
39            }
40            "pwrite64" => {
41                let [fd, buf, n, offset] = &ecx.check_shim_sig(
42                    shim_sig!(extern "C" fn(i32, *_, usize, libc::off64_t) -> isize),
43                    (link_name, abi, args),
44                )?;
45                let fd = ecx.read_scalar(fd)?.to_i32()?;
46                let buf = ecx.read_pointer(buf)?;
47                let count = ecx.read_target_usize(n)?;
48                let offset = ecx.read_scalar(offset)?.to_int(offset.layout.size)?;
49                trace!("Called pwrite64({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset);
50                ecx.write(fd, buf, count, Some(offset), dest)?;
51            }
52            "lseek64" => {
53                let [fd, offset, whence] = &ecx.check_shim_sig(
54                    shim_sig!(extern "C" fn(i32, libc::off64_t, i32) -> libc::off64_t),
55                    (link_name, abi, args),
56                )?;
57                let fd = ecx.read_scalar(fd)?.to_i32()?;
58                let offset = ecx.read_scalar(offset)?.to_int(offset.layout.size)?;
59                let whence = ecx.read_scalar(whence)?.to_i32()?;
60                ecx.lseek(fd, offset, whence, dest)?;
61            }
62            "ftruncate64" => {
63                let [fd, length] = &ecx.check_shim_sig(
64                    shim_sig!(extern "C" fn(i32, libc::off64_t) -> i32),
65                    (link_name, abi, args),
66                )?;
67                let fd = ecx.read_scalar(fd)?.to_i32()?;
68                let length = ecx.read_scalar(length)?.to_int(length.layout.size)?;
69                let result = ecx.ftruncate64(fd, length)?;
70                ecx.write_scalar(result, dest)?;
71            }
72
73            // epoll, eventfd
74            "epoll_create1" => {
75                let [flag] = &ecx
76                    .check_shim_sig(shim_sig!(extern "C" fn(i32) -> i32), (link_name, abi, args))?;
77                let result = ecx.epoll_create1(flag)?;
78                ecx.write_scalar(result, dest)?;
79            }
80            "epoll_ctl" => {
81                let [epfd, op, fd, event] = &ecx.check_shim_sig(
82                    shim_sig!(extern "C" fn(i32, i32, i32, *libc::epoll_event) -> i32),
83                    (link_name, abi, args),
84                )?;
85                let result = ecx.epoll_ctl(epfd, op, fd, event)?;
86                ecx.write_scalar(result, dest)?;
87            }
88            "epoll_wait" => {
89                let [epfd, events, maxevents, timeout] = &ecx.check_shim_sig(
90                    shim_sig!(extern "C" fn(i32, *libc::epoll_event, i32, i32) -> i32),
91                    (link_name, abi, args),
92                )?;
93                ecx.epoll_wait(epfd, events, maxevents, timeout, dest)?;
94            }
95            "eventfd" => {
96                let [val, flag] = &ecx.check_shim_sig(
97                    shim_sig!(extern "C" fn(u32, i32) -> i32),
98                    (link_name, abi, args),
99                )?;
100                let result = ecx.eventfd(val, flag)?;
101                ecx.write_scalar(result, dest)?;
102            }
103
104            // Miscellaneous
105            "__errno" => {
106                let [] =
107                    &ecx.check_shim_sig(shim_sig!(extern "C" fn() -> *_), (link_name, abi, args))?;
108                let errno_place = ecx.last_error_place()?;
109                ecx.write_scalar(errno_place.to_ref(ecx).to_scalar(), dest)?;
110            }
111
112            "gettid" => {
113                let [] = &ecx.check_shim_sig(
114                    shim_sig!(extern "C" fn() -> libc::pid_t),
115                    (link_name, abi, args),
116                )?;
117                let result = ecx.unix_gettid(link_name.as_str())?;
118                ecx.write_scalar(result, dest)?;
119            }
120
121            // Dynamically invoked syscalls
122            "syscall" => syscall(ecx, link_name, abi, args, dest)?,
123
124            // Threading
125            "prctl" => prctl(ecx, link_name, abi, args, dest)?,
126
127            // std-only stubs
128            "sendfile" if ecx.frame_in_std() => {
129                let [_out_fd, _in_fd, _offset, _count] = &ecx.check_shim_sig(
130                    shim_sig!(extern "C" fn(i32, i32, *libc::off_t, usize) -> isize),
131                    (link_name, abi, args),
132                )?;
133                // Force std to use a fallback path.
134                ecx.set_errno_and_return_neg1(LibcError("ENOSYS"), dest)?;
135            }
136
137            _ => return interp_ok(EmulateItemResult::NotSupported),
138        }
139        interp_ok(EmulateItemResult::NeedsReturn)
140    }
141}