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
84 "_NSGetEnviron" => {
86 let [] = this.check_shim_sig_lenient(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_lenient(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_lenient(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_lenient(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] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
120 let result = this.mach_wait_until(deadline)?;
121 this.write_scalar(result, dest)?;
122 }
123
124 "_NSGetArgc" => {
126 let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
128 this.write_pointer(this.machine.argc.expect("machine must be initialized"), dest)?;
129 }
130 "_NSGetArgv" => {
131 let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
133 this.write_pointer(this.machine.argv.expect("machine must be initialized"), dest)?;
134 }
135 "_NSGetExecutablePath" => {
136 let [buf, bufsize] =
138 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
139 this.check_no_isolation("`_NSGetExecutablePath`")?;
140
141 let buf_ptr = this.read_pointer(buf)?;
142 let bufsize = this.deref_pointer_as(bufsize, this.machine.layouts.u32)?;
143
144 let path = std::env::current_exe().unwrap();
147 let (written, size_needed) = this.write_path_to_c_str(
148 &path,
149 buf_ptr,
150 this.read_scalar(&bufsize)?.to_u32()?.into(),
151 )?;
152
153 if written {
154 this.write_null(dest)?;
155 } else {
156 this.write_scalar(Scalar::from_u32(size_needed.try_into().unwrap()), &bufsize)?;
157 this.write_int(-1, dest)?;
158 }
159 }
160
161 "_tlv_atexit" => {
163 let [dtor, data] =
164 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
165 let dtor = this.read_pointer(dtor)?;
166 let dtor = this.get_ptr_fn(dtor)?.as_instance()?;
167 let data = this.read_scalar(data)?;
168 let active_thread = this.active_thread();
169 this.machine.tls.add_macos_thread_dtor(
170 active_thread,
171 dtor,
172 data,
173 this.machine.current_user_relevant_span(),
174 )?;
175 }
176
177 "pthread_get_stackaddr_np" => {
179 let [thread] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
181 this.read_target_usize(thread)?;
182 let stack_addr = Scalar::from_uint(this.machine.stack_addr, this.pointer_size());
183 this.write_scalar(stack_addr, dest)?;
184 }
185 "pthread_get_stacksize_np" => {
186 let [thread] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
188 this.read_target_usize(thread)?;
189 let stack_size = Scalar::from_uint(this.machine.stack_size, this.pointer_size());
190 this.write_scalar(stack_size, dest)?;
191 }
192
193 "pthread_setname_np" => {
195 let [name] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
196
197 let thread = this.pthread_self()?;
207 let res = match this.pthread_setname_np(
208 thread,
209 this.read_scalar(name)?,
210 this.eval_libc("MAXTHREADNAMESIZE").to_target_usize(this)?,
211 false,
212 )? {
213 ThreadNameResult::Ok => Scalar::from_u32(0),
214 ThreadNameResult::NameTooLong => this.eval_libc("ENAMETOOLONG"),
215 ThreadNameResult::ThreadNotFound => unreachable!(),
216 };
217 this.write_scalar(res, dest)?;
220 }
221 "pthread_getname_np" => {
222 let [thread, name, len] =
223 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
224
225 let res = match this.pthread_getname_np(
234 this.read_scalar(thread)?,
235 this.read_scalar(name)?,
236 this.read_scalar(len)?,
237 true,
238 )? {
239 ThreadNameResult::Ok => Scalar::from_u32(0),
240 ThreadNameResult::NameTooLong => Scalar::from_u32(0),
242 ThreadNameResult::ThreadNotFound => this.eval_libc("ESRCH"),
243 };
244 this.write_scalar(res, dest)?;
245 }
246 "pthread_threadid_np" => {
247 let [thread, tid_ptr] =
248 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
249 let res = this.apple_pthread_threadip_np(thread, tid_ptr)?;
250 this.write_scalar(res, dest)?;
251 }
252
253 "os_sync_wait_on_address" => {
255 let [addr_op, value_op, size_op, flags_op] =
256 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
257 this.os_sync_wait_on_address(
258 addr_op,
259 value_op,
260 size_op,
261 flags_op,
262 MacOsFutexTimeout::None,
263 dest,
264 )?;
265 }
266 "os_sync_wait_on_address_with_deadline" => {
267 let [addr_op, value_op, size_op, flags_op, clock_op, timeout_op] =
268 this.check_shim_sig_lenient(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::Absolute { clock_op, timeout_op },
275 dest,
276 )?;
277 }
278 "os_sync_wait_on_address_with_timeout" => {
279 let [addr_op, value_op, size_op, flags_op, clock_op, timeout_op] =
280 this.check_shim_sig_lenient(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::Relative { clock_op, timeout_op },
287 dest,
288 )?;
289 }
290 "os_sync_wake_by_address_any" => {
291 let [addr_op, size_op, flags_op] =
292 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
293 this.os_sync_wake_by_address(
294 addr_op, size_op, flags_op, false, dest,
295 )?;
296 }
297 "os_sync_wake_by_address_all" => {
298 let [addr_op, size_op, flags_op] =
299 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
300 this.os_sync_wake_by_address(
301 addr_op, size_op, flags_op, true, dest,
302 )?;
303 }
304 "os_unfair_lock_lock" => {
305 let [lock_op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
306 this.os_unfair_lock_lock(lock_op)?;
307 }
308 "os_unfair_lock_trylock" => {
309 let [lock_op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
310 this.os_unfair_lock_trylock(lock_op, dest)?;
311 }
312 "os_unfair_lock_unlock" => {
313 let [lock_op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
314 this.os_unfair_lock_unlock(lock_op)?;
315 }
316 "os_unfair_lock_assert_owner" => {
317 let [lock_op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
318 this.os_unfair_lock_assert_owner(lock_op)?;
319 }
320 "os_unfair_lock_assert_not_owner" => {
321 let [lock_op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
322 this.os_unfair_lock_assert_not_owner(lock_op)?;
323 }
324
325 "pthread_cond_timedwait_relative_np" => {
326 let [cond, mutex, reltime] =
327 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
328 this.pthread_cond_timedwait(
329 cond, mutex, reltime, dest, true,
330 )?;
331 }
332
333 _ => return interp_ok(EmulateItemResult::NotSupported),
334 };
335
336 interp_ok(EmulateItemResult::NeedsReturn)
337 }
338}