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