1
+ use std:: ops:: Range ;
2
+
1
3
use ipc_channel:: ipc;
2
4
use nix:: sys:: { ptrace, signal, wait} ;
3
5
use nix:: unistd;
@@ -161,7 +163,21 @@ impl Supervisor {
161
163
pub fn get_events ( ) -> Option < MemEvents > {
162
164
let mut sv_guard = SUPERVISOR . lock ( ) . unwrap ( ) ;
163
165
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 ( ) ;
165
181
* sv_guard = Some ( sv) ;
166
182
ret
167
183
}
@@ -176,47 +192,9 @@ pub enum TraceRequest {
176
192
177
193
#[ derive( serde:: Serialize , serde:: Deserialize , Debug ) ]
178
194
pub 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 > > ,
220
198
}
221
199
222
200
struct ChildListener {
@@ -274,8 +252,9 @@ impl Iterator for ChildListener {
274
252
/// created before the fork are the same).
275
253
fn sv_loop ( listener : ChildListener , t_event : ipc:: IpcSender < MemEvents > ) -> ! {
276
254
// 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 ! [ ] ;
279
258
280
259
// Memory allocated on the MiriMachine
281
260
let mut ch_pages = vec ! [ ] ;
@@ -310,7 +289,9 @@ fn sv_loop(listener: ChildListener, t_event: ipc::IpcSender<MemEvents>) -> ! {
310
289
wait:: WaitStatus :: Stopped ( pid, signal) => {
311
290
match signal {
312
291
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
+ {
314
295
retcode = ret;
315
296
break ' listen;
316
297
}
@@ -354,7 +335,10 @@ fn sv_loop(listener: ChildListener, t_event: ipc::IpcSender<MemEvents>) -> ! {
354
335
#[ expect( clippy:: as_conversions) ]
355
336
if regs. retval ( ) as isize > 0 {
356
337
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
+ ) ;
358
342
}
359
343
}
360
344
Err ( ret) => {
@@ -412,8 +396,9 @@ fn sv_loop(listener: ChildListener, t_event: ipc::IpcSender<MemEvents>) -> ! {
412
396
413
397
TraceRequest :: EndFfi => {
414
398
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 ! [ ] ;
417
402
mappings = vec ! [ ] ;
418
403
if let Err ( ret) = wait_for_signal ( main_pid, signal:: SIGSTOP , false ) {
419
404
retcode = ret;
@@ -509,19 +494,18 @@ fn wait_for_syscall(pid: unistd::Pid, syscall: i64) -> Result<libc::user_regs_st
509
494
fn handle_munmap (
510
495
pid : unistd:: Pid ,
511
496
regs : libc:: user_regs_struct ,
512
- mappings : & mut Vec < ( u64 , u64 ) > ,
497
+ mappings : & mut Vec < Range < u64 > > ,
513
498
) -> Result < ( ) , i32 > {
514
499
// The unmap call might hit multiple mappings we've saved,
515
500
// or overlap with them partially (or both)
516
501
let um_start = regs. arg1 ( ) . to_u64 ( ) ;
517
502
let um_len = regs. arg2 ( ) . to_u64 ( ) ;
518
503
let um_end = um_start. strict_add ( um_len) ;
519
504
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 ) ;
525
509
526
510
if cond {
527
511
idxes. push ( idx) ;
@@ -542,16 +526,15 @@ fn handle_munmap(
542
526
// but it may be only partial so we may readd some sections
543
527
for idx in idxes {
544
528
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) ;
547
530
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) ) ;
551
534
}
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) ) ;
555
538
}
556
539
}
557
540
}
@@ -562,7 +545,8 @@ fn handle_munmap(
562
545
fn handle_segfault (
563
546
pid : unistd:: Pid ,
564
547
ch_pages : & [ u64 ] ,
565
- accesses : & mut Vec < ( u64 , u64 , MemAccessType ) > ,
548
+ reads : & mut Vec < Range < u64 > > ,
549
+ writes : & mut Vec < Range < u64 > > ,
566
550
) -> Result < ( ) , i32 > {
567
551
let siginfo = ptrace:: getsiginfo ( pid) . unwrap ( ) ;
568
552
let addr = unsafe { siginfo. si_addr ( ) . addr ( ) . to_u64 ( ) } ;
@@ -617,28 +601,44 @@ fn handle_segfault(
617
601
let instr = decoder. decode ( ) ;
618
602
let memsize = instr. op_code ( ) . memory_size ( ) . size ( ) . to_u64 ( ) ;
619
603
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;
632
628
} else {
633
- curr = Some ( m ) ;
629
+ reads . push ( addr..addr_end ) ;
634
630
}
635
631
}
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
+ }
642
642
}
643
643
}
644
644
#[ expect( clippy:: as_conversions) ]
@@ -660,7 +660,7 @@ fn handle_segfault(
660
660
661
661
fn handle_sigtrap (
662
662
pid : unistd:: Pid ,
663
- mappings : & mut Vec < ( u64 , u64 ) > ,
663
+ mappings : & mut Vec < Range < u64 > > ,
664
664
malloc_bytes : i64 ,
665
665
realloc_bytes : i64 ,
666
666
free_bytes : i64 ,
@@ -677,31 +677,24 @@ fn handle_sigtrap(
677
677
match regs. ip ( ) . strict_sub ( 1 ) {
678
678
a if a == malloc_addr => {
679
679
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) ) ;
683
682
}
684
683
}
685
684
a if a == realloc_addr => {
686
685
let old_ptr = regs. arg1 ( ) . to_u64 ( ) ;
687
686
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 ) ;
691
688
if let Some ( pos) = pos {
692
689
let _ = mappings. remove ( pos) ;
693
690
}
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) ) ;
697
693
}
698
694
}
699
695
a if a == free_addr => {
700
696
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 ) ;
705
698
if let Some ( pos) = pos {
706
699
let _ = mappings. remove ( pos) ;
707
700
}
0 commit comments