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 [fd] = this.check_shim_sig_lenient(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] = 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$INODE64" => {
56 let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
57 let result = this.lstat(path, buf)?;
58 this.write_scalar(result, dest)?;
59 }
60 "fstat$INODE64" => {
61 let [fd, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
62 let result = this.fstat(fd, buf)?;
63 this.write_scalar(result, dest)?;
64 }
65 "opendir$INODE64" => {
66 let [name] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
67 let result = this.opendir(name)?;
68 this.write_scalar(result, dest)?;
69 }
70 "readdir$INODE64" => {
71 let [dirp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
72 this.readdir(dirp, dest)?;
73 }
74 "realpath$DARWIN_EXTSN" => {
75 let [path, resolved_path] =
76 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
77 let result = this.realpath(path, resolved_path)?;
78 this.write_scalar(result, dest)?;
79 }
80
81 "_NSGetEnviron" => {
83 let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
85 let environ = this.machine.env_vars.unix().environ();
86 this.write_pointer(environ, dest)?;
87 }
88
89 "CCRandomGenerateBytes" => {
91 let [bytes, count] =
92 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
93 let bytes = this.read_pointer(bytes)?;
94 let count = this.read_target_usize(count)?;
95 let success = this.eval_libc_i32("kCCSuccess");
96 this.gen_random(bytes, count)?;
97 this.write_int(success, dest)?;
98 }
99
100 "mach_absolute_time" => {
102 let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
103 let result = this.mach_absolute_time()?;
104 this.write_scalar(result, dest)?;
105 }
106
107 "mach_timebase_info" => {
108 let [info] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
110 let result = this.mach_timebase_info(info)?;
111 this.write_scalar(result, dest)?;
112 }
113
114 "mach_wait_until" => {
115 let [deadline] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
117 let result = this.mach_wait_until(deadline)?;
118 this.write_scalar(result, dest)?;
119 }
120
121 "_NSGetArgc" => {
123 let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
125 this.write_pointer(this.machine.argc.expect("machine must be initialized"), dest)?;
126 }
127 "_NSGetArgv" => {
128 let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
130 this.write_pointer(this.machine.argv.expect("machine must be initialized"), dest)?;
131 }
132 "_NSGetExecutablePath" => {
133 let [buf, bufsize] =
135 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
136 this.check_no_isolation("`_NSGetExecutablePath`")?;
137
138 let buf_ptr = this.read_pointer(buf)?;
139 let bufsize = this.deref_pointer_as(bufsize, this.machine.layouts.u32)?;
140
141 let path = std::env::current_exe().unwrap();
144 let (written, size_needed) = this.write_path_to_c_str(
145 &path,
146 buf_ptr,
147 this.read_scalar(&bufsize)?.to_u32()?.into(),
148 )?;
149
150 if written {
151 this.write_null(dest)?;
152 } else {
153 this.write_scalar(Scalar::from_u32(size_needed.try_into().unwrap()), &bufsize)?;
154 this.write_int(-1, dest)?;
155 }
156 }
157
158 "_tlv_atexit" => {
160 let [dtor, data] =
161 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
162 let dtor = this.read_pointer(dtor)?;
163 let dtor = this.get_ptr_fn(dtor)?.as_instance()?;
164 let data = this.read_scalar(data)?;
165 let active_thread = this.active_thread();
166 this.machine.tls.add_macos_thread_dtor(
167 active_thread,
168 dtor,
169 data,
170 this.machine.current_user_relevant_span(),
171 )?;
172 }
173
174 "pthread_get_stackaddr_np" => {
176 let [thread] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
178 this.read_target_usize(thread)?;
179 let stack_addr = Scalar::from_uint(this.machine.stack_addr, this.pointer_size());
180 this.write_scalar(stack_addr, dest)?;
181 }
182 "pthread_get_stacksize_np" => {
183 let [thread] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
185 this.read_target_usize(thread)?;
186 let stack_size = Scalar::from_uint(this.machine.stack_size, this.pointer_size());
187 this.write_scalar(stack_size, dest)?;
188 }
189
190 "pthread_setname_np" => {
192 let [name] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
193
194 let thread = this.pthread_self()?;
204 let res = match this.pthread_setname_np(
205 thread,
206 this.read_scalar(name)?,
207 this.eval_libc("MAXTHREADNAMESIZE").to_target_usize(this)?,
208 false,
209 )? {
210 ThreadNameResult::Ok => Scalar::from_u32(0),
211 ThreadNameResult::NameTooLong => this.eval_libc("ENAMETOOLONG"),
212 ThreadNameResult::ThreadNotFound => unreachable!(),
213 };
214 this.write_scalar(res, dest)?;
217 }
218 "pthread_getname_np" => {
219 let [thread, name, len] =
220 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
221
222 let res = match this.pthread_getname_np(
231 this.read_scalar(thread)?,
232 this.read_scalar(name)?,
233 this.read_scalar(len)?,
234 true,
235 )? {
236 ThreadNameResult::Ok => Scalar::from_u32(0),
237 ThreadNameResult::NameTooLong => Scalar::from_u32(0),
239 ThreadNameResult::ThreadNotFound => this.eval_libc("ESRCH"),
240 };
241 this.write_scalar(res, dest)?;
242 }
243 "pthread_threadid_np" => {
244 let [thread, tid_ptr] =
245 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
246 let res = this.apple_pthread_threadid_np(thread, tid_ptr)?;
247 this.write_scalar(res, dest)?;
248 }
249
250 "os_sync_wait_on_address" => {
252 let [addr_op, value_op, size_op, flags_op] =
253 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
254 this.os_sync_wait_on_address(
255 addr_op,
256 value_op,
257 size_op,
258 flags_op,
259 MacOsFutexTimeout::None,
260 dest,
261 )?;
262 }
263 "os_sync_wait_on_address_with_deadline" => {
264 let [addr_op, value_op, size_op, flags_op, clock_op, timeout_op] =
265 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
266 this.os_sync_wait_on_address(
267 addr_op,
268 value_op,
269 size_op,
270 flags_op,
271 MacOsFutexTimeout::Absolute { clock_op, timeout_op },
272 dest,
273 )?;
274 }
275 "os_sync_wait_on_address_with_timeout" => {
276 let [addr_op, value_op, size_op, flags_op, clock_op, timeout_op] =
277 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
278 this.os_sync_wait_on_address(
279 addr_op,
280 value_op,
281 size_op,
282 flags_op,
283 MacOsFutexTimeout::Relative { clock_op, timeout_op },
284 dest,
285 )?;
286 }
287 "os_sync_wake_by_address_any" => {
288 let [addr_op, size_op, flags_op] =
289 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
290 this.os_sync_wake_by_address(
291 addr_op, size_op, flags_op, false, dest,
292 )?;
293 }
294 "os_sync_wake_by_address_all" => {
295 let [addr_op, size_op, flags_op] =
296 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
297 this.os_sync_wake_by_address(
298 addr_op, size_op, flags_op, true, dest,
299 )?;
300 }
301 "os_unfair_lock_lock" => {
302 let [lock_op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
303 this.os_unfair_lock_lock(lock_op)?;
304 }
305 "os_unfair_lock_trylock" => {
306 let [lock_op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
307 this.os_unfair_lock_trylock(lock_op, dest)?;
308 }
309 "os_unfair_lock_unlock" => {
310 let [lock_op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
311 this.os_unfair_lock_unlock(lock_op)?;
312 }
313 "os_unfair_lock_assert_owner" => {
314 let [lock_op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
315 this.os_unfair_lock_assert_owner(lock_op)?;
316 }
317 "os_unfair_lock_assert_not_owner" => {
318 let [lock_op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
319 this.os_unfair_lock_assert_not_owner(lock_op)?;
320 }
321
322 "pthread_cond_timedwait_relative_np" => {
323 let [cond, mutex, reltime] =
324 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
325 this.pthread_cond_timedwait(
326 cond, mutex, reltime, dest, true,
327 )?;
328 }
329
330 "confstr" => {
333 let [_key, _buf, _buflen] =
334 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
335 this.set_last_error(LibcError("EINVAL"))?;
337 this.write_null(dest)?;
338 }
339
340 _ => return interp_ok(EmulateItemResult::NotSupported),
341 };
342
343 interp_ok(EmulateItemResult::NeedsReturn)
344 }
345}