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_deprecated(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 [fd] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
46 let fd = this.read_scalar(fd)?.to_i32()?;
47 let result = this.close(fd)?;
48 this.write_scalar(result, dest)?;
49 }
50 "stat$INODE64" => {
51 let [path, buf] =
52 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
53 let result = this.stat(path, buf)?;
54 this.write_scalar(result, dest)?;
55 }
56 "lstat$INODE64" => {
57 let [path, buf] =
58 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
59 let result = this.lstat(path, buf)?;
60 this.write_scalar(result, dest)?;
61 }
62 "fstat$INODE64" => {
63 let [fd, buf] =
64 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
65 let result = this.fstat(fd, buf, "stat")?;
66 this.write_scalar(result, dest)?;
67 }
68 "fstatat$INODE64" => {
69 let [dirfd, path, buf, flags] = this.check_shim_sig(
70 shim_sig!(extern "C" fn(i32, *_, *_, i32) -> i32),
71 (link_name, abi, args),
72 )?;
73 let result = this.fstatat(dirfd, path, buf, flags)?;
74 this.write_scalar(result, dest)?;
75 }
76 "opendir$INODE64" => {
77 let [name] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
78 let result = this.opendir(name)?;
79 this.write_scalar(result, dest)?;
80 }
81 "readdir$INODE64" => {
82 let [dirp] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
83 this.readdir(dirp, dest, "dirent")?;
84 }
85 "realpath$DARWIN_EXTSN" => {
86 let [path, resolved_path] =
87 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
88 let result = this.realpath(path, resolved_path)?;
89 this.write_scalar(result, dest)?;
90 }
91
92 "_NSGetEnviron" => {
94 let [] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
96 let environ = this.machine.env_vars.unix().environ();
97 this.write_pointer(environ, dest)?;
98 }
99
100 "CCRandomGenerateBytes" => {
102 let [bytes, count] =
103 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
104 let bytes = this.read_pointer(bytes)?;
105 let count = this.read_target_usize(count)?;
106 let success = this.eval_libc_i32("kCCSuccess");
107 this.gen_random(bytes, count)?;
108 this.write_int(success, dest)?;
109 }
110
111 "mach_absolute_time" => {
113 let [] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
114 let result = this.mach_absolute_time()?;
115 this.write_scalar(result, dest)?;
116 }
117
118 "mach_timebase_info" => {
119 let [info] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
121 let result = this.mach_timebase_info(info)?;
122 this.write_scalar(result, dest)?;
123 }
124
125 "mach_wait_until" => {
126 let [deadline] =
128 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
129 let result = this.mach_wait_until(deadline)?;
130 this.write_scalar(result, dest)?;
131 }
132
133 "_NSGetArgc" => {
135 let [] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
137 this.write_pointer(this.machine.argc.expect("machine must be initialized"), dest)?;
138 }
139 "_NSGetArgv" => {
140 let [] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
142 this.write_pointer(this.machine.argv.expect("machine must be initialized"), dest)?;
143 }
144 "_NSGetExecutablePath" => {
145 let [buf, bufsize] =
147 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
148 this.check_no_isolation("`_NSGetExecutablePath`")?;
149
150 let buf_ptr = this.read_pointer(buf)?;
151 let bufsize = this.deref_pointer_as(bufsize, this.machine.layouts.u32)?;
152
153 let Some(path) = this.machine.current_exe.clone() else {
154 throw_unsup_format!(
155 "_NSGetExecutablePath only works when Miri is run on a file"
156 )
157 };
158 let (written, size_needed) = this.write_path_to_c_str(
159 &path,
160 buf_ptr,
161 this.read_scalar(&bufsize)?.to_u32()?.into(),
162 )?;
163
164 if written {
165 this.write_null(dest)?;
166 } else {
167 this.write_scalar(Scalar::from_u32(size_needed.try_into().unwrap()), &bufsize)?;
168 this.write_int(-1, dest)?;
169 }
170 }
171
172 "_tlv_atexit" => {
174 let [dtor, data] =
175 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
176 let dtor = this.read_pointer(dtor)?;
177 let dtor = this.get_ptr_fn(dtor)?.as_instance()?;
178 let data = this.read_scalar(data)?;
179 let active_thread = this.active_thread();
180 this.machine.tls.add_macos_thread_dtor(
181 active_thread,
182 dtor,
183 data,
184 this.machine.current_user_relevant_span(),
185 )?;
186 }
187
188 "pthread_get_stackaddr_np" => {
190 let [thread] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
192 this.read_target_usize(thread)?;
193 let stack_addr = Scalar::from_uint(this.machine.stack_addr, this.pointer_size());
194 this.write_scalar(stack_addr, dest)?;
195 }
196 "pthread_get_stacksize_np" => {
197 let [thread] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
199 this.read_target_usize(thread)?;
200 let stack_size = Scalar::from_uint(this.machine.stack_size, this.pointer_size());
201 this.write_scalar(stack_size, dest)?;
202 }
203
204 "pthread_setname_np" => {
206 let [name] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
207
208 let thread = this.pthread_self()?;
218 let res = match this.pthread_setname_np(
219 thread,
220 this.read_scalar(name)?,
221 this.eval_libc("MAXTHREADNAMESIZE").to_target_usize(this)?,
222 false,
223 )? {
224 ThreadNameResult::Ok => Scalar::from_i32(0),
225 ThreadNameResult::NameTooLong => {
226 this.set_errno_and_return_neg1_i32(LibcError("ENAMETOOLONG"))?
228 }
229 };
230 this.write_scalar(res, dest)?;
233 }
234 "pthread_getname_np" => {
235 let [thread, name, len] =
236 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
237
238 let res = match this.pthread_getname_np(
247 this.read_scalar(thread)?,
248 this.read_scalar(name)?,
249 this.read_scalar(len)?,
250 true,
251 )? {
252 ThreadNameResult::Ok => Scalar::from_i32(0),
253 ThreadNameResult::NameTooLong => Scalar::from_i32(0),
255 };
256 this.write_scalar(res, dest)?;
257 }
258 "pthread_threadid_np" => {
259 let [thread, tid_ptr] =
260 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
261 let res = this.apple_pthread_threadid_np(thread, tid_ptr)?;
262 this.write_scalar(res, dest)?;
263 }
264
265 "os_sync_wait_on_address" => {
267 let [addr_op, value_op, size_op, flags_op] =
268 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
269 this.os_sync_wait_on_address(
270 addr_op,
271 value_op,
272 size_op,
273 flags_op,
274 MacOsFutexTimeout::None,
275 dest,
276 )?;
277 }
278 "os_sync_wait_on_address_with_deadline" => {
279 let [addr_op, value_op, size_op, flags_op, clock_op, timeout_op] =
280 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
281 this.os_sync_wait_on_address(
282 addr_op,
283 value_op,
284 size_op,
285 flags_op,
286 MacOsFutexTimeout::Absolute { clock_op, timeout_op },
287 dest,
288 )?;
289 }
290 "os_sync_wait_on_address_with_timeout" => {
291 let [addr_op, value_op, size_op, flags_op, clock_op, timeout_op] =
292 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
293 this.os_sync_wait_on_address(
294 addr_op,
295 value_op,
296 size_op,
297 flags_op,
298 MacOsFutexTimeout::Relative { clock_op, timeout_op },
299 dest,
300 )?;
301 }
302 "os_sync_wake_by_address_any" => {
303 let [addr_op, size_op, flags_op] =
304 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
305 this.os_sync_wake_by_address(
306 addr_op, size_op, flags_op, false, dest,
307 )?;
308 }
309 "os_sync_wake_by_address_all" => {
310 let [addr_op, size_op, flags_op] =
311 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
312 this.os_sync_wake_by_address(
313 addr_op, size_op, flags_op, true, dest,
314 )?;
315 }
316 "os_unfair_lock_lock" => {
317 let [lock_op] =
318 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
319 this.os_unfair_lock_lock(lock_op)?;
320 }
321 "os_unfair_lock_trylock" => {
322 let [lock_op] =
323 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
324 this.os_unfair_lock_trylock(lock_op, dest)?;
325 }
326 "os_unfair_lock_unlock" => {
327 let [lock_op] =
328 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
329 this.os_unfair_lock_unlock(lock_op)?;
330 }
331 "os_unfair_lock_assert_owner" => {
332 let [lock_op] =
333 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
334 this.os_unfair_lock_assert_owner(lock_op)?;
335 }
336 "os_unfair_lock_assert_not_owner" => {
337 let [lock_op] =
338 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
339 this.os_unfair_lock_assert_not_owner(lock_op)?;
340 }
341 "dispatch_semaphore_create" => {
342 let [value] = this.check_shim_sig(
343 shim_sig!(extern "C" fn(isize) -> *_),
344 (link_name, abi, args),
345 )?;
346 this.dispatch_semaphore_create(value, dest)?;
347 }
348 "dispatch_semaphore_wait" => {
349 let [sem, timeout] = this.check_shim_sig(
350 shim_sig!(extern "C" fn(*_, u64) -> isize),
351 (link_name, abi, args),
352 )?;
353 this.dispatch_semaphore_wait(sem, timeout, dest)?;
354 }
355 "dispatch_semaphore_signal" => {
356 let [sem] = this.check_shim_sig(
357 shim_sig!(extern "C" fn(*_) -> isize),
358 (link_name, abi, args),
359 )?;
360 this.dispatch_semaphore_signal(sem, dest)?;
361 }
362 "dispatch_release" => {
363 let [sem] = this
364 .check_shim_sig(shim_sig!(extern "C" fn(*_) -> ()), (link_name, abi, args))?;
365 this.dispatch_release(sem)?;
366 }
367 "dispatch_time" => {
368 let [when, delta] = this.check_shim_sig(
369 shim_sig!(extern "C" fn(u64, i64) -> u64),
370 (link_name, abi, args),
371 )?;
372 this.dispatch_time(when, delta, dest)?;
373 }
374
375 "pthread_cond_timedwait_relative_np" => {
376 let [cond, mutex, reltime] =
377 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
378 this.pthread_cond_timedwait(
379 cond, mutex, reltime, dest, true,
380 )?;
381 }
382
383 "confstr" => {
386 let [_key, _buf, _buflen] =
387 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
388 this.set_last_error(LibcError("EINVAL"))?;
390 this.write_null(dest)?;
391 }
392
393 _ => return interp_ok(EmulateItemResult::NotSupported),
394 };
395
396 interp_ok(EmulateItemResult::NeedsReturn)
397 }
398}