1+ use std:: ops:: Range ;
2+
13use ipc_channel:: ipc;
24use nix:: sys:: { ptrace, signal, wait} ;
35use nix:: unistd;
@@ -161,7 +163,21 @@ impl Supervisor {
161163 pub fn get_events ( ) -> Option < MemEvents > {
162164 let mut sv_guard = SUPERVISOR . lock ( ) . unwrap ( ) ;
163165 let sv = sv_guard. take ( ) ?;
164- let ret = sv. r_event . recv ( ) . ok ( ) ;
166+ // On the off-chance something really weird happens, don't block forever
167+ let ret = sv
168+ . r_event
169+ . try_recv_timeout ( std:: time:: Duration :: from_secs ( 1 ) )
170+ . map_err ( |e| {
171+ match e {
172+ ipc:: TryRecvError :: IpcError ( e) => ipc:: TryRecvError :: IpcError ( e) ,
173+ ipc:: TryRecvError :: Empty => {
174+ // timed out!
175+ eprintln ! ( "Waiting for accesses from supervisor timed out!" ) ;
176+ ipc:: TryRecvError :: Empty
177+ }
178+ }
179+ } )
180+ . ok ( ) ;
165181 * sv_guard = Some ( sv) ;
166182 ret
167183 }
@@ -176,47 +192,9 @@ pub enum TraceRequest {
176192
177193#[ derive( serde:: Serialize , serde:: Deserialize , Debug ) ]
178194pub struct MemEvents {
179- pub accesses : Vec < ( u64 , u64 , MemAccessType ) > ,
180- pub mappings : Vec < ( u64 , u64 ) > ,
181- }
182-
183- #[ derive( serde:: Serialize , serde:: Deserialize , Debug , Clone ) ]
184- pub enum MemAccessType {
185- Read ,
186- Write ,
187- ReadWrite ,
188- }
189-
190- impl MemAccessType {
191- fn update ( & mut self , other : MemAccessType ) {
192- match self {
193- MemAccessType :: Read =>
194- match other {
195- MemAccessType :: Read => ( ) ,
196- _ => * self = MemAccessType :: ReadWrite ,
197- } ,
198- MemAccessType :: Write =>
199- match other {
200- MemAccessType :: Write => ( ) ,
201- _ => * self = MemAccessType :: ReadWrite ,
202- } ,
203- MemAccessType :: ReadWrite => ( ) ,
204- }
205- }
206-
207- pub fn did_read ( & self ) -> bool {
208- match self {
209- MemAccessType :: Write => false ,
210- _ => true ,
211- }
212- }
213-
214- pub fn did_write ( & self ) -> bool {
215- match self {
216- MemAccessType :: Read => false ,
217- _ => true ,
218- }
219- }
195+ pub reads : Vec < Range < u64 > > ,
196+ pub writes : Vec < Range < u64 > > ,
197+ pub mappings : Vec < Range < u64 > > ,
220198}
221199
222200struct ChildListener {
@@ -274,8 +252,9 @@ impl Iterator for ChildListener {
274252/// created before the fork are the same).
275253fn sv_loop ( listener : ChildListener , t_event : ipc:: IpcSender < MemEvents > ) -> ! {
276254 // Things that we return to the child process
277- let mut accesses: Vec < ( u64 , u64 , MemAccessType ) > = vec ! [ ] ;
278- let mut mappings: Vec < ( u64 , u64 ) > = vec ! [ ] ;
255+ let mut reads: Vec < Range < u64 > > = vec ! [ ] ;
256+ let mut writes: Vec < Range < u64 > > = vec ! [ ] ;
257+ let mut mappings: Vec < Range < u64 > > = vec ! [ ] ;
279258
280259 // Memory allocated on the MiriMachine
281260 let mut ch_pages = vec ! [ ] ;
@@ -310,7 +289,9 @@ fn sv_loop(listener: ChildListener, t_event: ipc::IpcSender<MemEvents>) -> ! {
310289 wait:: WaitStatus :: Stopped ( pid, signal) => {
311290 match signal {
312291 signal:: SIGSEGV => {
313- if let Err ( ret) = handle_segfault ( pid, & ch_pages, & mut accesses) {
292+ if let Err ( ret) =
293+ handle_segfault ( pid, & ch_pages, & mut reads, & mut writes)
294+ {
314295 retcode = ret;
315296 break ' listen;
316297 }
@@ -354,7 +335,10 @@ fn sv_loop(listener: ChildListener, t_event: ipc::IpcSender<MemEvents>) -> ! {
354335 #[ expect( clippy:: as_conversions) ]
355336 if regs. retval ( ) as isize > 0 {
356337 let addr = regs. retval ( ) ;
357- mappings. push ( ( addr. to_u64 ( ) , len. to_u64 ( ) ) ) ;
338+ mappings. push (
339+ addr. to_u64 ( )
340+ ..addr. to_u64 ( ) . strict_add ( len. to_u64 ( ) ) ,
341+ ) ;
358342 }
359343 }
360344 Err ( ret) => {
@@ -412,8 +396,9 @@ fn sv_loop(listener: ChildListener, t_event: ipc::IpcSender<MemEvents>) -> ! {
412396
413397 TraceRequest :: EndFfi => {
414398 signal:: kill ( main_pid, signal:: SIGSTOP ) . unwrap ( ) ;
415- t_event. send ( MemEvents { accesses, mappings } ) . unwrap ( ) ;
416- accesses = vec ! [ ] ;
399+ t_event. send ( MemEvents { reads, writes, mappings } ) . unwrap ( ) ;
400+ reads = vec ! [ ] ;
401+ writes = vec ! [ ] ;
417402 mappings = vec ! [ ] ;
418403 if let Err ( ret) = wait_for_signal ( main_pid, signal:: SIGSTOP , false ) {
419404 retcode = ret;
@@ -509,19 +494,18 @@ fn wait_for_syscall(pid: unistd::Pid, syscall: i64) -> Result<libc::user_regs_st
509494fn handle_munmap (
510495 pid : unistd:: Pid ,
511496 regs : libc:: user_regs_struct ,
512- mappings : & mut Vec < ( u64 , u64 ) > ,
497+ mappings : & mut Vec < Range < u64 > > ,
513498) -> Result < ( ) , i32 > {
514499 // The unmap call might hit multiple mappings we've saved,
515500 // or overlap with them partially (or both)
516501 let um_start = regs. arg1 ( ) . to_u64 ( ) ;
517502 let um_len = regs. arg2 ( ) . to_u64 ( ) ;
518503 let um_end = um_start. strict_add ( um_len) ;
519504 let mut idxes = vec ! [ ] ;
520- for ( idx, & ( mp_start, len) ) in mappings. iter ( ) . enumerate ( ) {
521- let mp_end = mp_start. strict_add ( len) ;
522- let cond = ( mp_start..mp_end) . contains ( & um_start)
523- || ( mp_start..mp_end) . contains ( & um_end)
524- || ( um_start..um_end) . contains ( & mp_start) ;
505+ for ( idx, mp) in mappings. iter ( ) . enumerate ( ) {
506+ let cond = mp. contains ( & um_start)
507+ || mp. contains ( & um_end)
508+ || ( um_start..um_end) . contains ( & mp. start ) ;
525509
526510 if cond {
527511 idxes. push ( idx) ;
@@ -542,16 +526,15 @@ fn handle_munmap(
542526 // but it may be only partial so we may readd some sections
543527 for idx in idxes {
544528 let um_end = um_start. strict_add ( um_len) ;
545- let ( mp_start, mp_len) = mappings. remove ( idx) ;
546- let mp_end = mp_len. strict_add ( mp_len) ;
529+ let mp = mappings. remove ( idx) ;
547530
548- if mp_start < um_start {
549- let preserved_len_head = um_start. strict_sub ( mp_start ) ;
550- mappings. push ( ( mp_start , preserved_len_head) ) ;
531+ if mp . start < um_start {
532+ let preserved_len_head = um_start. strict_sub ( mp . start ) ;
533+ mappings. push ( mp . start ..mp . start . strict_add ( preserved_len_head) ) ;
551534 }
552- if mp_end > um_end {
553- let preserved_len_tail = mp_end . strict_sub ( um_end) ;
554- mappings. push ( ( um_end, preserved_len_tail) ) ;
535+ if mp . end > um_end {
536+ let preserved_len_tail = mp . end . strict_sub ( um_end) ;
537+ mappings. push ( um_end..um_end . strict_add ( preserved_len_tail) ) ;
555538 }
556539 }
557540 }
@@ -562,7 +545,8 @@ fn handle_munmap(
562545fn handle_segfault (
563546 pid : unistd:: Pid ,
564547 ch_pages : & [ u64 ] ,
565- accesses : & mut Vec < ( u64 , u64 , MemAccessType ) > ,
548+ reads : & mut Vec < Range < u64 > > ,
549+ writes : & mut Vec < Range < u64 > > ,
566550) -> Result < ( ) , i32 > {
567551 let siginfo = ptrace:: getsiginfo ( pid) . unwrap ( ) ;
568552 let addr = unsafe { siginfo. si_addr ( ) . addr ( ) . to_u64 ( ) } ;
@@ -617,28 +601,44 @@ fn handle_segfault(
617601 let instr = decoder. decode ( ) ;
618602 let memsize = instr. op_code ( ) . memory_size ( ) . size ( ) . to_u64 ( ) ;
619603 let mem = fac. info ( & instr) . used_memory ( ) ;
620- let acc = mem. iter ( ) . fold ( None , |mut curr : Option < MemAccessType > , m| {
621- if let Some ( m) = match m. access ( ) {
622- iced_x86:: OpAccess :: Read => Some ( MemAccessType :: Read ) ,
623- iced_x86:: OpAccess :: CondRead => Some ( MemAccessType :: Read ) ,
624- iced_x86:: OpAccess :: Write => Some ( MemAccessType :: Write ) ,
625- iced_x86:: OpAccess :: CondWrite => Some ( MemAccessType :: Write ) ,
626- iced_x86:: OpAccess :: ReadWrite => Some ( MemAccessType :: ReadWrite ) ,
627- iced_x86:: OpAccess :: ReadCondWrite => Some ( MemAccessType :: ReadWrite ) ,
628- _ => None ,
629- } {
630- if let Some ( curr) = curr. as_mut ( ) {
631- curr. update ( m) ;
604+
605+ for acc in mem {
606+ let mut r = false ;
607+ let mut w = false ;
608+ match acc. access ( ) {
609+ iced_x86:: OpAccess :: Read | iced_x86:: OpAccess :: CondRead => {
610+ r = true ;
611+ }
612+ iced_x86:: OpAccess :: Write | iced_x86:: OpAccess :: CondWrite => {
613+ w = true ;
614+ }
615+ iced_x86:: OpAccess :: ReadWrite | iced_x86:: OpAccess :: ReadCondWrite => {
616+ r = true ;
617+ w = true ;
618+ }
619+ _ => ( ) ,
620+ }
621+ let addr_end = addr. strict_add ( memsize) ;
622+ if r {
623+ if let Some ( idx) = reads. iter ( ) . position ( |r| r. start <= addr_end && addr <= r. end ) {
624+ let mut rg = reads[ idx] . clone ( ) ;
625+ rg. start = std:: cmp:: min ( rg. start , addr) ;
626+ rg. end = std:: cmp:: max ( rg. end , addr_end) ;
627+ reads[ idx] = rg;
632628 } else {
633- curr = Some ( m ) ;
629+ reads . push ( addr..addr_end ) ;
634630 }
635631 }
636- curr
637- } ) ;
638- if let Some ( acc) = acc {
639- match accesses. iter ( ) . position ( |& ( a, len, _) | a == addr && len == memsize) {
640- Some ( pos) => accesses[ pos] . 2 . update ( acc) ,
641- None => accesses. push ( ( addr, memsize, acc) ) ,
632+ if w {
633+ if let Some ( idx) = writes. iter ( ) . position ( |r| r. start <= addr_end && addr <= r. end )
634+ {
635+ let mut rg = writes[ idx] . clone ( ) ;
636+ rg. start = std:: cmp:: min ( rg. start , addr) ;
637+ rg. end = std:: cmp:: max ( rg. end , addr_end) ;
638+ writes[ idx] = rg;
639+ } else {
640+ writes. push ( addr..addr_end) ;
641+ }
642642 }
643643 }
644644 #[ expect( clippy:: as_conversions) ]
@@ -660,7 +660,7 @@ fn handle_segfault(
660660
661661fn handle_sigtrap (
662662 pid : unistd:: Pid ,
663- mappings : & mut Vec < ( u64 , u64 ) > ,
663+ mappings : & mut Vec < Range < u64 > > ,
664664 malloc_bytes : i64 ,
665665 realloc_bytes : i64 ,
666666 free_bytes : i64 ,
@@ -677,31 +677,24 @@ fn handle_sigtrap(
677677 match regs. ip ( ) . strict_sub ( 1 ) {
678678 a if a == malloc_addr => {
679679 let size = regs. arg1 ( ) . to_u64 ( ) ; // !
680- let ptr = intercept_retptr ( pid, regs, malloc_addr, malloc_bytes) ?;
681- if ptr > 0 {
682- mappings. push ( ( ptr as u64 , size) ) ;
680+ if let Ok ( ptr) = intercept_retptr ( pid, regs, malloc_addr, malloc_bytes) ?. try_into ( ) {
681+ mappings. push ( ptr..ptr. strict_add ( size) ) ;
683682 }
684683 }
685684 a if a == realloc_addr => {
686685 let old_ptr = regs. arg1 ( ) . to_u64 ( ) ;
687686 let size = regs. arg2 ( ) . to_u64 ( ) ;
688- let pos = mappings
689- . iter ( )
690- . position ( |& ( ptr, size) | ptr <= old_ptr && old_ptr < ptr. strict_add ( size) ) ;
687+ let pos = mappings. iter ( ) . position ( |rg| rg. start <= old_ptr && old_ptr < rg. end ) ;
691688 if let Some ( pos) = pos {
692689 let _ = mappings. remove ( pos) ;
693690 }
694- let ptr = intercept_retptr ( pid, regs, realloc_addr, realloc_bytes) ?;
695- if ptr > 0 {
696- mappings. push ( ( ptr as u64 , size) ) ;
691+ if let Ok ( ptr) = intercept_retptr ( pid, regs, realloc_addr, realloc_bytes) ?. try_into ( ) {
692+ mappings. push ( ptr..ptr. strict_add ( size) ) ;
697693 }
698694 }
699695 a if a == free_addr => {
700696 let old_ptr = regs. arg1 ( ) . to_u64 ( ) ;
701- //let size = regs.rdi;
702- let pos = mappings
703- . iter ( )
704- . position ( |& ( ptr, size) | ptr <= old_ptr && old_ptr < ptr. strict_add ( size) ) ;
697+ let pos = mappings. iter ( ) . position ( |rg| rg. start <= old_ptr && old_ptr < rg. end ) ;
705698 if let Some ( pos) = pos {
706699 let _ = mappings. remove ( pos) ;
707700 }
0 commit comments