Skip to main content

miri/shims/unix/solarish/
foreign_items.rs

1use rustc_middle::ty::Ty;
2use rustc_span::Symbol;
3use rustc_target::callconv::FnAbi;
4use rustc_target::spec::Os;
5
6use crate::shims::unix::foreign_items::EvalContextExt as _;
7use crate::shims::unix::linux_like::epoll::EvalContextExt as _;
8use crate::shims::unix::linux_like::eventfd::EvalContextExt as _;
9use crate::shims::unix::*;
10use crate::*;
11
12pub fn is_dyn_sym(name: &str) -> bool {
13    matches!(name, "pthread_setname_np")
14}
15
16impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
17pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
18    fn emulate_foreign_item_inner(
19        &mut self,
20        link_name: Symbol,
21        abi: &FnAbi<'tcx, Ty<'tcx>>,
22        args: &[OpTy<'tcx>],
23        dest: &MPlaceTy<'tcx>,
24    ) -> InterpResult<'tcx, EmulateItemResult> {
25        let this = self.eval_context_mut();
26        match link_name.as_str() {
27            // epoll, eventfd (NOT available on Solaris!)
28            "epoll_create1" => {
29                this.assert_target_os(Os::Illumos, "epoll_create1");
30                let [flag] = &this
31                    .check_shim_sig(shim_sig!(extern "C" fn(i32) -> i32), (link_name, abi, args))?;
32                let result = this.epoll_create1(flag)?;
33                this.write_scalar(result, dest)?;
34            }
35            "epoll_ctl" => {
36                this.assert_target_os(Os::Illumos, "epoll_ctl");
37                let [epfd, op, fd, event] = &this.check_shim_sig(
38                    shim_sig!(extern "C" fn(i32, i32, i32, *libc::epoll_event) -> i32),
39                    (link_name, abi, args),
40                )?;
41                let result = this.epoll_ctl(epfd, op, fd, event)?;
42                this.write_scalar(result, dest)?;
43            }
44            "epoll_wait" => {
45                this.assert_target_os(Os::Illumos, "epoll_wait");
46                let [epfd, events, maxevents, timeout] = &this.check_shim_sig(
47                    shim_sig!(extern "C" fn(i32, *libc::epoll_event, i32, i32) -> i32),
48                    (link_name, abi, args),
49                )?;
50                this.epoll_wait(epfd, events, maxevents, timeout, dest)?;
51            }
52            "eventfd" => {
53                this.assert_target_os(Os::Illumos, "eventfd");
54                let [val, flag] = &this.check_shim_sig(
55                    shim_sig!(extern "C" fn(u32, i32) -> i32),
56                    (link_name, abi, args),
57                )?;
58                let result = this.eventfd(val, flag)?;
59                this.write_scalar(result, dest)?;
60            }
61
62            // Threading
63            "pthread_setname_np" => {
64                let [thread, name] = &this.check_shim_sig(
65                    shim_sig!(extern "C" fn(libc::pthread_t, *_) -> i32),
66                    (link_name, abi, args),
67                )?;
68                // THREAD_NAME_MAX allows a thread name of 31+1 length
69                // https://github.com/illumos/illumos-gate/blob/7671517e13b8123748eda4ef1ee165c6d9dba7fe/usr/src/uts/common/sys/thread.h#L613
70                let max_len = 32;
71                // See https://illumos.org/man/3C/pthread_setname_np for the error codes.
72                let res = match this.pthread_setname_np(
73                    this.read_scalar(thread)?,
74                    this.read_scalar(name)?,
75                    max_len,
76                    /* truncate */ false,
77                )? {
78                    ThreadNameResult::Ok => Scalar::from_u32(0),
79                    ThreadNameResult::NameTooLong => this.eval_libc("ERANGE"),
80                };
81                this.write_scalar(res, dest)?;
82            }
83            "pthread_getname_np" => {
84                let [thread, name, len] = &this.check_shim_sig(
85                    shim_sig!(extern "C" fn(libc::pthread_t, *_, usize) -> i32),
86                    (link_name, abi, args),
87                )?;
88                // See https://illumos.org/man/3C/pthread_getname_np for the error codes.
89                let res = match this.pthread_getname_np(
90                    this.read_scalar(thread)?,
91                    this.read_scalar(name)?,
92                    this.read_scalar(len)?,
93                    /* truncate */ false,
94                )? {
95                    ThreadNameResult::Ok => Scalar::from_u32(0),
96                    ThreadNameResult::NameTooLong => this.eval_libc("ERANGE"),
97                };
98                this.write_scalar(res, dest)?;
99            }
100
101            // Sockets and pipes
102            "__xnet_socketpair" => {
103                let [domain, type_, protocol, sv] = &this.check_shim_sig(
104                    shim_sig!(extern "C" fn(i32, i32, i32, *i32) -> i32),
105                    (link_name, abi, args),
106                )?;
107                let result = this.socketpair(domain, type_, protocol, sv)?;
108                this.write_scalar(result, dest)?;
109            }
110
111            // Network sockets
112            "__xnet_socket" | "__xnet7_socket" => {
113                let [domain, type_, protocol] = &this.check_shim_sig(
114                    shim_sig!(extern "C" fn(i32, i32, i32) -> i32),
115                    (link_name, abi, args),
116                )?;
117                let result = this.socket(domain, type_, protocol)?;
118                this.write_scalar(result, dest)?;
119            }
120            "__xnet_bind" => {
121                let [socket, address, address_len] = &this.check_shim_sig(
122                    shim_sig!(extern "C" fn(i32, *libc::sockaddr, libc::socklen_t) -> i32),
123                    (link_name, abi, args),
124                )?;
125                let result = this.bind(socket, address, address_len)?;
126                this.write_scalar(result, dest)?;
127            }
128            "__xnet_connect" => {
129                let [socket, address, address_len] = &this.check_shim_sig(
130                    shim_sig!(extern "C" fn(i32, *libc::sockaddr, libc::socklen_t) -> i32),
131                    (link_name, abi, args),
132                )?;
133                this.connect(socket, address, address_len, dest)?;
134            }
135            "__xnet_sendto" => {
136                let [socket, buffer, length, flags, dest_addr, dest_addr_len] = &this.check_shim_sig(
137                    shim_sig!(extern "C" fn(i32, *_, libc::size_t, i32, *libc::sockaddr, libc::socklen_t) -> libc::ssize_t),
138                    (link_name, abi, args),
139                )?;
140                this.send(socket, buffer, length, flags, Some((dest_addr, dest_addr_len)), dest)?;
141            }
142            "__xnet_getaddrinfo" => {
143                let [node, service, hints, res] = &this.check_shim_sig(
144                    shim_sig!(extern "C" fn(*_, *_, *_, **_) -> i32),
145                    (link_name, abi, args),
146                )?;
147                let result = this.getaddrinfo(node, service, hints, res)?;
148                this.write_scalar(result, dest)?;
149            }
150            "__xnet_getsockopt" => {
151                let [socket, level, option_name, option_value, option_len] = &this.check_shim_sig(
152                    shim_sig!(extern "C" fn(i32, i32, i32, *_, *_) -> i32),
153                    (link_name, abi, args),
154                )?;
155                let result =
156                    this.getsockopt(socket, level, option_name, option_value, option_len)?;
157                this.write_scalar(result, dest)?;
158            }
159
160            // Miscellaneous
161            "___errno" => {
162                let [] = &this
163                    .check_shim_sig(shim_sig!(extern "C" fn() -> *_), (link_name, abi, args))?;
164                let errno_place = this.last_error_place()?;
165                this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
166            }
167
168            "stack_getbounds" => {
169                // FIXME: This does not have a direct test (#3179).
170                let [stack] = &this.check_shim_sig(
171                    shim_sig!(extern "C" fn(*libc::stack_t) -> i32),
172                    (link_name, abi, args),
173                )?;
174                let stack = this.deref_pointer(stack)?;
175
176                this.write_int_fields_named(
177                    &[
178                        ("ss_sp", this.machine.stack_addr.into()),
179                        ("ss_size", this.machine.stack_size.into()),
180                        // field set to 0 means not in an alternate signal stack
181                        // https://docs.oracle.com/cd/E86824_01/html/E54766/stack-getbounds-3c.html
182                        ("ss_flags", 0),
183                    ],
184                    &stack,
185                )?;
186
187                this.write_int(0, dest)?;
188            }
189
190            "pset_info" => {
191                // FIXME: This does not have a direct test (#3179).
192                let [pset, tpe, cpus, list] = &this.check_shim_sig(
193                    shim_sig!(extern "C" fn(i32, *_, *u32, *_) -> i32),
194                    (link_name, abi, args),
195                )?;
196                // We do not need to handle the current process cpu mask, available_parallelism
197                // implementation pass null anyway. We only care for the number of
198                // cpus.
199                // https://docs.oracle.com/cd/E88353_01/html/E37841/pset-info-2.html
200
201                let pset = this.read_scalar(pset)?.to_i32()?;
202                let tpe = this.read_pointer(tpe)?;
203                let list = this.read_pointer(list)?;
204
205                let ps_myid = this.eval_libc_i32("PS_MYID");
206                if ps_myid != pset {
207                    throw_unsup_format!("pset_info is only supported with pset==PS_MYID");
208                }
209
210                if !this.ptr_is_null(tpe)? {
211                    throw_unsup_format!("pset_info is only supported with type==NULL");
212                }
213
214                if !this.ptr_is_null(list)? {
215                    throw_unsup_format!("pset_info is only supported with list==NULL");
216                }
217
218                let cpus = this.deref_pointer(cpus)?;
219                this.write_scalar(Scalar::from_u32(this.machine.num_cpus), &cpus)?;
220                this.write_int(0, dest)?;
221            }
222
223            "__sysconf_xpg7" => {
224                let [val] = &this.check_shim_sig(
225                    shim_sig!(extern "C" fn(i32) -> isize),
226                    (link_name, abi, args),
227                )?;
228                let result = this.sysconf(val)?;
229                this.write_scalar(result, dest)?;
230            }
231
232            _ => return interp_ok(EmulateItemResult::NotSupported),
233        }
234        interp_ok(EmulateItemResult::NeedsReturn)
235    }
236}