@@ -12,14 +12,6 @@ use crate::shims::native_lib::{AccessEvent, AccessRange, MemEvents};
1212const WAIT_FLAGS : wait:: WaitPidFlag =
1313 wait:: WaitPidFlag :: WUNTRACED . union ( wait:: WaitPidFlag :: WEXITED ) ;
1414
15- /// Arch-specific maximum size a single access might perform. x86 value is set
16- /// assuming nothing bigger than AVX-512 is available.
17- #[ cfg( any( target_arch = "x86" , target_arch = "x86_64" ) ) ]
18- const ARCH_MAX_ACCESS_SIZE : usize = 64 ;
19- /// The largest arm64 simd instruction operates on 16 bytes.
20- #[ cfg( target_arch = "aarch64" ) ]
21- const ARCH_MAX_ACCESS_SIZE : usize = 16 ;
22-
2315/// The default word size on a given platform, in bytes.
2416#[ cfg( target_arch = "x86" ) ]
2517const ARCH_WORD_SIZE : usize = 4 ;
@@ -105,11 +97,24 @@ pub enum ExecEvent {
10597/// A listener for the FFI start info channel along with relevant state.
10698pub struct ChildListener {
10799 /// The matching channel for the child's `Supervisor` struct.
108- pub message_rx : ipc:: IpcReceiver < TraceRequest > ,
100+ message_rx : ipc:: IpcReceiver < TraceRequest > ,
101+ /// ...
102+ confirm_tx : ipc:: IpcSender < Confirmation > ,
109103 /// Whether an FFI call is currently ongoing.
110- pub attached : bool ,
104+ attached : bool ,
111105 /// If `Some`, overrides the return code with the given value.
112- pub override_retcode : Option < i32 > ,
106+ override_retcode : Option < i32 > ,
107+ /// Last code obtained from a child exiting.
108+ last_code : Option < i32 > ,
109+ }
110+
111+ impl ChildListener {
112+ pub fn new (
113+ message_rx : ipc:: IpcReceiver < TraceRequest > ,
114+ confirm_tx : ipc:: IpcSender < Confirmation > ,
115+ ) -> Self {
116+ Self { message_rx, confirm_tx, attached : false , override_retcode : None , last_code : None }
117+ }
113118}
114119
115120impl Iterator for ChildListener {
@@ -129,13 +134,9 @@ impl Iterator for ChildListener {
129134 Ok ( stat) =>
130135 match stat {
131136 // Child exited normally with a specific code set.
132- wait:: WaitStatus :: Exited ( _, code) => {
133- let code = self . override_retcode . unwrap_or ( code) ;
134- return Some ( ExecEvent :: Died ( Some ( code) ) ) ;
135- }
137+ wait:: WaitStatus :: Exited ( _, code) => self . last_code = Some ( code) ,
136138 // Child was killed by a signal, without giving a code.
137- wait:: WaitStatus :: Signaled ( _, _, _) =>
138- return Some ( ExecEvent :: Died ( self . override_retcode ) ) ,
139+ wait:: WaitStatus :: Signaled ( _, _, _) => self . last_code = None ,
139140 // Child entered or exited a syscall.
140141 wait:: WaitStatus :: PtraceSyscall ( pid) =>
141142 if self . attached {
@@ -173,10 +174,8 @@ impl Iterator for ChildListener {
173174 } ,
174175 _ => ( ) ,
175176 } ,
176- // This case should only trigger if all children died and we
177- // somehow missed that, but it's best we not allow any room
178- // for deadlocks.
179- Err ( _) => return Some ( ExecEvent :: Died ( None ) ) ,
177+ // This case should only trigger when all children died.
178+ Err ( _) => return Some ( ExecEvent :: Died ( self . override_retcode . or ( self . last_code ) ) ) ,
180179 }
181180
182181 // Similarly, do a non-blocking poll of the IPC channel.
@@ -190,7 +189,10 @@ impl Iterator for ChildListener {
190189 self . attached = true ;
191190 return Some ( ExecEvent :: Start ( info) ) ;
192191 } ,
193- TraceRequest :: OverrideRetcode ( code) => self . override_retcode = Some ( code) ,
192+ TraceRequest :: OverrideRetcode ( code) => {
193+ self . override_retcode = Some ( code) ;
194+ self . confirm_tx . send ( Confirmation ) . unwrap ( ) ;
195+ }
194196 }
195197 }
196198
@@ -406,8 +408,6 @@ fn handle_segfault(
406408 match x86_operand. op_type {
407409 // We only care about memory accesses
408410 arch:: x86:: X86OperandType :: Mem ( _) => {
409- use crate :: shims:: native_lib:: AccessRange ;
410-
411411 let push = AccessRange {
412412 addr,
413413 min_size : x86_operand. size . into ( ) ,
@@ -421,54 +421,13 @@ fn handle_segfault(
421421 if acc_ty. is_writable ( ) {
422422 acc_events. push ( AccessEvent :: Write ( push) ) ;
423423 }
424+
425+ return Ok ( ( ) ) ;
424426 }
425427 _ => ( ) ,
426428 }
427429 }
428- #[ cfg( target_arch = "aarch64" ) ]
429- arch:: ArchOperand :: Arm64Operand ( arm64_operand) => {
430- // Annoyingly, we don't always get the size here, so just be pessimistic for now.
431- match arm64_operand. op_type {
432- arch:: arm64:: Arm64OperandType :: Mem ( _) => {
433- let mut is_vas = true ;
434- // B = 1 byte, H = 2 bytes, S = 4 bytes, D = 8 bytes, Q = 16 bytes.
435- let max_size = match arm64_operand. vas {
436- // Not an fp/simd instruction.
437- arch:: arm64:: Arm64Vas :: ARM64_VAS_INVALID => {
438- is_vas = false ;
439- ARCH_WORD_SIZE
440- }
441- // 1 byte.
442- arch:: arm64:: Arm64Vas :: ARM64_VAS_1B => 1 ,
443- // 2 bytes.
444- arch:: arm64:: Arm64Vas :: ARM64_VAS_1H => 2 ,
445- // 4 bytes.
446- arch:: arm64:: Arm64Vas :: ARM64_VAS_4B
447- | arch:: arm64:: Arm64Vas :: ARM64_VAS_2H
448- | arch:: arm64:: Arm64Vas :: ARM64_VAS_1S => 4 ,
449- // 8 bytes.
450- arch:: arm64:: Arm64Vas :: ARM64_VAS_8B
451- | arch:: arm64:: Arm64Vas :: ARM64_VAS_4H
452- | arch:: arm64:: Arm64Vas :: ARM64_VAS_2S
453- | arch:: arm64:: Arm64Vas :: ARM64_VAS_1D => 8 ,
454- // 16 bytes.
455- arch:: arm64:: Arm64Vas :: ARM64_VAS_16B
456- | arch:: arm64:: Arm64Vas :: ARM64_VAS_8H
457- | arch:: arm64:: Arm64Vas :: ARM64_VAS_4S
458- | arch:: arm64:: Arm64Vas :: ARM64_VAS_2D
459- | arch:: arm64:: Arm64Vas :: ARM64_VAS_1Q => 16 ,
460- } ;
461- let min_size = if is_vas { max_size } else { 1 } ;
462- let push = AccessRange { addr, max_size, min_size } ;
463- // FIXME: This now has access type info in the latest
464- // git version of capstone because this pissed me off
465- // and I added it. Change this when it updates.
466- acc_events. push ( AccessEvent :: Read ( push. clone ( ) ) ) ;
467- acc_events. push ( AccessEvent :: Write ( push) ) ;
468- }
469- _ => ( ) ,
470- }
471- }
430+ // FIXME: arm64
472431 _ => unimplemented ! ( ) ,
473432 }
474433 }
@@ -580,11 +539,7 @@ fn handle_segfault(
580539 } ) ;
581540
582541 // Now figure out the size + type of access and log it down.
583- if capstone_disassemble ( & instr, addr, cs, acc_events) . is_err ( ) {
584- let fallback = AccessRange { addr, max_size : ARCH_MAX_ACCESS_SIZE , min_size : 0 } ;
585- acc_events. push ( AccessEvent :: Read ( fallback. clone ( ) ) ) ;
586- acc_events. push ( AccessEvent :: Write ( fallback) ) ;
587- }
542+ capstone_disassemble ( & instr, addr, cs, acc_events) . expect ( "Failed to disassemble instruction" ) ;
588543
589544 // Reprotect everything and continue.
590545 #[ expect( clippy:: as_conversions) ]
0 commit comments