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