1
1
//! Implements calling functions from a native library.
2
2
3
- // FIXME: disabled since it fails to build on many targets.
4
- //#[cfg(target_os = "linux")]
5
- //pub mod trace;
6
-
7
3
use std:: ops:: Deref ;
8
4
9
5
use libffi:: high:: call as ffi;
@@ -13,14 +9,55 @@ use rustc_middle::mir::interpret::Pointer;
13
9
use rustc_middle:: ty:: { self as ty, IntTy , UintTy } ;
14
10
use rustc_span:: Symbol ;
15
11
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
+
18
22
use crate :: * ;
19
23
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
+ }
24
61
25
62
impl < ' tcx > EvalContextExtPriv < ' tcx > for crate :: MiriInterpCx < ' tcx > { }
26
63
trait EvalContextExtPriv < ' tcx > : crate :: MiriInterpCxExt < ' tcx > {
@@ -31,18 +68,17 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
31
68
dest : & MPlaceTy < ' tcx > ,
32
69
ptr : CodePtr ,
33
70
libffi_args : Vec < libffi:: high:: Arg < ' a > > ,
34
- ) -> CallResult < ' tcx > {
71
+ ) -> InterpResult < ' tcx , ( crate :: ImmTy < ' tcx > , Option < MemEvents > ) > {
35
72
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 = ( ) ;
42
78
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
46
82
let scalar = match dest. layout . ty . kind ( ) {
47
83
// ints
48
84
ty:: Int ( IntTy :: I8 ) => {
@@ -93,31 +129,22 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
93
129
// have the output_type `Tuple([])`.
94
130
ty:: Tuple ( t_list) if ( * t_list) . deref ( ) . is_empty ( ) => {
95
131
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 ) ) ;
97
133
}
98
134
ty:: RawPtr ( ..) => {
99
135
let x = unsafe { ffi:: call :: < * const ( ) > ( ptr, libffi_args. as_slice ( ) ) } ;
100
136
let ptr = Pointer :: new ( Provenance :: Wildcard , Size :: from_bytes ( x. addr ( ) ) ) ;
101
137
Scalar :: from_pointer ( ptr, this)
102
138
}
103
139
_ =>
104
- break ' res Err ( err_unsup_format ! (
140
+ return Err ( err_unsup_format ! (
105
141
"unsupported return type for native call: {:?}" ,
106
142
link_name
107
143
) )
108
144
. into ( ) ,
109
145
} ;
110
146
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
+ } )
121
148
}
122
149
123
150
/// 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> {
214
241
if !this. machine . native_call_mem_warned . replace ( true ) {
215
242
// Newly set, so first time we get here.
216
243
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 ( ) ,
221
245
} ) ;
222
246
}
223
247
0 commit comments