]> git.lizzy.rs Git - rust.git/blob - src/shims/windows/dlsym.rs
Use precomputed layouts.
[rust.git] / src / shims / windows / dlsym.rs
1 use rustc_middle::mir;
2 use rustc_target::abi::Size;
3 use rustc_target::spec::abi::Abi;
4
5 use log::trace;
6
7 use crate::helpers::check_arg_count;
8 use crate::*;
9
10 #[derive(Debug, Copy, Clone)]
11 pub enum Dlsym {
12     NtWriteFile,
13 }
14
15 impl Dlsym {
16     // Returns an error for unsupported symbols, and None if this symbol
17     // should become a NULL pointer (pretend it does not exist).
18     pub fn from_str(name: &str) -> InterpResult<'static, Option<Dlsym>> {
19         Ok(match name {
20             "GetSystemTimePreciseAsFileTime" => None,
21             "NtWriteFile" => Some(Dlsym::NtWriteFile),
22             _ => throw_unsup_format!("unsupported Windows dlsym: {}", name),
23         })
24     }
25 }
26
27 impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
28 pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
29     fn call_dlsym(
30         &mut self,
31         dlsym: Dlsym,
32         abi: Abi,
33         args: &[OpTy<'tcx, Tag>],
34         ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>,
35     ) -> InterpResult<'tcx> {
36         let this = self.eval_context_mut();
37         let (dest, ret) = ret.expect("we don't support any diverging dlsym");
38         assert!(this.tcx.sess.target.os == "windows");
39
40         this.check_abi(abi, Abi::System { unwind: false })?;
41
42         match dlsym {
43             Dlsym::NtWriteFile => {
44                 if !this.frame_in_std() {
45                     throw_unsup_format!(
46                         "NtWriteFile support is crude and just enough for stdout to work"
47                     );
48                 }
49
50                 let [
51                     handle,
52                     _event,
53                     _apc_routine,
54                     _apc_context,
55                     io_status_block,
56                     buf,
57                     n,
58                     byte_offset,
59                     _key,
60                 ] = check_arg_count(args)?;
61                 let handle = this.read_scalar(handle)?.to_machine_isize(this)?;
62                 let buf = this.read_pointer(buf)?;
63                 let n = this.read_scalar(n)?.to_u32()?;
64                 let byte_offset = this.read_scalar(byte_offset)?.to_machine_usize(this)?; // is actually a pointer
65                 let io_status_block = this.deref_operand(io_status_block)?;
66
67                 if byte_offset != 0 {
68                     throw_unsup_format!(
69                         "NtWriteFile ByteOffset paremeter is non-null, which is unsupported"
70                     );
71                 }
72
73                 let written = if handle == -11 || handle == -12 {
74                     // stdout/stderr
75                     use std::io::{self, Write};
76
77                     let buf_cont = this.read_bytes_ptr(buf, Size::from_bytes(u64::from(n)))?;
78                     let res = if this.machine.mute_stdout_stderr {
79                         Ok(buf_cont.len())
80                     } else if handle == -11 {
81                         io::stdout().write(buf_cont)
82                     } else {
83                         io::stderr().write(buf_cont)
84                     };
85                     res.ok().map(|n| n as u32)
86                 } else {
87                     throw_unsup_format!(
88                         "on Windows, writing to anything except stdout/stderr is not supported"
89                     )
90                 };
91                 // We have to put the result into io_status_block.
92                 if let Some(n) = written {
93                     let io_status_information =
94                         this.mplace_field_named(&io_status_block, "Information")?;
95                     this.write_scalar(
96                         Scalar::from_machine_usize(n.into(), this),
97                         &io_status_information.into(),
98                     )?;
99                 }
100                 // Return whether this was a success. >= 0 is success.
101                 // For the error code we arbitrarily pick 0xC0000185, STATUS_IO_DEVICE_ERROR.
102                 this.write_scalar(
103                     Scalar::from_i32(if written.is_some() { 0 } else { 0xC0000185u32 as i32 }),
104                     dest,
105                 )?;
106             }
107         }
108
109         trace!("{:?}", this.dump_place(**dest));
110         this.go_to_block(ret);
111         Ok(())
112     }
113 }