2 use rustc_target::spec::abi::Abi;
5 use helpers::check_arg_count;
6 use shims::foreign_items::EmulateByNameResult;
7 use shims::posix::fs::EvalContextExt as _;
8 use shims::posix::thread::EvalContextExt as _;
10 impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
11 pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
12 fn emulate_foreign_item_by_name(
16 args: &[OpTy<'tcx, Tag>],
17 dest: &PlaceTy<'tcx, Tag>,
18 _ret: mir::BasicBlock,
19 ) -> InterpResult<'tcx, EmulateByNameResult> {
20 let this = self.eval_context_mut();
25 this.check_abi(abi, Abi::C { unwind: false })?;
26 let &[] = check_arg_count(args)?;
27 let errno_place = this.last_error_place()?;
28 this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?;
32 "close" | "close$NOCANCEL" => {
33 this.check_abi(abi, Abi::C { unwind: false })?;
34 let &[ref result] = check_arg_count(args)?;
35 let result = this.close(result)?;
36 this.write_scalar(Scalar::from_i32(result), dest)?;
38 "stat" | "stat$INODE64" => {
39 this.check_abi(abi, Abi::C { unwind: false })?;
40 let &[ref path, ref buf] = check_arg_count(args)?;
41 let result = this.macos_stat(path, buf)?;
42 this.write_scalar(Scalar::from_i32(result), dest)?;
44 "lstat" | "lstat$INODE64" => {
45 this.check_abi(abi, Abi::C { unwind: false })?;
46 let &[ref path, ref buf] = check_arg_count(args)?;
47 let result = this.macos_lstat(path, buf)?;
48 this.write_scalar(Scalar::from_i32(result), dest)?;
50 "fstat" | "fstat$INODE64" => {
51 this.check_abi(abi, Abi::C { unwind: false })?;
52 let &[ref fd, ref buf] = check_arg_count(args)?;
53 let result = this.macos_fstat(fd, buf)?;
54 this.write_scalar(Scalar::from_i32(result), dest)?;
56 "opendir" | "opendir$INODE64" => {
57 this.check_abi(abi, Abi::C { unwind: false })?;
58 let &[ref name] = check_arg_count(args)?;
59 let result = this.opendir(name)?;
60 this.write_scalar(result, dest)?;
62 "readdir_r" | "readdir_r$INODE64" => {
63 this.check_abi(abi, Abi::C { unwind: false })?;
64 let &[ref dirp, ref entry, ref result] = check_arg_count(args)?;
65 let result = this.macos_readdir_r(dirp, entry, result)?;
66 this.write_scalar(Scalar::from_i32(result), dest)?;
69 this.check_abi(abi, Abi::C { unwind: false })?;
70 let &[ref fd, ref length] = check_arg_count(args)?;
71 let result = this.ftruncate64(fd, length)?;
72 this.write_scalar(Scalar::from_i32(result), dest)?;
75 // Environment related shims
77 this.check_abi(abi, Abi::C { unwind: false })?;
78 let &[] = check_arg_count(args)?;
79 this.write_scalar(this.machine.env_vars.environ.unwrap().ptr, dest)?;
84 this.check_abi(abi, Abi::C { unwind: false })?;
85 let &[ref tv, ref tz] = check_arg_count(args)?;
86 let result = this.gettimeofday(tv, tz)?;
87 this.write_scalar(Scalar::from_i32(result), dest)?;
89 "mach_absolute_time" => {
90 this.check_abi(abi, Abi::C { unwind: false })?;
91 let &[] = check_arg_count(args)?;
92 let result = this.mach_absolute_time()?;
93 this.write_scalar(Scalar::from_u64(result), dest)?;
96 "mach_timebase_info" => {
97 this.check_abi(abi, Abi::C { unwind: false })?;
98 let &[ref info] = check_arg_count(args)?;
99 let result = this.mach_timebase_info(info)?;
100 this.write_scalar(Scalar::from_i32(result), dest)?;
103 // Access to command-line arguments
105 this.check_abi(abi, Abi::C { unwind: false })?;
106 let &[] = check_arg_count(args)?;
107 this.write_scalar(this.machine.argc.expect("machine must be initialized"), dest)?;
110 this.check_abi(abi, Abi::C { unwind: false })?;
111 let &[] = check_arg_count(args)?;
112 this.write_scalar(this.machine.argv.expect("machine must be initialized"), dest)?;
115 // Thread-local storage
117 this.check_abi(abi, Abi::C { unwind: false })?;
118 let &[ref dtor, ref data] = check_arg_count(args)?;
119 let dtor = this.read_scalar(dtor)?.check_init()?;
120 let dtor = this.memory.get_fn(dtor)?.as_instance()?;
121 let data = this.read_scalar(data)?.check_init()?;
122 let active_thread = this.get_active_thread();
123 this.machine.tls.set_macos_thread_dtor(active_thread, dtor, data)?;
126 // Querying system information
127 "pthread_get_stackaddr_np" => {
128 this.check_abi(abi, Abi::C { unwind: false })?;
129 let &[ref thread] = check_arg_count(args)?;
130 this.read_scalar(thread)?.to_machine_usize(this)?;
131 let stack_addr = Scalar::from_uint(STACK_ADDR, this.pointer_size());
132 this.write_scalar(stack_addr, dest)?;
134 "pthread_get_stacksize_np" => {
135 this.check_abi(abi, Abi::C { unwind: false })?;
136 let &[ref thread] = check_arg_count(args)?;
137 this.read_scalar(thread)?.to_machine_usize(this)?;
138 let stack_size = Scalar::from_uint(STACK_SIZE, this.pointer_size());
139 this.write_scalar(stack_size, dest)?;
143 "pthread_setname_np" => {
144 this.check_abi(abi, Abi::C { unwind: false })?;
145 let &[ref name] = check_arg_count(args)?;
146 let name = this.read_scalar(name)?.check_init()?;
147 this.pthread_setname_np(name)?;
150 // Incomplete shims that we "stub out" just to get pre-main initialization code to work.
151 // These shims are enabled only when the caller is in the standard library.
152 "mmap" if this.frame().instance.to_string().starts_with("std::sys::unix::") => {
153 this.check_abi(abi, Abi::C { unwind: false })?;
154 // 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.
155 let &[ref addr, _, _, _, _, _] = check_arg_count(args)?;
156 let addr = this.read_scalar(addr)?.check_init()?;
157 this.write_scalar(addr, dest)?;
160 _ => return Ok(EmulateByNameResult::NotSupported),
163 Ok(EmulateByNameResult::NeedsJumping)