]> git.lizzy.rs Git - rust.git/blob - src/tools/miri/src/shims/unix/macos/foreign_items.rs
Add 'src/tools/miri/' from commit '75dd959a3a40eb5b4574f8d2e23aa6efbeb33573'
[rust.git] / src / tools / miri / src / shims / unix / macos / foreign_items.rs
1 use rustc_span::Symbol;
2 use rustc_target::spec::abi::Abi;
3
4 use crate::*;
5 use shims::foreign_items::EmulateByNameResult;
6 use shims::unix::fs::EvalContextExt as _;
7 use shims::unix::thread::EvalContextExt as _;
8
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(
12         &mut self,
13         link_name: Symbol,
14         abi: Abi,
15         args: &[OpTy<'tcx, Provenance>],
16         dest: &PlaceTy<'tcx, Provenance>,
17     ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
18         let this = self.eval_context_mut();
19
20         // See `fn emulate_foreign_item_by_name` in `shims/foreign_items.rs` for the general pattern.
21
22         match link_name.as_str() {
23             // errno
24             "__error" => {
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)?;
28             }
29
30             // File related shims
31             "close$NOCANCEL" => {
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)?;
35             }
36             "stat" | "stat64" | "stat$INODE64" => {
37                 let [path, buf] =
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)?;
41             }
42             "lstat" | "lstat64" | "lstat$INODE64" => {
43                 let [path, buf] =
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)?;
47             }
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)?;
52             }
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)?;
57             }
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)?;
63             }
64             "lseek" => {
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)?;
70             }
71             "ftruncate" => {
72                 let [fd, length] =
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)?;
77             }
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)?;
83             }
84
85             // Environment related shims
86             "_NSGetEnviron" => {
87                 let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
88                 this.write_pointer(
89                     this.machine.env_vars.environ.expect("machine must be initialized").ptr,
90                     dest,
91                 )?;
92             }
93
94             // Time related shims
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)?;
99             }
100
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)?;
105             }
106
107             // Access to command-line arguments
108             "_NSGetArgc" => {
109                 let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
110                 this.write_pointer(
111                     this.machine.argc.expect("machine must be initialized").ptr,
112                     dest,
113                 )?;
114             }
115             "_NSGetArgv" => {
116                 let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
117                 this.write_pointer(
118                     this.machine.argv.expect("machine must be initialized").ptr,
119                     dest,
120                 )?;
121             }
122             "_NSGetExecutablePath" => {
123                 let [buf, bufsize] =
124                     this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
125                 this.check_no_isolation("`_NSGetExecutablePath`")?;
126
127                 let buf_ptr = this.read_pointer(buf)?;
128                 let bufsize = this.deref_operand(bufsize)?;
129
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(
134                     &path,
135                     buf_ptr,
136                     this.read_scalar(&bufsize.into())?.to_u32()?.into(),
137                 )?;
138
139                 if written {
140                     this.write_null(dest)?;
141                 } else {
142                     this.write_scalar(
143                         Scalar::from_u32(size_needed.try_into().unwrap()),
144                         &bufsize.into(),
145                     )?;
146                     this.write_int(-1, dest)?;
147                 }
148             }
149
150             // Thread-local storage
151             "_tlv_atexit" => {
152                 let [dtor, data] =
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)?;
159             }
160
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)?;
167             }
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)?;
173             }
174
175             // Threading
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)?)?;
180             }
181
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)?;
190             }
191
192             _ => return Ok(EmulateByNameResult::NotSupported),
193         };
194
195         Ok(EmulateByNameResult::NeedsJumping)
196     }
197 }