@@ -12,14 +12,6 @@ use crate::shims::native_lib::{AccessEvent, AccessRange, MemEvents};
12
12
const WAIT_FLAGS : wait:: WaitPidFlag =
13
13
wait:: WaitPidFlag :: WUNTRACED . union ( wait:: WaitPidFlag :: WEXITED ) ;
14
14
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
-
23
15
/// The default word size on a given platform, in bytes.
24
16
#[ cfg( target_arch = "x86" ) ]
25
17
const ARCH_WORD_SIZE : usize = 4 ;
@@ -105,11 +97,24 @@ pub enum ExecEvent {
105
97
/// A listener for the FFI start info channel along with relevant state.
106
98
pub struct ChildListener {
107
99
/// 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 > ,
109
103
/// Whether an FFI call is currently ongoing.
110
- pub attached : bool ,
104
+ attached : bool ,
111
105
/// 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
+ }
113
118
}
114
119
115
120
impl Iterator for ChildListener {
@@ -129,13 +134,9 @@ impl Iterator for ChildListener {
129
134
Ok ( stat) =>
130
135
match stat {
131
136
// 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) ,
136
138
// 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 ,
139
140
// Child entered or exited a syscall.
140
141
wait:: WaitStatus :: PtraceSyscall ( pid) =>
141
142
if self . attached {
@@ -173,10 +174,8 @@ impl Iterator for ChildListener {
173
174
} ,
174
175
_ => ( ) ,
175
176
} ,
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 ) ) ) ,
180
179
}
181
180
182
181
// Similarly, do a non-blocking poll of the IPC channel.
@@ -190,7 +189,10 @@ impl Iterator for ChildListener {
190
189
self . attached = true ;
191
190
return Some ( ExecEvent :: Start ( info) ) ;
192
191
} ,
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
+ }
194
196
}
195
197
}
196
198
@@ -406,8 +408,6 @@ fn handle_segfault(
406
408
match x86_operand. op_type {
407
409
// We only care about memory accesses
408
410
arch:: x86:: X86OperandType :: Mem ( _) => {
409
- use crate :: shims:: native_lib:: AccessRange ;
410
-
411
411
let push = AccessRange {
412
412
addr,
413
413
min_size : x86_operand. size . into ( ) ,
@@ -421,54 +421,13 @@ fn handle_segfault(
421
421
if acc_ty. is_writable ( ) {
422
422
acc_events. push ( AccessEvent :: Write ( push) ) ;
423
423
}
424
+
425
+ return Ok ( ( ) ) ;
424
426
}
425
427
_ => ( ) ,
426
428
}
427
429
}
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
472
431
_ => unimplemented ! ( ) ,
473
432
}
474
433
}
@@ -580,11 +539,7 @@ fn handle_segfault(
580
539
} ) ;
581
540
582
541
// 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" ) ;
588
543
589
544
// Reprotect everything and continue.
590
545
#[ expect( clippy:: as_conversions) ]
0 commit comments