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(path_raw, flag, varargs)?;
48 this.write_scalar(result, dest)?;
49 }
50 "pread64" => {
51 let [fd, buf, count, offset] = this.check_shim_sig(
53 shim_sig!(extern "C" fn(i32, *_, usize, libc::off64_t) -> isize),
54 (link_name, abi, args),
55 )?;
56 let fd = this.read_scalar(fd)?.to_i32()?;
57 let buf = this.read_pointer(buf)?;
58 let count = this.read_target_usize(count)?;
59 let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
60 this.read(fd, buf, count, Some(offset), dest)?;
61 }
62 "pwrite64" => {
63 let [fd, buf, n, offset] = this.check_shim_sig(
65 shim_sig!(extern "C" fn(i32, *_, usize, libc::off64_t) -> isize),
66 (link_name, abi, args),
67 )?;
68 let fd = this.read_scalar(fd)?.to_i32()?;
69 let buf = this.read_pointer(buf)?;
70 let count = this.read_target_usize(n)?;
71 let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
72 trace!("Called pwrite64({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset);
73 this.write(fd, buf, count, Some(offset), dest)?;
74 }
75 "lseek64" => {
76 let [fd, offset, whence] = this.check_shim_sig(
78 shim_sig!(extern "C" fn(i32, libc::off64_t, i32) -> libc::off64_t),
79 (link_name, abi, args),
80 )?;
81 let fd = this.read_scalar(fd)?.to_i32()?;
82 let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
83 let whence = this.read_scalar(whence)?.to_i32()?;
84 this.lseek(fd, offset, whence, dest)?;
85 }
86 "ftruncate64" => {
87 let [fd, length] = this.check_shim_sig(
88 shim_sig!(extern "C" fn(i32, libc::off64_t) -> i32),
89 (link_name, abi, args),
90 )?;
91 let fd = this.read_scalar(fd)?.to_i32()?;
92 let length = this.read_scalar(length)?.to_int(length.layout.size)?;
93 let result = this.ftruncate64(fd, length)?;
94 this.write_scalar(result, 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
110 "fallocate" => {
111 let [fd, mode, offset, len] = this.check_shim_sig(
112 shim_sig!(extern "C" fn(i32, i32, libc::off_t, libc::off_t) -> i32),
113 (link_name, abi, args),
114 )?;
115
116 let fd = this.read_scalar(fd)?.to_i32()?;
117 let mode = this.read_scalar(mode)?.to_i32()?;
118 let offset =
120 i64::try_from(this.read_scalar(offset)?.to_int(offset.layout.size)?).unwrap();
121 let len = i64::try_from(this.read_scalar(len)?.to_int(len.layout.size)?).unwrap();
122
123 let result = this.linux_fallocate(fd, mode, offset, len)?;
124 this.write_scalar(result, dest)?;
125 }
126
127 "fallocate64" => {
128 let [fd, mode, offset, len] = this.check_shim_sig(
129 shim_sig!(extern "C" fn(i32, i32, libc::off64_t, libc::off64_t) -> i32),
130 (link_name, abi, args),
131 )?;
132
133 let fd = this.read_scalar(fd)?.to_i32()?;
134 let mode = this.read_scalar(mode)?.to_i32()?;
135 let offset = this.read_scalar(offset)?.to_i64()?;
136 let len = this.read_scalar(len)?.to_i64()?;
137
138 let result = this.linux_fallocate(fd, mode, offset, len)?;
139 this.write_scalar(result, dest)?;
140 }
141
142 "readdir64" => {
143 let [dirp] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
144 this.readdir(dirp, dest)?;
145 }
146 "sync_file_range" => {
147 let [fd, offset, nbytes, flags] =
148 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
149 let result = this.sync_file_range(fd, offset, nbytes, flags)?;
150 this.write_scalar(result, dest)?;
151 }
152 "statx" => {
153 let [dirfd, pathname, flags, mask, statxbuf] =
154 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
155 let result = this.linux_statx(dirfd, pathname, flags, mask, statxbuf)?;
156 this.write_scalar(result, dest)?;
157 }
158 "epoll_create1" => {
160 let [flag] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
161 let result = this.epoll_create1(flag)?;
162 this.write_scalar(result, dest)?;
163 }
164 "epoll_ctl" => {
165 let [epfd, op, fd, event] =
166 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
167 let result = this.epoll_ctl(epfd, op, fd, event)?;
168 this.write_scalar(result, dest)?;
169 }
170 "epoll_wait" => {
171 let [epfd, events, maxevents, timeout] =
172 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
173 this.epoll_wait(epfd, events, maxevents, timeout, dest)?;
174 }
175 "eventfd" => {
176 let [val, flag] =
177 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
178 let result = this.eventfd(val, flag)?;
179 this.write_scalar(result, dest)?;
180 }
181
182 "pthread_setname_np" => {
184 let [thread, name] =
185 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
186 let res = match this.pthread_setname_np(
187 this.read_scalar(thread)?,
188 this.read_scalar(name)?,
189 TASK_COMM_LEN,
190 false,
191 )? {
192 ThreadNameResult::Ok => Scalar::from_u32(0),
193 ThreadNameResult::NameTooLong => this.eval_libc("ERANGE"),
194 ThreadNameResult::ThreadNotFound => this.eval_libc("ENOENT"),
196 };
197 this.write_scalar(res, dest)?;
198 }
199 "pthread_getname_np" => {
200 let [thread, name, len] =
201 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
202 let len = this.read_scalar(len)?;
206 let res = if len.to_target_usize(this)? >= TASK_COMM_LEN {
207 match this.pthread_getname_np(
208 this.read_scalar(thread)?,
209 this.read_scalar(name)?,
210 len,
211 false,
212 )? {
213 ThreadNameResult::Ok => Scalar::from_u32(0),
214 ThreadNameResult::NameTooLong => unreachable!(),
215 ThreadNameResult::ThreadNotFound => this.eval_libc("ENOENT"),
217 }
218 } else {
219 this.eval_libc("ERANGE")
220 };
221 this.write_scalar(res, dest)?;
222 }
223 "gettid" => {
224 let [] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
225 let result = this.unix_gettid(link_name.as_str())?;
226 this.write_scalar(result, dest)?;
227 }
228 "prctl" => prctl(this, link_name, abi, args, dest)?,
229
230 "syscall" => {
232 syscall(this, link_name, abi, args, dest)?;
233 }
234
235 "mmap64" => {
237 let [addr, length, prot, flags, fd, offset] =
238 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
239 let offset = this.read_scalar(offset)?.to_i64()?;
240 let ptr = this.mmap(addr, length, prot, flags, fd, offset.into())?;
241 this.write_scalar(ptr, dest)?;
242 }
243 "mremap" => {
244 let ([old_address, old_size, new_size, flags], _) = this.check_shim_sig_variadic(
245 shim_sig!(extern "C" fn(*_, usize, usize, i32, ...) -> *_),
246 (link_name, abi, args),
247 )?;
248 let ptr = this.mremap(old_address, old_size, new_size, flags)?;
249 this.write_scalar(ptr, dest)?;
250 }
251 "__xpg_strerror_r" => {
252 let [errnum, buf, buflen] =
253 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
254 let result = this.strerror_r(errnum, buf, buflen)?;
255 this.write_scalar(result, dest)?;
256 }
257 "__errno_location" => {
258 let [] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
259 let errno_place = this.last_error_place()?;
260 this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
261 }
262 "__libc_current_sigrtmin" => {
263 let [] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
264
265 this.write_int(SIGRTMIN, dest)?;
266 }
267 "__libc_current_sigrtmax" => {
268 let [] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
269
270 this.write_int(SIGRTMAX, dest)?;
271 }
272
273 "pthread_getattr_np" if this.frame_in_std() => {
276 let [_thread, _attr] =
277 this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
278 this.write_null(dest)?;
279 }
280 "gnu_get_libc_version"
281 if this.frame_in_std()
282 && this.tcx.sess.target.env == rustc_target::spec::Env::Gnu =>
283 {
284 let [] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?;
285 let version = "2.26\0";
288 let version = this.allocate_str_dedup(version)?;
289 this.write_pointer(version.ptr(), dest)?;
290 }
291
292 _ => return interp_ok(EmulateItemResult::NotSupported),
293 };
294
295 interp_ok(EmulateItemResult::NeedsReturn)
296 }
297}