1use rustc_abi::CanonAbi;
2use rustc_middle::ty::Ty;
3use rustc_span::Symbol;
4use rustc_target::callconv::FnAbi;
5
6use self::shims::unix::linux::mem::EvalContextExt as _;
7use self::shims::unix::linux_like::eventfd::EvalContextExt as _;
8use self::shims::unix::linux_like::syscall::syscall;
9use crate::machine::{SIGRTMAX, SIGRTMIN};
10use crate::shims::unix::foreign_items::EvalContextExt as _;
11use crate::shims::unix::linux_like::epoll::EvalContextExt as _;
12use crate::shims::unix::linux_like::thread::prctl;
13use crate::shims::unix::*;
14use crate::*;
15
16const TASK_COMM_LEN: u64 = 16;
20
21pub fn is_dyn_sym(name: &str) -> bool {
22 matches!(name, "gettid" | "statx")
23}
24
25impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
26pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
27 fn emulate_foreign_item_inner(
28 &mut self,
29 link_name: Symbol,
30 abi: &FnAbi<'tcx, Ty<'tcx>>,
31 args: &[OpTy<'tcx>],
32 dest: &MPlaceTy<'tcx>,
33 ) -> InterpResult<'tcx, EmulateItemResult> {
34 let this = self.eval_context_mut();
35
36 match link_name.as_str() {
39 "open64" => {
41 let ([path_raw, flag], varargs) = this.check_shim_sig_variadic(
44 shim_sig!(extern "C" fn(*_, i32, ...) -> i32),
45 (link_name, abi, args),
46 )?;
47 let result = this.open(None, path_raw, flag, varargs)?;
48 this.write_scalar(result, dest)?;
49 }
50 "openat64" => {
51 let ([dirfd, path_raw, flag], varargs) = this.check_shim_sig_variadic(
54 shim_sig!(extern "C" fn(i32, *_, i32, ...) -> i32),
55 (link_name, abi, args),
56 )?;
57 let result = this.open(Some(dirfd), path_raw, flag, varargs)?;
58 this.write_scalar(result, dest)?;
59 }
60 "pread64" => {
61 let [fd, buf, count, offset] = this.check_shim_sig(
63 shim_sig!(extern "C" fn(i32, *_, usize, libc::off64_t) -> isize),
64 (link_name, abi, args),
65 )?;
66 let fd = this.read_scalar(fd)?.to_i32()?;
67 let buf = this.read_pointer(buf)?;
68 let count = this.read_target_usize(count)?;
69 let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
70 this.read(fd, buf, count, Some(offset), dest)?;
71 }
72 "pwrite64" => {
73 let [fd, buf, n, offset] = this.check_shim_sig(
75 shim_sig!(extern "C" fn(i32, *_, usize, libc::off64_t) -> isize),
76 (link_name, abi, args),
77 )?;
78 let fd = this.read_scalar(fd)?.to_i32()?;
79 let buf = this.read_pointer(buf)?;
80 let count = this.read_target_usize(n)?;
81 let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
82 trace!("Called pwrite64({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset);
83 this.write(fd, buf, count, Some(offset), dest)?;
84 }
85 "lseek64" => {
86 let [fd, offset, whence] = this.check_shim_sig(
88 shim_sig!(extern "C" fn(i32, libc::off64_t, i32) -> libc::off64_t),
89 (link_name, abi, args),
90 )?;
91 let fd = this.read_scalar(fd)?.to_i32()?;
92 let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
93 let whence = this.read_scalar(whence)?.to_i32()?;
94 this.lseek(fd, offset, whence, dest)?;
95 }
96 "posix_fallocate64" => {
97 let [fd, offset, len] = this.check_shim_sig(
98 shim_sig!(extern "C" fn(i32, libc::off64_t, libc::off64_t) -> i32),
99 (link_name, abi, args),
100 )?;
101
102 let fd = this.read_scalar(fd)?.to_i32()?;
103 let offset = this.read_scalar(offset)?.to_i64()?;
104 let len = this.read_scalar(len)?.to_i64()?;
105
106 let result = this.posix_fallocate(fd, offset, len)?;
107 this.write_scalar(result, dest)?;
108 }
109 "fallocate" => {
110 let [fd, mode, offset, len] = this.check_shim_sig(
111 shim_sig!(extern "C" fn(i32, i32, libc::off_t, libc::off_t) -> i32),
112 (link_name, abi, args),
113 )?;
114
115 let fd = this.read_scalar(fd)?.to_i32()?;
116 let mode = this.read_scalar(mode)?.to_i32()?;
117 let offset =
119 i64::try_from(this.read_scalar(offset)?.to_int(offset.layout.size)?).unwrap();
120 let len = i64::try_from(this.read_scalar(len)?.to_int(len.layout.size)?).unwrap();
121
122 let result = this.linux_fallocate(fd, mode, offset, len)?;
123 this.write_scalar(result, dest)?;
124 }
125 "fallocate64" => {
126 let [fd, mode, offset, len] = this.check_shim_sig(
127 shim_sig!(extern "C" fn(i32, i32, libc::off64_t, libc::off64_t) -> i32),
128 (link_name, abi, args),
129 )?;
130
131 let fd = this.read_scalar(fd)?.to_i32()?;
132 let mode = this.read_scalar(mode)?.to_i32()?;
133 let offset = this.read_scalar(offset)?.to_i64()?;
134 let len = this.read_scalar(len)?.to_i64()?;
135
136 let result = this.linux_fallocate(fd, mode, offset, len)?;
137 this.write_scalar(result, dest)?;
138 }
139 "ftruncate64" => {
140 let [fd, length] = this.check_shim_sig(
141 shim_sig!(extern "C" fn(i32, libc::off64_t) -> i32),
142 (link_name, abi, args),
143 )?;
144 let fd = this.read_scalar(fd)?.to_i32()?;
145 let length = this.read_scalar(length)?.to_int(length.layout.size)?;
146 let result = this.ftruncate64(fd, length)?;
147 this.write_scalar(result, dest)?;
148 }
149 "sync_file_range" => {
150 let [fd, offset, nbytes, flags] =
151 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
152 let result = this.sync_file_range(fd, offset, nbytes, flags)?;
153 this.write_scalar(result, dest)?;
154 }
155 "statx" => {
156 let [dirfd, pathname, flags, mask, statxbuf] =
157 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
158 let result = this.linux_statx(dirfd, pathname, flags, mask, statxbuf)?;
159 this.write_scalar(result, dest)?;
160 }
161 "fstat64" => {
162 let [fd, buf] = this.check_shim_sig(
163 shim_sig!(extern "C" fn(i32, *_) -> i32),
164 (link_name, abi, args),
165 )?;
166 let result = this.fstat(fd, buf, "stat64")?;
167 this.write_scalar(result, dest)?;
168 }
169 "readdir64" => {
170 let [dirp] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
171 this.readdir(dirp, dest, "dirent64")?;
172 }
173
174 "epoll_create1" => {
176 let [flag] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
177 let result = this.epoll_create1(flag)?;
178 this.write_scalar(result, dest)?;
179 }
180 "epoll_ctl" => {
181 let [epfd, op, fd, event] =
182 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
183 let result = this.epoll_ctl(epfd, op, fd, event)?;
184 this.write_scalar(result, dest)?;
185 }
186 "epoll_wait" => {
187 let [epfd, events, maxevents, timeout] =
188 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
189 this.epoll_wait(epfd, events, maxevents, timeout, dest)?;
190 }
191 "eventfd" => {
192 let [val, flag] =
193 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
194 let result = this.eventfd(val, flag)?;
195 this.write_scalar(result, dest)?;
196 }
197
198 "pthread_setname_np" => {
200 let [thread, name] =
201 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
202 let res = match this.pthread_setname_np(
203 this.read_scalar(thread)?,
204 this.read_scalar(name)?,
205 TASK_COMM_LEN,
206 false,
207 )? {
208 ThreadNameResult::Ok => Scalar::from_u32(0),
209 ThreadNameResult::NameTooLong => this.eval_libc("ERANGE"),
210 };
211 this.write_scalar(res, dest)?;
212 }
213 "pthread_getname_np" => {
214 let [thread, name, len] =
215 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
216 let len = this.read_scalar(len)?;
220 let res = if len.to_target_usize(this)? >= TASK_COMM_LEN {
221 match this.pthread_getname_np(
222 this.read_scalar(thread)?,
223 this.read_scalar(name)?,
224 len,
225 false,
226 )? {
227 ThreadNameResult::Ok => Scalar::from_u32(0),
228 ThreadNameResult::NameTooLong => unreachable!(),
229 }
230 } else {
231 this.eval_libc("ERANGE")
232 };
233 this.write_scalar(res, dest)?;
234 }
235 "gettid" => {
236 let [] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
237 let result = this.unix_gettid(link_name.as_str())?;
238 this.write_scalar(result, dest)?;
239 }
240 "prctl" => prctl(this, link_name, abi, args, dest)?,
241
242 "syscall" => {
244 syscall(this, link_name, abi, args, dest)?;
245 }
246
247 "mmap64" => {
249 let [addr, length, prot, flags, fd, offset] =
250 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
251 let offset = this.read_scalar(offset)?.to_i64()?;
252 let ptr = this.mmap(addr, length, prot, flags, fd, offset.into())?;
253 this.write_scalar(ptr, dest)?;
254 }
255 "mremap" => {
256 let ([old_address, old_size, new_size, flags], _) = this.check_shim_sig_variadic(
257 shim_sig!(extern "C" fn(*_, usize, usize, i32, ...) -> *_),
258 (link_name, abi, args),
259 )?;
260 let ptr = this.mremap(old_address, old_size, new_size, flags)?;
261 this.write_scalar(ptr, dest)?;
262 }
263 "__xpg_strerror_r" => {
264 let [errnum, buf, buflen] =
265 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
266 let result = this.strerror_r(errnum, buf, buflen)?;
267 this.write_scalar(result, dest)?;
268 }
269 "__errno_location" => {
270 let [] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
271 let errno_place = this.last_error_place()?;
272 this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
273 }
274 "__libc_current_sigrtmin" => {
275 let [] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
276
277 this.write_int(SIGRTMIN, dest)?;
278 }
279 "__libc_current_sigrtmax" => {
280 let [] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
281
282 this.write_int(SIGRTMAX, dest)?;
283 }
284
285 "pthread_getattr_np" if this.frame_in_std() => {
288 let [_thread, _attr] =
289 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
290 this.write_null(dest)?;
291 }
292 "gnu_get_libc_version"
293 if this.frame_in_std()
294 && this.tcx.sess.target.env == rustc_target::spec::Env::Gnu =>
295 {
296 let [] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
297 let version = "2.26\0";
300 let version = this.allocate_str_dedup(version)?;
301 this.write_pointer(version.ptr(), dest)?;
302 }
303
304 _ => return interp_ok(EmulateItemResult::NotSupported),
305 };
306
307 interp_ok(EmulateItemResult::NeedsReturn)
308 }
309}