]> git.lizzy.rs Git - rust.git/blob - src/shims/windows/dlsym.rs
Replace unneeded use of `ref` in favor of "match ergonomics"
[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 handle == -11 {
79                         io::stdout().write(buf_cont)
80                     } else {
81                         io::stderr().write(buf_cont)
82                     };
83                     res.ok().map(|n| n as u32)
84                 } else {
85                     throw_unsup_format!(
86                         "on Windows, writing to anything except stdout/stderr is not supported"
87                     )
88                 };
89                 // We have to put the result into io_status_block.
90                 if let Some(n) = written {
91                     let io_status_information =
92                         this.mplace_field_named(&io_status_block, "Information")?;
93                     this.write_scalar(
94                         Scalar::from_machine_usize(n.into(), this),
95                         &io_status_information.into(),
96                     )?;
97                 }
98                 // Return whether this was a success. >= 0 is success.
99                 // For the error code we arbitrarily pick 0xC0000185, STATUS_IO_DEVICE_ERROR.
100                 this.write_scalar(
101                     Scalar::from_i32(if written.is_some() { 0 } else { 0xC0000185u32 as i32 }),
102                     dest,
103                 )?;
104             }
105         }
106
107         trace!("{:?}", this.dump_place(**dest));
108         this.go_to_block(ret);
109         Ok(())
110     }
111 }