1use rustc_abi::CanonAbi;
2use rustc_middle::ty::Ty;
3use rustc_span::Symbol;
4use rustc_target::callconv::FnAbi;
5
6use super::sync::{EvalContextExt as _, MacOsFutexTimeout};
7use crate::shims::unix::*;
8use crate::*;
9
10pub fn is_dyn_sym(name: &str) -> bool {
11 match name {
12 "os_sync_wait_on_address"
14 | "os_sync_wait_on_address_with_deadline"
15 | "os_sync_wait_on_address_with_timeout"
16 | "os_sync_wake_by_address_any"
17 | "os_sync_wake_by_address_all" => true,
18 _ => false,
19 }
20}
21
22impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
23pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
24 fn emulate_foreign_item_inner(
25 &mut self,
26 link_name: Symbol,
27 abi: &FnAbi<'tcx, Ty<'tcx>>,
28 args: &[OpTy<'tcx>],
29 dest: &MPlaceTy<'tcx>,
30 ) -> InterpResult<'tcx, EmulateItemResult> {
31 let this = self.eval_context_mut();
32
33 match link_name.as_str() {
36 "__error" => {
38 let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
39 let errno_place = this.last_error_place()?;
40 this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
41 }
42
43 "close$NOCANCEL" => {
45 let [result] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
46 let result = this.close(result)?;
47 this.write_scalar(result, dest)?;
48 }
49 "stat" | "stat$INODE64" => {
50 let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
52 let result = this.stat(path, buf)?;
53 this.write_scalar(result, dest)?;
54 }
55 "lstat" | "lstat$INODE64" => {
56 let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
58 let result = this.lstat(path, buf)?;
59 this.write_scalar(result, dest)?;
60 }
61 "fstat$INODE64" => {
62 let [fd, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
63 let result = this.fstat(fd, buf)?;
64 this.write_scalar(result, dest)?;
65 }
66 "opendir$INODE64" => {
67 let [name] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
68 let result = this.opendir(name)?;
69 this.write_scalar(result, dest)?;
70 }
71 "readdir_r" | "readdir_r$INODE64" => {
72 let [dirp, entry, result] =
73 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
74 let result = this.macos_readdir_r(dirp, entry, result)?;
75 this.write_scalar(result, dest)?;
76 }
77 "realpath$DARWIN_EXTSN" => {
78 let [path, resolved_path] =
79 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
80 let result = this.realpath(path, resolved_path)?;
81 this.write_scalar(result, dest)?;
82 }
83 "ioctl" => {
84 let ([fd_num, cmd], varargs) =
85 this.check_shim_sig_variadic_lenient(abi, CanonAbi::C, link_name, args)?;
86 let result = this.ioctl(fd_num, cmd, varargs)?;
87 this.write_scalar(result, dest)?;
88 }
89
90 "_NSGetEnviron" => {
92 let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
94 let environ = this.machine.env_vars.unix().environ();
95 this.write_pointer(environ, dest)?;
96 }
97
98 "CCRandomGenerateBytes" => {
100 let [bytes, count] =
101 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
102 let bytes = this.read_pointer(bytes)?;
103 let count = this.read_target_usize(count)?;
104 let success = this.eval_libc_i32("kCCSuccess");
105 this.gen_random(bytes, count)?;
106 this.write_int(success, dest)?;
107 }
108
109 "mach_absolute_time" => {
111 let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
112 let result = this.mach_absolute_time()?;
113 this.write_scalar(result, dest)?;
114 }
115
116 "mach_timebase_info" => {
117 let [info] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
119 let result = this.mach_timebase_info(info)?;
120 this.write_scalar(result, dest)?;
121 }
122
123 "mach_wait_until" => {
124 let [deadline] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
126 let result = this.mach_wait_until(deadline)?;
127 this.write_scalar(result, dest)?;
128 }
129
130 "_NSGetArgc" => {
132 let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
134 this.write_pointer(this.machine.argc.expect("machine must be initialized"), dest)?;
135 }
136 "_NSGetArgv" => {
137 let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
139 this.write_pointer(this.machine.argv.expect("machine must be initialized"), dest)?;
140 }
141 "_NSGetExecutablePath" => {
142 let [buf, bufsize] =
144 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
145 this.check_no_isolation("`_NSGetExecutablePath`")?;
146
147 let buf_ptr = this.read_pointer(buf)?;
148 let bufsize = this.deref_pointer_as(bufsize, this.machine.layouts.u32)?;
149
150 let path = std::env::current_exe().unwrap();
153 let (written, size_needed) = this.write_path_to_c_str(
154 &path,
155 buf_ptr,
156 this.read_scalar(&bufsize)?.to_u32()?.into(),
157 )?;
158
159 if written {
160 this.write_null(dest)?;
161 } else {
162 this.write_scalar(Scalar::from_u32(size_needed.try_into().unwrap()), &bufsize)?;
163 this.write_int(-1, dest)?;
164 }
165 }
166
167 "_tlv_atexit" => {
169 let [dtor, data] =
170 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
171 let dtor = this.read_pointer(dtor)?;
172 let dtor = this.get_ptr_fn(dtor)?.as_instance()?;
173 let data = this.read_scalar(data)?;
174 let active_thread = this.active_thread();
175 this.machine.tls.add_macos_thread_dtor(
176 active_thread,
177 dtor,
178 data,
179 this.machine.current_user_relevant_span(),
180 )?;
181 }
182
183 "pthread_get_stackaddr_np" => {
185 let [thread] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
187 this.read_target_usize(thread)?;
188 let stack_addr = Scalar::from_uint(this.machine.stack_addr, this.pointer_size());
189 this.write_scalar(stack_addr, dest)?;
190 }
191 "pthread_get_stacksize_np" => {
192 let [thread] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
194 this.read_target_usize(thread)?;
195 let stack_size = Scalar::from_uint(this.machine.stack_size, this.pointer_size());
196 this.write_scalar(stack_size, dest)?;
197 }
198
199 "pthread_setname_np" => {
201 let [name] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
202
203 let thread = this.pthread_self()?;
213 let res = match this.pthread_setname_np(
214 thread,
215 this.read_scalar(name)?,
216 this.eval_libc("MAXTHREADNAMESIZE").to_target_usize(this)?,
217 false,
218 )? {
219 ThreadNameResult::Ok => Scalar::from_u32(0),
220 ThreadNameResult::NameTooLong => this.eval_libc("ENAMETOOLONG"),
221 ThreadNameResult::ThreadNotFound => unreachable!(),
222 };
223 this.write_scalar(res, dest)?;
226 }
227 "pthread_getname_np" => {
228 let [thread, name, len] =
229 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
230
231 let res = match this.pthread_getname_np(
240 this.read_scalar(thread)?,
241 this.read_scalar(name)?,
242 this.read_scalar(len)?,
243 true,
244 )? {
245 ThreadNameResult::Ok => Scalar::from_u32(0),
246 ThreadNameResult::NameTooLong => Scalar::from_u32(0),
248 ThreadNameResult::ThreadNotFound => this.eval_libc("ESRCH"),
249 };
250 this.write_scalar(res, dest)?;
251 }
252 "pthread_threadid_np" => {
253 let [thread, tid_ptr] =
254 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
255 let res = this.apple_pthread_threadip_np(thread, tid_ptr)?;
256 this.write_scalar(res, dest)?;
257 }
258
259 "os_sync_wait_on_address" => {
261 let [addr_op, value_op, size_op, flags_op] =
262 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
263 this.os_sync_wait_on_address(
264 addr_op,
265 value_op,
266 size_op,
267 flags_op,
268 MacOsFutexTimeout::None,
269 dest,
270 )?;
271 }
272 "os_sync_wait_on_address_with_deadline" => {
273 let [addr_op, value_op, size_op, flags_op, clock_op, timeout_op] =
274 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
275 this.os_sync_wait_on_address(
276 addr_op,
277 value_op,
278 size_op,
279 flags_op,
280 MacOsFutexTimeout::Absolute { clock_op, timeout_op },
281 dest,
282 )?;
283 }
284 "os_sync_wait_on_address_with_timeout" => {
285 let [addr_op, value_op, size_op, flags_op, clock_op, timeout_op] =
286 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
287 this.os_sync_wait_on_address(
288 addr_op,
289 value_op,
290 size_op,
291 flags_op,
292 MacOsFutexTimeout::Relative { clock_op, timeout_op },
293 dest,
294 )?;
295 }
296 "os_sync_wake_by_address_any" => {
297 let [addr_op, size_op, flags_op] =
298 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
299 this.os_sync_wake_by_address(
300 addr_op, size_op, flags_op, false, dest,
301 )?;
302 }
303 "os_sync_wake_by_address_all" => {
304 let [addr_op, size_op, flags_op] =
305 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
306 this.os_sync_wake_by_address(
307 addr_op, size_op, flags_op, true, dest,
308 )?;
309 }
310 "os_unfair_lock_lock" => {
311 let [lock_op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
312 this.os_unfair_lock_lock(lock_op)?;
313 }
314 "os_unfair_lock_trylock" => {
315 let [lock_op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
316 this.os_unfair_lock_trylock(lock_op, dest)?;
317 }
318 "os_unfair_lock_unlock" => {
319 let [lock_op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
320 this.os_unfair_lock_unlock(lock_op)?;
321 }
322 "os_unfair_lock_assert_owner" => {
323 let [lock_op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
324 this.os_unfair_lock_assert_owner(lock_op)?;
325 }
326 "os_unfair_lock_assert_not_owner" => {
327 let [lock_op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
328 this.os_unfair_lock_assert_not_owner(lock_op)?;
329 }
330
331 "pthread_cond_timedwait_relative_np" => {
332 let [cond, mutex, reltime] =
333 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
334 this.pthread_cond_timedwait(
335 cond, mutex, reltime, dest, true,
336 )?;
337 }
338
339 _ => return interp_ok(EmulateItemResult::NotSupported),
340 };
341
342 interp_ok(EmulateItemResult::NeedsReturn)
343 }
344
345 fn ioctl(
346 &mut self,
347 fd_num: &OpTy<'tcx>,
348 cmd: &OpTy<'tcx>,
349 _varargs: &[OpTy<'tcx>],
350 ) -> InterpResult<'tcx, Scalar> {
351 let this = self.eval_context_mut();
352
353 let fioclex = this.eval_libc_u64("FIOCLEX");
354
355 let fd_num = this.read_scalar(fd_num)?.to_i32()?;
356 let cmd = this.read_scalar(cmd)?.to_u64()?;
357
358 if cmd == fioclex {
359 if this.machine.fds.is_fd_num(fd_num) {
362 interp_ok(Scalar::from_i32(0))
363 } else {
364 this.set_last_error_and_return_i32(LibcError("EBADF"))
365 }
366 } else {
367 throw_unsup_format!("ioctl: unsupported command {cmd:#x}");
368 }
369 }
370}