]> git.lizzy.rs Git - rust.git/blob - src/shims/windows/dlsym.rs
Auto merge of #2165 - saethlin:more-clocks, r=RalfJung
[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<'tcx>(name: &str) -> InterpResult<'tcx, 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         dest: &PlaceTy<'tcx, Tag>,
35         ret: Option<mir::BasicBlock>,
36     ) -> InterpResult<'tcx> {
37         let this = self.eval_context_mut();
38         let ret = ret.expect("we don't support any diverging dlsym");
39         assert!(this.tcx.sess.target.os == "windows");
40
41         this.check_abi(abi, Abi::System { unwind: false })?;
42
43         match dlsym {
44             Dlsym::NtWriteFile => {
45                 if !this.frame_in_std() {
46                     throw_unsup_format!(
47                         "NtWriteFile support is crude and just enough for stdout to work"
48                     );
49                 }
50
51                 let [
52                     handle,
53                     _event,
54                     _apc_routine,
55                     _apc_context,
56                     io_status_block,
57                     buf,
58                     n,
59                     byte_offset,
60                     _key,
61                 ] = check_arg_count(args)?;
62                 let handle = this.read_scalar(handle)?.to_machine_isize(this)?;
63                 let buf = this.read_pointer(buf)?;
64                 let n = this.read_scalar(n)?.to_u32()?;
65                 let byte_offset = this.read_scalar(byte_offset)?.to_machine_usize(this)?; // is actually a pointer
66                 let io_status_block = this.deref_operand(io_status_block)?;
67
68                 if byte_offset != 0 {
69                     throw_unsup_format!(
70                         "NtWriteFile ByteOffset paremeter is non-null, which is unsupported"
71                     );
72                 }
73
74                 let written = if handle == -11 || handle == -12 {
75                     // stdout/stderr
76                     use std::io::{self, Write};
77
78                     let buf_cont = this.read_bytes_ptr(buf, Size::from_bytes(u64::from(n)))?;
79                     let res = if this.machine.mute_stdout_stderr {
80                         Ok(buf_cont.len())
81                     } else if handle == -11 {
82                         io::stdout().write(buf_cont)
83                     } else {
84                         io::stderr().write(buf_cont)
85                     };
86                     res.ok().map(|n| n as u32)
87                 } else {
88                     throw_unsup_format!(
89                         "on Windows, writing to anything except stdout/stderr is not supported"
90                     )
91                 };
92                 // We have to put the result into io_status_block.
93                 if let Some(n) = written {
94                     let io_status_information =
95                         this.mplace_field_named(&io_status_block, "Information")?;
96                     this.write_scalar(
97                         Scalar::from_machine_usize(n.into(), this),
98                         &io_status_information.into(),
99                     )?;
100                 }
101                 // Return whether this was a success. >= 0 is success.
102                 // For the error code we arbitrarily pick 0xC0000185, STATUS_IO_DEVICE_ERROR.
103                 this.write_scalar(
104                     Scalar::from_i32(if written.is_some() { 0 } else { 0xC0000185u32 as i32 }),
105                     dest,
106                 )?;
107             }
108         }
109
110         trace!("{:?}", this.dump_place(**dest));
111         this.go_to_block(ret);
112         Ok(())
113     }
114 }