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