11use rustc_middle:: mir;
2+ use rustc_target:: abi:: Size ;
23use rustc_target:: spec:: abi:: Abi ;
34
5+ use log:: trace;
6+
7+ use crate :: helpers:: check_arg_count;
48use crate :: * ;
59
610#[ derive( Debug , Copy , Clone ) ]
7- pub enum Dlsym { }
11+ pub enum Dlsym {
12+ NtWriteFile ,
13+ }
814
915impl Dlsym {
1016 // Returns an error for unsupported symbols, and None if this symbol
1117 // should become a NULL pointer (pretend it does not exist).
1218 pub fn from_str ( name : & str ) -> InterpResult < ' static , Option < Dlsym > > {
1319 Ok ( match name {
1420 "GetSystemTimePreciseAsFileTime" => None ,
21+ "NtWriteFile" => Some ( Dlsym :: NtWriteFile ) ,
1522 _ => throw_unsup_format ! ( "unsupported Windows dlsym: {}" , name) ,
1623 } )
1724 }
@@ -23,15 +30,85 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
2330 & mut self ,
2431 dlsym : Dlsym ,
2532 abi : Abi ,
26- _args : & [ OpTy < ' tcx , Tag > ] ,
33+ args : & [ OpTy < ' tcx , Tag > ] ,
2734 ret : Option < ( & PlaceTy < ' tcx , Tag > , mir:: BasicBlock ) > ,
2835 ) -> InterpResult < ' tcx > {
2936 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" ) ;
3138 assert ! ( this. tcx. sess. target. os == "windows" ) ;
3239
3340 this. check_abi ( abi, Abi :: System { unwind : false } ) ?;
3441
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 ( ( ) )
36113 }
37114}
0 commit comments