2 use rustc_span::Symbol;
3 use rustc_target::spec::abi::Abi;
6 use shims::foreign_items::EmulateByNameResult;
7 use shims::unix::fs::EvalContextExt as _;
8 use shims::unix::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<'mir, 'tcx>> {
20 let this = self.eval_context_mut();
22 match link_name.as_str() {
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)?;
31 "close" | "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(Scalar::from_i32(result), dest)?;
36 "stat" | "stat$INODE64" => {
38 this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
39 let result = this.macos_stat(path, buf)?;
40 this.write_scalar(Scalar::from_i32(result), dest)?;
42 "lstat" | "lstat$INODE64" => {
44 this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
45 let result = this.macos_lstat(path, buf)?;
46 this.write_scalar(Scalar::from_i32(result), dest)?;
48 "fstat" | "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(Scalar::from_i32(result), dest)?;
53 "opendir" | "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)?;
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(Scalar::from_i32(result), dest)?;
66 this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
67 let result = this.ftruncate64(fd, length)?;
68 this.write_scalar(Scalar::from_i32(result), dest)?;
71 // Environment related shims
73 let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
75 this.machine.env_vars.environ.expect("machine must be initialized").ptr,
82 let [tv, tz] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
83 let result = this.gettimeofday(tv, tz)?;
84 this.write_scalar(Scalar::from_i32(result), dest)?;
86 "mach_absolute_time" => {
87 let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
88 let result = this.mach_absolute_time()?;
89 this.write_scalar(Scalar::from_u64(result), dest)?;
92 "mach_timebase_info" => {
93 let [info] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
94 let result = this.mach_timebase_info(info)?;
95 this.write_scalar(Scalar::from_i32(result), dest)?;
98 // Access to command-line arguments
100 let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
102 this.machine.argc.expect("machine must be initialized").ptr,
107 let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
109 this.machine.argv.expect("machine must be initialized").ptr,
114 // Thread-local storage
117 this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
118 let dtor = this.read_pointer(dtor)?;
119 let dtor = this.get_ptr_fn(dtor)?.as_instance()?;
120 let data = this.read_scalar(data)?.check_init()?;
121 let active_thread = this.get_active_thread();
122 this.machine.tls.set_macos_thread_dtor(active_thread, dtor, data)?;
125 // Querying system information
126 "pthread_get_stackaddr_np" => {
127 let [thread] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
128 this.read_scalar(thread)?.to_machine_usize(this)?;
129 let stack_addr = Scalar::from_uint(STACK_ADDR, this.pointer_size());
130 this.write_scalar(stack_addr, dest)?;
132 "pthread_get_stacksize_np" => {
133 let [thread] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
134 this.read_scalar(thread)?.to_machine_usize(this)?;
135 let stack_size = Scalar::from_uint(STACK_SIZE, this.pointer_size());
136 this.write_scalar(stack_size, dest)?;
140 "pthread_setname_np" => {
141 let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
142 let name = this.read_pointer(name)?;
143 this.pthread_setname_np(name)?;
146 // Incomplete shims that we "stub out" just to get pre-main initialization code to work.
147 // These shims are enabled only when the caller is in the standard library.
148 "mmap" if this.frame_in_std() => {
149 // 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.
150 let [addr, _, _, _, _, _] =
151 this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
152 let addr = this.read_scalar(addr)?.check_init()?;
153 this.write_scalar(addr, dest)?;
156 _ => return Ok(EmulateByNameResult::NotSupported),
159 Ok(EmulateByNameResult::NeedsJumping)