11//! Implements calling functions from a native library.
22
3- // FIXME: disabled since it fails to build on many targets.
4- //#[cfg(target_os = "linux")]
5- //pub mod trace;
6-
73use std:: ops:: Deref ;
84
95use libffi:: high:: call as ffi;
@@ -13,14 +9,55 @@ use rustc_middle::mir::interpret::Pointer;
139use rustc_middle:: ty:: { self as ty, IntTy , UintTy } ;
1410use rustc_span:: Symbol ;
1511
16- //#[cfg(target_os = "linux")]
17- //use self::trace::Supervisor;
12+ #[ cfg_attr(
13+ not( all(
14+ target_os = "linux" ,
15+ target_env = "gnu" ,
16+ any( target_arch = "x86" , target_arch = "x86_64" )
17+ ) ) ,
18+ path = "trace/stub.rs"
19+ ) ]
20+ pub mod trace;
21+
1822use crate :: * ;
1923
20- //#[cfg(target_os = "linux")]
21- //type CallResult<'tcx> = InterpResult<'tcx, (ImmTy<'tcx>, Option<self::trace::messages::MemEvents>)>;
22- //#[cfg(not(target_os = "linux"))]
23- type CallResult < ' tcx > = InterpResult < ' tcx , ( ImmTy < ' tcx > , Option < !> ) > ;
24+ /// The final results of an FFI trace, containing every relevant event detected
25+ /// by the tracer.
26+ #[ allow( dead_code) ]
27+ #[ cfg_attr( target_os = "linux" , derive( serde:: Serialize , serde:: Deserialize ) ) ]
28+ #[ derive( Debug ) ]
29+ pub struct MemEvents {
30+ /// An list of memory accesses that occurred, in the order they occurred in.
31+ pub acc_events : Vec < AccessEvent > ,
32+ }
33+
34+ /// A single memory access.
35+ #[ allow( dead_code) ]
36+ #[ cfg_attr( target_os = "linux" , derive( serde:: Serialize , serde:: Deserialize ) ) ]
37+ #[ derive( Debug ) ]
38+ pub enum AccessEvent {
39+ /// A read may have occurred on this memory range.
40+ /// Some instructions *may* read memory without *always* doing that,
41+ /// so this can be an over-approximation.
42+ /// The range info, however, is reliable if the access did happen.
43+ Read ( AccessRange ) ,
44+ /// A read may have occurred on this memory range.
45+ /// Some instructions *may* write memory without *always* doing that,
46+ /// so this can be an over-approximation.
47+ /// The range info, however, is reliable if the access did happen.
48+ Write ( AccessRange ) ,
49+ }
50+
51+ /// The memory touched by a given access.
52+ #[ allow( dead_code) ]
53+ #[ cfg_attr( target_os = "linux" , derive( serde:: Serialize , serde:: Deserialize ) ) ]
54+ #[ derive( Clone , Debug ) ]
55+ pub struct AccessRange {
56+ /// The base address in memory where an access occurred.
57+ pub addr : usize ,
58+ /// The number of bytes affected from the base.
59+ pub size : usize ,
60+ }
2461
2562impl < ' tcx > EvalContextExtPriv < ' tcx > for crate :: MiriInterpCx < ' tcx > { }
2663trait EvalContextExtPriv < ' tcx > : crate :: MiriInterpCxExt < ' tcx > {
@@ -31,18 +68,17 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
3168 dest : & MPlaceTy < ' tcx > ,
3269 ptr : CodePtr ,
3370 libffi_args : Vec < libffi:: high:: Arg < ' a > > ,
34- ) -> CallResult < ' tcx > {
71+ ) -> InterpResult < ' tcx , ( crate :: ImmTy < ' tcx > , Option < MemEvents > ) > {
3572 let this = self . eval_context_mut ( ) ;
36- //#[cfg(target_os = "linux")]
37- //let alloc = this.machine.allocator.as_ref().unwrap();
38-
39- // SAFETY: We don't touch the machine memory past this point.
40- //#[cfg(target_os = "linux")]
41- //let (guard, stack_ptr) = unsafe { Supervisor::start_ffi(alloc) };
73+ #[ cfg( target_os = "linux" ) ]
74+ let alloc = this. machine . allocator . as_ref ( ) . unwrap ( ) ;
75+ #[ cfg( not( target_os = "linux" ) ) ]
76+ // Placeholder value.
77+ let alloc = ( ) ;
4278
43- // Call the function (`ptr`) with arguments `libffi_args`, and obtain the return value
44- // as the specified primitive integer type
45- let res = ' res : {
79+ trace :: Supervisor :: do_ffi ( alloc , || {
80+ // Call the function (`ptr`) with arguments `libffi_args`, and obtain the return value
81+ // as the specified primitive integer type
4682 let scalar = match dest. layout . ty . kind ( ) {
4783 // ints
4884 ty:: Int ( IntTy :: I8 ) => {
@@ -93,31 +129,22 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
93129 // have the output_type `Tuple([])`.
94130 ty:: Tuple ( t_list) if ( * t_list) . deref ( ) . is_empty ( ) => {
95131 unsafe { ffi:: call :: < ( ) > ( ptr, libffi_args. as_slice ( ) ) } ;
96- break ' res interp_ok ( ImmTy :: uninit ( dest. layout ) ) ;
132+ return interp_ok ( ImmTy :: uninit ( dest. layout ) ) ;
97133 }
98134 ty:: RawPtr ( ..) => {
99135 let x = unsafe { ffi:: call :: < * const ( ) > ( ptr, libffi_args. as_slice ( ) ) } ;
100136 let ptr = Pointer :: new ( Provenance :: Wildcard , Size :: from_bytes ( x. addr ( ) ) ) ;
101137 Scalar :: from_pointer ( ptr, this)
102138 }
103139 _ =>
104- break ' res Err ( err_unsup_format ! (
140+ return Err ( err_unsup_format ! (
105141 "unsupported return type for native call: {:?}" ,
106142 link_name
107143 ) )
108144 . into ( ) ,
109145 } ;
110146 interp_ok ( ImmTy :: from_scalar ( scalar, dest. layout ) )
111- } ;
112-
113- // SAFETY: We got the guard and stack pointer from start_ffi, and
114- // the allocator is the same
115- //#[cfg(target_os = "linux")]
116- //let events = unsafe { Supervisor::end_ffi(alloc, guard, stack_ptr) };
117- //#[cfg(not(target_os = "linux"))]
118- let events = None ;
119-
120- interp_ok ( ( res?, events) )
147+ } )
121148 }
122149
123150 /// Get the pointer to the function of the specified name in the shared object file,
@@ -214,10 +241,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
214241 if !this. machine . native_call_mem_warned . replace ( true ) {
215242 // Newly set, so first time we get here.
216243 this. emit_diagnostic ( NonHaltingDiagnostic :: NativeCallSharedMem {
217- //#[cfg(target_os = "linux")]
218- //tracing: self::trace::Supervisor::is_enabled(),
219- //#[cfg(not(target_os = "linux"))]
220- tracing : false ,
244+ tracing : self :: trace:: Supervisor :: is_enabled ( ) ,
221245 } ) ;
222246 }
223247
0 commit comments