@@ -34,18 +34,34 @@ pub struct MemEvents {
3434/// A single memory access. 
3535#[ allow( dead_code) ]  
3636#[ cfg_attr( target_os = "linux" ,  derive( serde:: Serialize ,  serde:: Deserialize ) ) ]  
37- #[ derive( Debug ) ]  
37+ #[ derive( Clone ,   Debug ) ]  
3838pub  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. 
39+     /// A read occurred on this memory range. 
4340     Read ( AccessRange ) , 
44-     /// A read  may have occurred on this memory range. 
41+     /// A write  may have occurred on this memory range. 
4542     /// Some instructions *may* write memory without *always* doing that, 
4643     /// so this can be an over-approximation. 
4744     /// The range info, however, is reliable if the access did happen. 
48-      Write ( AccessRange ) , 
45+      /// If the second field is true, the access definitely happened. 
46+      Write ( AccessRange ,  bool ) , 
47+ } 
48+ 
49+ impl  AccessEvent  { 
50+     fn  get_range ( & self )  -> AccessRange  { 
51+         match  self  { 
52+             AccessEvent :: Read ( access_range)  => access_range. clone ( ) , 
53+             AccessEvent :: Write ( access_range,  _)  => access_range. clone ( ) , 
54+         } 
55+     } 
56+ 
57+     fn  is_read ( & self )  -> bool  { 
58+         matches ! ( self ,  AccessEvent :: Read ( _) ) 
59+     } 
60+ 
61+     fn  definitely_happened ( & self )  -> bool  { 
62+         // Anything except a maybe-write is definitive. 
63+         !matches ! ( self ,  AccessEvent :: Write ( _,  false ) ) 
64+     } 
4965} 
5066
5167/// The memory touched by a given access. 
@@ -59,6 +75,12 @@ pub struct AccessRange {
5975     pub  size :  usize , 
6076} 
6177
78+ impl  AccessRange  { 
79+     fn  end ( & self )  -> usize  { 
80+         self . addr . strict_add ( self . size ) 
81+     } 
82+ } 
83+ 
6284impl < ' tcx >  EvalContextExtPriv < ' tcx >  for  crate :: MiriInterpCx < ' tcx >  { } 
6385trait  EvalContextExtPriv < ' tcx > :  crate :: MiriInterpCxExt < ' tcx >  { 
6486    /// Call native host function and return the output as an immediate. 
@@ -196,6 +218,43 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
196218        } 
197219        None 
198220    } 
221+ 
222+     /// Applies the `events` to Miri's internal state. The event vector must be 
223+      /// ordered sequentially by when the accesses happened, and the sizes are 
224+      /// assumed to be exact. 
225+      fn  tracing_apply_accesses ( & mut  self ,  events :  MemEvents )  -> InterpResult < ' tcx >  { 
226+         let  this = self . eval_context_mut ( ) ; 
227+ 
228+         for  evt in  events. acc_events  { 
229+             let  evt_rg = evt. get_range ( ) ; 
230+             // We're assuming an access only touches 1 allocation. 
231+             let  alloc_id = this
232+                 . alloc_id_from_addr ( evt_rg. addr . to_u64 ( ) ,  evt_rg. size . try_into ( ) . unwrap ( ) ,  true ) 
233+                 . expect ( "Foreign code did an out-of-bounds access!" ) ; 
234+ 
235+             let  alloc = this. get_alloc_raw ( alloc_id) ?; 
236+             let  alloc_addr = alloc. get_bytes_unchecked_raw ( ) . addr ( ) ; 
237+ 
238+             // Shift the overlap range to be an offset from the allocation base addr. 
239+             let  overlap = evt_rg. addr . strict_sub ( alloc_addr) ..evt_rg. end ( ) . strict_sub ( alloc_addr) ; 
240+ 
241+             // Reads are infallible, writes might not be. 
242+             if  evt. is_read ( )  { 
243+                 let  p_map = alloc. provenance ( ) ; 
244+                 for  idx in  overlap { 
245+                     // If a provenance was read by the foreign code, expose it. 
246+                     if  let  Some ( prov)  = p_map. get ( Size :: from_bytes ( idx) ,  this)  { 
247+                         this. expose_provenance ( prov) ?; 
248+                     } 
249+                 } 
250+             }  else  if  evt. definitely_happened ( )  || alloc. mutability . is_mut ( )  { 
251+                 //let (alloc, cx) = this.get_alloc_raw_mut(alloc_id)?; 
252+                 //alloc.process_native_write(AllocRange { start: overlap.start, size: overlap.len() }) 
253+             } 
254+         } 
255+ 
256+         interp_ok ( ( ) ) 
257+     } 
199258} 
200259
201260impl < ' tcx >  EvalContextExt < ' tcx >  for  crate :: MiriInterpCx < ' tcx >  { } 
@@ -221,6 +280,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
221280            } 
222281        } ; 
223282
283+         // Do we have ptrace? 
284+         let  tracing = trace:: Supervisor :: is_enabled ( ) ; 
285+ 
224286        // Get the function arguments, and convert them to `libffi`-compatible form. 
225287        let  mut  libffi_args = Vec :: < CArg > :: with_capacity ( args. len ( ) ) ; 
226288        for  arg in  args. iter ( )  { 
@@ -240,9 +302,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
240302                // The first time this happens, print a warning. 
241303                if  !this. machine . native_call_mem_warned . replace ( true )  { 
242304                    // Newly set, so first time we get here. 
243-                     this. emit_diagnostic ( NonHaltingDiagnostic :: NativeCallSharedMem  { 
244-                         tracing :  self :: trace:: Supervisor :: is_enabled ( ) , 
245-                     } ) ; 
305+                     this. emit_diagnostic ( NonHaltingDiagnostic :: NativeCallSharedMem  {  tracing } ) ; 
246306                } 
247307
248308                this. expose_provenance ( prov) ?; 
@@ -268,15 +328,21 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
268328            // be read by FFI. The `black_box` is defensive programming as LLVM likes 
269329            // to (incorrectly) optimize away ptr2int casts whose result is unused. 
270330            std:: hint:: black_box ( alloc. get_bytes_unchecked_raw ( ) . expose_provenance ( ) ) ; 
271-             // Expose all provenances in this allocation, since the native code can do $whatever. 
272-             for  prov in  alloc. provenance ( ) . provenances ( )  { 
273-                 this. expose_provenance ( prov) ?; 
331+ 
332+             if  !tracing { 
333+                 // Expose all provenances in this allocation, since the native code can do $whatever. 
334+                 for  prov in  alloc. provenance ( ) . provenances ( )  { 
335+                     this. expose_provenance ( prov) ?; 
336+                 } 
274337            } 
275338
276339            // Prepare for possible write from native code if mutable. 
277340            if  info. mutbl . is_mut ( )  { 
278-                 let  alloc =  & mut   this. get_alloc_raw_mut ( alloc_id) ?. 0 ; 
341+                 let  ( alloc,  _cx )  =  this. get_alloc_raw_mut ( alloc_id) ?; 
279342                alloc. prepare_for_native_access ( ) ; 
343+                 if  tracing { 
344+                     //alloc.process_native_write(&cx.tcx, None); 
345+                 } 
280346                // Also expose *mutable* provenance for the interpreter-level allocation. 
281347                std:: hint:: black_box ( alloc. get_bytes_unchecked_raw_mut ( ) . expose_provenance ( ) ) ; 
282348            } 
@@ -288,10 +354,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
288354        let  ( ret,  maybe_memevents)  =
289355            this. call_native_with_args ( link_name,  dest,  code_ptr,  libffi_args) ?; 
290356
291-         if  cfg ! ( target_os = "linux" ) 
292-             && let  Some ( events)  = maybe_memevents
293-         { 
294-             trace ! ( "Registered FFI events:\n {events:#0x?}" ) ; 
357+         if  tracing { 
358+             this. tracing_apply_accesses ( maybe_memevents. unwrap ( ) ) ?; 
295359        } 
296360
297361        this. write_immediate ( * ret,  dest) ?; 
0 commit comments