1
1
use rustc_middle:: mir;
2
+ use rustc_target:: abi:: Size ;
2
3
use rustc_target:: spec:: abi:: Abi ;
3
4
5
+ use log:: trace;
6
+
7
+ use crate :: helpers:: check_arg_count;
4
8
use crate :: * ;
5
9
6
10
#[ derive( Debug , Copy , Clone ) ]
7
- pub enum Dlsym { }
11
+ pub enum Dlsym {
12
+ NtWriteFile ,
13
+ }
8
14
9
15
impl Dlsym {
10
16
// Returns an error for unsupported symbols, and None if this symbol
11
17
// should become a NULL pointer (pretend it does not exist).
12
18
pub fn from_str ( name : & str ) -> InterpResult < ' static , Option < Dlsym > > {
13
19
Ok ( match name {
14
20
"GetSystemTimePreciseAsFileTime" => None ,
21
+ "NtWriteFile" => Some ( Dlsym :: NtWriteFile ) ,
15
22
_ => throw_unsup_format ! ( "unsupported Windows dlsym: {}" , name) ,
16
23
} )
17
24
}
@@ -23,15 +30,85 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
23
30
& mut self ,
24
31
dlsym : Dlsym ,
25
32
abi : Abi ,
26
- _args : & [ OpTy < ' tcx , Tag > ] ,
33
+ args : & [ OpTy < ' tcx , Tag > ] ,
27
34
ret : Option < ( & PlaceTy < ' tcx , Tag > , mir:: BasicBlock ) > ,
28
35
) -> InterpResult < ' tcx > {
29
36
let this = self . eval_context_mut ( ) ;
30
- let ( _dest , _ret ) = ret. expect ( "we don't support any diverging dlsym" ) ;
37
+ let ( dest , ret ) = ret. expect ( "we don't support any diverging dlsym" ) ;
31
38
assert ! ( this. tcx. sess. target. os == "windows" ) ;
32
39
33
40
this. check_abi ( abi, Abi :: System { unwind : false } ) ?;
34
41
35
- match dlsym { }
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
+ ref handle,
52
+ ref _event,
53
+ ref _apc_routine,
54
+ ref _apc_context,
55
+ ref io_status_block,
56
+ ref buf,
57
+ ref n,
58
+ ref byte_offset,
59
+ ref _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) ?;
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_machine_isize (
102
+ if written. is_some ( ) { 0 } else { ( 0xC0000185u32 as i32 ) . into ( ) } ,
103
+ this,
104
+ ) ,
105
+ dest,
106
+ ) ?;
107
+ }
108
+ }
109
+
110
+ trace ! ( "{:?}" , this. dump_place( * * dest) ) ;
111
+ this. go_to_block ( ret) ;
112
+ Ok ( ( ) )
36
113
}
37
114
}
0 commit comments