1 use rustc_span::Symbol;
2 use rustc_target::spec::abi::Abi;
5 use shims::foreign_items::EmulateByNameResult;
6 use shims::unix::fs::EvalContextExt as _;
7 use shims::unix::thread::EvalContextExt as _;
9 impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
10 pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
11 fn emulate_foreign_item_by_name(
15 args: &[OpTy<'tcx, Provenance>],
16 dest: &PlaceTy<'tcx, Provenance>,
17 ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
18 let this = self.eval_context_mut();
20 // See `fn emulate_foreign_item_by_name` in `shims/foreign_items.rs` for the general pattern.
22 match link_name.as_str() {
25 let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
26 let errno_place = this.last_error_place()?;
27 this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
32 let [result] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
33 let result = this.close(result)?;
34 this.write_scalar(result, dest)?;
36 "stat" | "stat64" | "stat$INODE64" => {
38 this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
39 let result = this.macos_stat(path, buf)?;
40 this.write_scalar(result, dest)?;
42 "lstat" | "lstat64" | "lstat$INODE64" => {
44 this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
45 let result = this.macos_lstat(path, buf)?;
46 this.write_scalar(result, dest)?;
48 "fstat" | "fstat64" | "fstat$INODE64" => {
49 let [fd, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
50 let result = this.macos_fstat(fd, buf)?;
51 this.write_scalar(result, dest)?;
53 "opendir$INODE64" => {
54 let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
55 let result = this.opendir(name)?;
56 this.write_scalar(result, dest)?;
58 "readdir_r" | "readdir_r$INODE64" => {
59 let [dirp, entry, result] =
60 this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
61 let result = this.macos_readdir_r(dirp, entry, result)?;
62 this.write_scalar(result, dest)?;
65 let [fd, offset, whence] =
66 this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
67 // macOS is 64bit-only, so this is lseek64
68 let result = this.lseek64(fd, offset, whence)?;
69 this.write_scalar(result, dest)?;
73 this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
74 // macOS is 64bit-only, so this is ftruncate64
75 let result = this.ftruncate64(fd, length)?;
76 this.write_scalar(result, dest)?;
78 "realpath$DARWIN_EXTSN" => {
79 let [path, resolved_path] =
80 this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
81 let result = this.realpath(path, resolved_path)?;
82 this.write_scalar(result, dest)?;
85 // Environment related shims
87 let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
89 this.machine.env_vars.environ.expect("machine must be initialized").ptr,
95 "mach_absolute_time" => {
96 let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
97 let result = this.mach_absolute_time()?;
98 this.write_scalar(result, dest)?;
101 "mach_timebase_info" => {
102 let [info] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
103 let result = this.mach_timebase_info(info)?;
104 this.write_scalar(result, dest)?;
107 // Access to command-line arguments
109 let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
111 this.machine.argc.expect("machine must be initialized").ptr,
116 let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
118 this.machine.argv.expect("machine must be initialized").ptr,
122 "_NSGetExecutablePath" => {
124 this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
125 this.check_no_isolation("`_NSGetExecutablePath`")?;
127 let buf_ptr = this.read_pointer(buf)?;
128 let bufsize = this.deref_operand(bufsize)?;
130 // Using the host current_exe is a bit off, but consistent with Linux
131 // (where stdlib reads /proc/self/exe).
132 let path = std::env::current_exe().unwrap();
133 let (written, size_needed) = this.write_path_to_c_str(
136 this.read_scalar(&bufsize.into())?.to_u32()?.into(),
140 this.write_null(dest)?;
143 Scalar::from_u32(size_needed.try_into().unwrap()),
146 this.write_int(-1, dest)?;
150 // Thread-local storage
153 this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
154 let dtor = this.read_pointer(dtor)?;
155 let dtor = this.get_ptr_fn(dtor)?.as_instance()?;
156 let data = this.read_scalar(data)?;
157 let active_thread = this.get_active_thread();
158 this.machine.tls.set_macos_thread_dtor(active_thread, dtor, data)?;
161 // Querying system information
162 "pthread_get_stackaddr_np" => {
163 let [thread] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
164 this.read_scalar(thread)?.to_machine_usize(this)?;
165 let stack_addr = Scalar::from_uint(STACK_ADDR, this.pointer_size());
166 this.write_scalar(stack_addr, dest)?;
168 "pthread_get_stacksize_np" => {
169 let [thread] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
170 this.read_scalar(thread)?.to_machine_usize(this)?;
171 let stack_size = Scalar::from_uint(STACK_SIZE, this.pointer_size());
172 this.write_scalar(stack_size, dest)?;
176 "pthread_setname_np" => {
177 let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
178 let thread = this.pthread_self()?;
179 this.pthread_setname_np(thread, this.read_scalar(name)?)?;
182 // Incomplete shims that we "stub out" just to get pre-main initialization code to work.
183 // These shims are enabled only when the caller is in the standard library.
184 "mmap" if this.frame_in_std() => {
185 // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value.
186 let [addr, _, _, _, _, _] =
187 this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
188 let addr = this.read_scalar(addr)?;
189 this.write_scalar(addr, dest)?;
192 _ => return Ok(EmulateByNameResult::NotSupported),
195 Ok(EmulateByNameResult::NeedsJumping)