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::epoll::EvalContextExt as _;
8use self::shims::unix::linux_like::eventfd::EvalContextExt as _;
9use self::shims::unix::linux_like::syscall::syscall;
10use crate::machine::{SIGRTMAX, SIGRTMIN};
11use crate::shims::unix::foreign_items::EvalContextExt as _;
12use crate::shims::unix::*;
13use crate::*;
14
15const TASK_COMM_LEN: u64 = 16;
19
20pub fn is_dyn_sym(name: &str) -> bool {
21 matches!(name, "gettid" | "statx")
22}
23
24impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
25pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
26 fn emulate_foreign_item_inner(
27 &mut self,
28 link_name: Symbol,
29 abi: &FnAbi<'tcx, Ty<'tcx>>,
30 args: &[OpTy<'tcx>],
31 dest: &MPlaceTy<'tcx>,
32 ) -> InterpResult<'tcx, EmulateItemResult> {
33 let this = self.eval_context_mut();
34
35 match link_name.as_str() {
38 "open64" => {
40 let ([path_raw, flag], varargs) =
43 this.check_shim_sig_variadic_lenient(abi, CanonAbi::C, link_name, args)?;
44 let result = this.open(path_raw, flag, varargs)?;
45 this.write_scalar(result, dest)?;
46 }
47 "pread64" => {
48 let [fd, buf, count, offset] = this.check_shim_sig(
49 shim_sig!(extern "C" fn(i32, *mut _, usize, libc::off64_t) -> isize),
50 link_name,
51 abi,
52 args,
53 )?;
54 let fd = this.read_scalar(fd)?.to_i32()?;
55 let buf = this.read_pointer(buf)?;
56 let count = this.read_target_usize(count)?;
57 let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
58 this.read(fd, buf, count, Some(offset), dest)?;
59 }
60 "pwrite64" => {
61 let [fd, buf, n, offset] = this.check_shim_sig(
62 shim_sig!(extern "C" fn(i32, *const _, usize, libc::off64_t) -> isize),
63 link_name,
64 abi,
65 args,
66 )?;
67 let fd = this.read_scalar(fd)?.to_i32()?;
68 let buf = this.read_pointer(buf)?;
69 let count = this.read_target_usize(n)?;
70 let offset = this.read_scalar(offset)?.to_int(offset.layout.size)?;
71 trace!("Called pwrite64({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset);
72 this.write(fd, buf, count, Some(offset), dest)?;
73 }
74 "lseek64" => {
75 let [fd, offset, whence] = this.check_shim_sig(
76 shim_sig!(extern "C" fn(i32, libc::off64_t, i32) -> libc::off64_t),
77 link_name,
78 abi,
79 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.lseek64(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,
90 abi,
91 args,
92 )?;
93 let fd = this.read_scalar(fd)?.to_i32()?;
94 let length = this.read_scalar(length)?.to_int(length.layout.size)?;
95 let result = this.ftruncate64(fd, length)?;
96 this.write_scalar(result, dest)?;
97 }
98 "posix_fallocate64" => {
99 let [fd, offset, len] = this.check_shim_sig(
100 shim_sig!(extern "C" fn(i32, libc::off64_t, libc::off64_t) -> i32),
101 link_name,
102 abi,
103 args,
104 )?;
105
106 let fd = this.read_scalar(fd)?.to_i32()?;
107 let offset = this.read_scalar(offset)?.to_i64()?;
108 let len = this.read_scalar(len)?.to_i64()?;
109
110 let result = this.posix_fallocate(fd, offset, len)?;
111 this.write_scalar(result, dest)?;
112 }
113 "readdir64" => {
114 let [dirp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
115 let result = this.readdir64("dirent64", dirp)?;
116 this.write_scalar(result, dest)?;
117 }
118 "sync_file_range" => {
119 let [fd, offset, nbytes, flags] =
120 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
121 let result = this.sync_file_range(fd, offset, nbytes, flags)?;
122 this.write_scalar(result, dest)?;
123 }
124 "statx" => {
125 let [dirfd, pathname, flags, mask, statxbuf] =
126 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
127 let result = this.linux_statx(dirfd, pathname, flags, mask, statxbuf)?;
128 this.write_scalar(result, dest)?;
129 }
130 "epoll_create1" => {
132 let [flag] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
133 let result = this.epoll_create1(flag)?;
134 this.write_scalar(result, dest)?;
135 }
136 "epoll_ctl" => {
137 let [epfd, op, fd, event] =
138 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
139 let result = this.epoll_ctl(epfd, op, fd, event)?;
140 this.write_scalar(result, dest)?;
141 }
142 "epoll_wait" => {
143 let [epfd, events, maxevents, timeout] =
144 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
145 this.epoll_wait(epfd, events, maxevents, timeout, dest)?;
146 }
147 "eventfd" => {
148 let [val, flag] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
149 let result = this.eventfd(val, flag)?;
150 this.write_scalar(result, dest)?;
151 }
152
153 "pthread_setname_np" => {
155 let [thread, name] =
156 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
157 let res = match this.pthread_setname_np(
158 this.read_scalar(thread)?,
159 this.read_scalar(name)?,
160 TASK_COMM_LEN,
161 false,
162 )? {
163 ThreadNameResult::Ok => Scalar::from_u32(0),
164 ThreadNameResult::NameTooLong => this.eval_libc("ERANGE"),
165 ThreadNameResult::ThreadNotFound => this.eval_libc("ENOENT"),
167 };
168 this.write_scalar(res, dest)?;
169 }
170 "pthread_getname_np" => {
171 let [thread, name, len] =
172 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
173 let len = this.read_scalar(len)?;
177 let res = if len.to_target_usize(this)? >= TASK_COMM_LEN {
178 match this.pthread_getname_np(
179 this.read_scalar(thread)?,
180 this.read_scalar(name)?,
181 len,
182 false,
183 )? {
184 ThreadNameResult::Ok => Scalar::from_u32(0),
185 ThreadNameResult::NameTooLong => unreachable!(),
186 ThreadNameResult::ThreadNotFound => this.eval_libc("ENOENT"),
188 }
189 } else {
190 this.eval_libc("ERANGE")
191 };
192 this.write_scalar(res, dest)?;
193 }
194 "gettid" => {
195 let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
196 let result = this.unix_gettid(link_name.as_str())?;
197 this.write_scalar(result, dest)?;
198 }
199
200 "syscall" => {
202 syscall(this, link_name, abi, args, dest)?;
203 }
204
205 "mmap64" => {
207 let [addr, length, prot, flags, fd, offset] =
208 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
209 let offset = this.read_scalar(offset)?.to_i64()?;
210 let ptr = this.mmap(addr, length, prot, flags, fd, offset.into())?;
211 this.write_scalar(ptr, dest)?;
212 }
213 "mremap" => {
214 let ([old_address, old_size, new_size, flags], _) =
215 this.check_shim_sig_variadic_lenient(abi, CanonAbi::C, link_name, args)?;
216 let ptr = this.mremap(old_address, old_size, new_size, flags)?;
217 this.write_scalar(ptr, dest)?;
218 }
219 "__xpg_strerror_r" => {
220 let [errnum, buf, buflen] =
221 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
222 let result = this.strerror_r(errnum, buf, buflen)?;
223 this.write_scalar(result, dest)?;
224 }
225 "__errno_location" => {
226 let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
227 let errno_place = this.last_error_place()?;
228 this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
229 }
230 "__libc_current_sigrtmin" => {
231 let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
232
233 this.write_int(SIGRTMIN, dest)?;
234 }
235 "__libc_current_sigrtmax" => {
236 let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
237
238 this.write_int(SIGRTMAX, dest)?;
239 }
240
241 "pthread_getattr_np" if this.frame_in_std() => {
244 let [_thread, _attr] =
245 this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
246 this.write_null(dest)?;
247 }
248
249 _ => return interp_ok(EmulateItemResult::NotSupported),
250 };
251
252 interp_ok(EmulateItemResult::NeedsReturn)
253 }
254}