Skip to content

Commit 199bf13

Browse files
committed
review 5: aarch64 strikes back
1 parent 16a0784 commit 199bf13

File tree

6 files changed

+46
-79
lines changed

6 files changed

+46
-79
lines changed

src/bin/miri.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,7 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls {
335335
fn exit(exit_code: i32) -> ! {
336336
// Drop the tracing guard before exiting, so tracing calls are flushed correctly.
337337
deinit_loggers();
338+
//eprintln!("Called exit!");
338339
#[cfg(target_os = "linux")]
339340
miri::native_lib::register_retcode_sv(exit_code);
340341
std::process::exit(exit_code);
@@ -754,7 +755,9 @@ fn main() {
754755
// SAFETY: No other threads are running
755756
#[cfg(target_os = "linux")]
756757
if unsafe { miri::native_lib::init_sv() }.is_err() {
757-
eprintln!("warning: The native-lib tracer could not be started. Is this a Linux system, and does Miri have permissions to ptrace?");
758+
eprintln!(
759+
"warning: The native-lib tracer could not be started. Is this a Linux system, and does Miri have permissions to ptrace?"
760+
);
758761
}
759762
}
760763
run_compiler_and_exit(

src/shims/native_lib/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use rustc_span::Symbol;
1313
not(all(
1414
target_os = "linux",
1515
target_env = "gnu",
16-
any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")
16+
any(target_arch = "x86", target_arch = "x86_64")
1717
)),
1818
path = "trace/stub.rs"
1919
)]

src/shims/native_lib/trace/child.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,7 @@ pub unsafe fn init_sv() -> Result<(), SvInitError> {
176176
// The child process is free to unwind, so we won't to avoid doubly freeing
177177
// system resources.
178178
let init = std::panic::catch_unwind(|| {
179-
let listener =
180-
ChildListener { message_rx, attached: false, override_retcode: None };
179+
let listener = ChildListener::new(message_rx, confirm_tx.clone());
181180
// Trace as many things as possible, to be able to handle them as needed.
182181
let options = ptrace::Options::PTRACE_O_TRACESYSGOOD
183182
| ptrace::Options::PTRACE_O_TRACECLONE
@@ -231,5 +230,6 @@ pub fn register_retcode_sv(code: i32) {
231230
let mut sv_guard = SUPERVISOR.lock().unwrap();
232231
if let Some(sv) = sv_guard.as_mut() {
233232
sv.message_tx.send(TraceRequest::OverrideRetcode(code)).unwrap();
233+
sv.confirm_rx.recv().unwrap();
234234
}
235235
}

src/shims/native_lib/trace/messages.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
//! let events = event_rx.recv();
1616
//! ```
1717
//! `TraceRequest::OverrideRetcode` can be sent at any point in the above, including
18-
//! before or after all of them.
18+
//! before or after all of them. `confirm_rx.recv()` is to be called after, to ensure
19+
//! that the child does not exit before the supervisor has registered the return code.
1920
//!
2021
//! NB: sending these events out of order, skipping steps, etc. will result in
2122
//! unspecified behaviour from the supervisor process, so use the abstractions
@@ -36,6 +37,8 @@ pub enum TraceRequest {
3637
StartFfi(StartFfiInfo),
3738
/// Manually overrides the code that the supervisor will return upon exiting.
3839
/// Once set, it is permanent. This can be called again to change the value.
40+
///
41+
/// After sending this, the child must wait to receive a `Confirmation`.
3942
OverrideRetcode(i32),
4043
}
4144

src/shims/native_lib/trace/parent.rs

Lines changed: 28 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,6 @@ use crate::shims::native_lib::{AccessEvent, AccessRange, MemEvents};
1212
const 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")]
2517
const 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.
10698
pub 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

115120
impl 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)]

src/shims/native_lib/trace/stub.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ use rustc_const_eval::interpret::InterpResult;
22

33
pub struct Supervisor;
44

5+
static SUPERVISOR: std::sync::Mutex<Option<Supervisor>> = std::sync::Mutex::new(None);
6+
57
impl Supervisor {
68
#[inline(always)]
79
pub fn is_enabled() -> bool {
@@ -12,13 +14,17 @@ impl Supervisor {
1214
_: T,
1315
f: impl FnOnce() -> InterpResult<'tcx, crate::ImmTy<'tcx>>,
1416
) -> InterpResult<'tcx, (crate::ImmTy<'tcx>, Option<super::MemEvents>)> {
17+
let _g = SUPERVISOR.lock().unwrap();
1518
f().map(|v| (v, None))
1619
}
1720
}
1821

1922
#[allow(dead_code, clippy::missing_safety_doc)]
20-
#[inline(always)]
2123
pub unsafe fn init_sv() -> Result<(), !> {
24+
let mut sv_guard = SUPERVISOR.lock().unwrap();
25+
if sv_guard.is_none() {
26+
*sv_guard = Some(Supervisor);
27+
}
2228
Ok(())
2329
}
2430

0 commit comments

Comments
 (0)