Skip to content

Commit f327ba0

Browse files
nia-eRalfJung
andcommitted
various native-lib-trace-related fixups
Co-Authored-By: Ralf Jung <post@ralfj.de>
1 parent 995bbaf commit f327ba0

File tree

10 files changed

+312
-338
lines changed

10 files changed

+312
-338
lines changed

src/alloc/isolated_alloc.rs

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -302,31 +302,28 @@ impl IsolatedAlloc {
302302
}
303303
}
304304

305-
/// Returns a vector of page addresses managed by the allocator.
306-
pub fn pages(&self) -> Vec<usize> {
307-
let mut pages: Vec<usize> =
308-
self.page_ptrs.iter().map(|p| p.expose_provenance().get()).collect();
309-
for (ptr, size) in self.huge_ptrs.iter() {
310-
for i in 0..size / self.page_size {
311-
pages.push(ptr.expose_provenance().get().strict_add(i * self.page_size));
312-
}
313-
}
314-
pages
305+
/// Returns a list of page addresses managed by the allocator.
306+
pub fn pages(&self) -> impl Iterator<Item = usize> {
307+
let pages = self.page_ptrs.iter().map(|p| p.expose_provenance().get());
308+
pages.chain(self.huge_ptrs.iter().flat_map(|(ptr, size)| {
309+
(0..size / self.page_size)
310+
.map(|i| ptr.expose_provenance().get().strict_add(i * self.page_size))
311+
}))
315312
}
316313

317314
/// Protects all owned memory as `PROT_NONE`, preventing accesses.
318315
///
319316
/// SAFETY: Accessing memory after this point will result in a segfault
320317
/// unless it is first unprotected.
321-
pub unsafe fn prepare_ffi(&mut self) -> Result<(), nix::errno::Errno> {
318+
pub unsafe fn start_ffi(&mut self) -> Result<(), nix::errno::Errno> {
322319
let prot = mman::ProtFlags::PROT_NONE;
323320
unsafe { self.mprotect(prot) }
324321
}
325322

326323
/// Deprotects all owned memory by setting it to RW. Erroring here is very
327324
/// likely unrecoverable, so it may panic if applying those permissions
328325
/// fails.
329-
pub fn unprep_ffi(&mut self) {
326+
pub fn end_ffi(&mut self) {
330327
let prot = mman::ProtFlags::PROT_READ | mman::ProtFlags::PROT_WRITE;
331328
unsafe {
332329
self.mprotect(prot).unwrap();

src/bin/miri.rs

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -233,8 +233,6 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
233233
} else {
234234
let return_code = miri::eval_entry(tcx, entry_def_id, entry_type, &config, None)
235235
.unwrap_or_else(|| {
236-
//#[cfg(target_os = "linux")]
237-
//miri::native_lib::register_retcode_sv(rustc_driver::EXIT_FAILURE);
238236
tcx.dcx().abort_if_errors();
239237
rustc_driver::EXIT_FAILURE
240238
});
@@ -337,6 +335,9 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls {
337335
fn exit(exit_code: i32) -> ! {
338336
// Drop the tracing guard before exiting, so tracing calls are flushed correctly.
339337
deinit_loggers();
338+
// Make sure the supervisor knows about the code code.
339+
#[cfg(target_os = "linux")]
340+
miri::native_lib::register_retcode_sv(exit_code);
340341
std::process::exit(exit_code);
341342
}
342343

@@ -355,6 +356,11 @@ fn run_compiler_and_exit(
355356
args: &[String],
356357
callbacks: &mut (dyn rustc_driver::Callbacks + Send),
357358
) -> ! {
359+
// Install the ctrlc handler that sets `rustc_const_eval::CTRL_C_RECEIVED`, even if
360+
// MIRI_BE_RUSTC is set. We do this late so that when `native_lib::init_sv` is called,
361+
// there are no other threads.
362+
rustc_driver::install_ctrlc_handler();
363+
358364
// Invoke compiler, catch any unwinding panics and handle return code.
359365
let exit_code =
360366
rustc_driver::catch_with_exit_code(move || rustc_driver::run_compiler(args, callbacks));
@@ -439,10 +445,6 @@ fn main() {
439445
let args = rustc_driver::catch_fatal_errors(|| rustc_driver::args::raw_args(&early_dcx))
440446
.unwrap_or_else(|_| std::process::exit(rustc_driver::EXIT_FAILURE));
441447

442-
// Install the ctrlc handler that sets `rustc_const_eval::CTRL_C_RECEIVED`, even if
443-
// MIRI_BE_RUSTC is set.
444-
rustc_driver::install_ctrlc_handler();
445-
446448
// If the environment asks us to actually be rustc, then do that.
447449
if let Some(crate_kind) = env::var_os("MIRI_BE_RUSTC") {
448450
// Earliest rustc setup.
@@ -750,15 +752,15 @@ fn main() {
750752

751753
debug!("rustc arguments: {:?}", rustc_args);
752754
debug!("crate arguments: {:?}", miri_config.args);
753-
#[cfg(target_os = "linux")]
754755
if !miri_config.native_lib.is_empty() && miri_config.native_lib_enable_tracing {
755-
// FIXME: This should display a diagnostic / warning on error
756-
// SAFETY: If any other threads exist at this point (namely for the ctrlc
757-
// handler), they will not interact with anything on the main rustc/Miri
758-
// thread in an async-signal-unsafe way such as by accessing shared
759-
// semaphores, etc.; the handler only calls `sleep()` and `exit()`, which
760-
// are async-signal-safe, as is accessing atomics
761-
//let _ = unsafe { miri::native_lib::init_sv() };
756+
// SAFETY: No other threads are running
757+
#[cfg(target_os = "linux")]
758+
if unsafe { miri::native_lib::init_sv() }.is_err() {
759+
eprintln!(
760+
"warning: The native-lib tracer could not be started. Is this an x86 Linux system, and does Miri have permissions to ptrace?\n\
761+
Falling back to non-tracing native-lib mode."
762+
);
763+
}
762764
}
763765
run_compiler_and_exit(
764766
&rustc_args,

src/lib.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,10 @@ pub use rustc_const_eval::interpret::{self, AllocMap, Provenance as _};
9696
use rustc_middle::{bug, span_bug};
9797
use tracing::{info, trace};
9898

99-
//#[cfg(target_os = "linux")]
100-
//pub mod native_lib {
101-
// pub use crate::shims::{init_sv, register_retcode_sv};
102-
//}
99+
#[cfg(target_os = "linux")]
100+
pub mod native_lib {
101+
pub use crate::shims::{init_sv, register_retcode_sv};
102+
}
103103

104104
// Type aliases that set the provenance parameter.
105105
pub type Pointer = interpret::Pointer<Option<machine::Provenance>>;

src/shims/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ pub mod tls;
2222
pub mod unwind;
2323

2424
pub use self::files::FdTable;
25-
//#[cfg(target_os = "linux")]
26-
//pub use self::native_lib::trace::{init_sv, register_retcode_sv};
25+
#[cfg(target_os = "linux")]
26+
pub use self::native_lib::trace::{init_sv, register_retcode_sv};
2727
pub use self::unix::{DirTable, EpollInterestTable};
2828

2929
/// What needs to be done after emulating an item (a shim or an intrinsic) is done.

src/shims/native_lib/mod.rs

Lines changed: 60 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
//! Implements calling functions from a native library.
22
3-
// FIXME: disabled since it fails to build on many targets.
4-
//#[cfg(target_os = "linux")]
5-
//pub mod trace;
6-
73
use std::ops::Deref;
84

95
use libffi::high::call as ffi;
@@ -13,14 +9,55 @@ use rustc_middle::mir::interpret::Pointer;
139
use rustc_middle::ty::{self as ty, IntTy, UintTy};
1410
use rustc_span::Symbol;
1511

16-
//#[cfg(target_os = "linux")]
17-
//use self::trace::Supervisor;
12+
#[cfg_attr(
13+
not(all(
14+
target_os = "linux",
15+
target_env = "gnu",
16+
any(target_arch = "x86", target_arch = "x86_64")
17+
)),
18+
path = "trace/stub.rs"
19+
)]
20+
pub mod trace;
21+
1822
use crate::*;
1923

20-
//#[cfg(target_os = "linux")]
21-
//type CallResult<'tcx> = InterpResult<'tcx, (ImmTy<'tcx>, Option<self::trace::messages::MemEvents>)>;
22-
//#[cfg(not(target_os = "linux"))]
23-
type CallResult<'tcx> = InterpResult<'tcx, (ImmTy<'tcx>, Option<!>)>;
24+
/// The final results of an FFI trace, containing every relevant event detected
25+
/// by the tracer.
26+
#[allow(dead_code)]
27+
#[cfg_attr(target_os = "linux", derive(serde::Serialize, serde::Deserialize))]
28+
#[derive(Debug)]
29+
pub struct MemEvents {
30+
/// An list of memory accesses that occurred, in the order they occurred in.
31+
pub acc_events: Vec<AccessEvent>,
32+
}
33+
34+
/// A single memory access.
35+
#[allow(dead_code)]
36+
#[cfg_attr(target_os = "linux", derive(serde::Serialize, serde::Deserialize))]
37+
#[derive(Debug)]
38+
pub enum AccessEvent {
39+
/// A read may have occurred on this memory range.
40+
/// Some instructions *may* read memory without *always* doing that,
41+
/// so this can be an over-approximation.
42+
/// The range info, however, is reliable if the access did happen.
43+
Read(AccessRange),
44+
/// A read may have occurred on this memory range.
45+
/// Some instructions *may* write memory without *always* doing that,
46+
/// so this can be an over-approximation.
47+
/// The range info, however, is reliable if the access did happen.
48+
Write(AccessRange),
49+
}
50+
51+
/// The memory touched by a given access.
52+
#[allow(dead_code)]
53+
#[cfg_attr(target_os = "linux", derive(serde::Serialize, serde::Deserialize))]
54+
#[derive(Clone, Debug)]
55+
pub struct AccessRange {
56+
/// The base address in memory where an access occurred.
57+
pub addr: usize,
58+
/// The number of bytes affected from the base.
59+
pub size: usize,
60+
}
2461

2562
impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {}
2663
trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
@@ -31,18 +68,17 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
3168
dest: &MPlaceTy<'tcx>,
3269
ptr: CodePtr,
3370
libffi_args: Vec<libffi::high::Arg<'a>>,
34-
) -> CallResult<'tcx> {
71+
) -> InterpResult<'tcx, (crate::ImmTy<'tcx>, Option<MemEvents>)> {
3572
let this = self.eval_context_mut();
36-
//#[cfg(target_os = "linux")]
37-
//let alloc = this.machine.allocator.as_ref().unwrap();
38-
39-
// SAFETY: We don't touch the machine memory past this point.
40-
//#[cfg(target_os = "linux")]
41-
//let (guard, stack_ptr) = unsafe { Supervisor::start_ffi(alloc) };
73+
#[cfg(target_os = "linux")]
74+
let alloc = this.machine.allocator.as_ref().unwrap();
75+
#[cfg(not(target_os = "linux"))]
76+
// Placeholder value.
77+
let alloc = ();
4278

43-
// Call the function (`ptr`) with arguments `libffi_args`, and obtain the return value
44-
// as the specified primitive integer type
45-
let res = 'res: {
79+
trace::Supervisor::do_ffi(alloc, || {
80+
// Call the function (`ptr`) with arguments `libffi_args`, and obtain the return value
81+
// as the specified primitive integer type
4682
let scalar = match dest.layout.ty.kind() {
4783
// ints
4884
ty::Int(IntTy::I8) => {
@@ -93,31 +129,22 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
93129
// have the output_type `Tuple([])`.
94130
ty::Tuple(t_list) if (*t_list).deref().is_empty() => {
95131
unsafe { ffi::call::<()>(ptr, libffi_args.as_slice()) };
96-
break 'res interp_ok(ImmTy::uninit(dest.layout));
132+
return interp_ok(ImmTy::uninit(dest.layout));
97133
}
98134
ty::RawPtr(..) => {
99135
let x = unsafe { ffi::call::<*const ()>(ptr, libffi_args.as_slice()) };
100136
let ptr = Pointer::new(Provenance::Wildcard, Size::from_bytes(x.addr()));
101137
Scalar::from_pointer(ptr, this)
102138
}
103139
_ =>
104-
break 'res Err(err_unsup_format!(
140+
return Err(err_unsup_format!(
105141
"unsupported return type for native call: {:?}",
106142
link_name
107143
))
108144
.into(),
109145
};
110146
interp_ok(ImmTy::from_scalar(scalar, dest.layout))
111-
};
112-
113-
// SAFETY: We got the guard and stack pointer from start_ffi, and
114-
// the allocator is the same
115-
//#[cfg(target_os = "linux")]
116-
//let events = unsafe { Supervisor::end_ffi(alloc, guard, stack_ptr) };
117-
//#[cfg(not(target_os = "linux"))]
118-
let events = None;
119-
120-
interp_ok((res?, events))
147+
})
121148
}
122149

123150
/// Get the pointer to the function of the specified name in the shared object file,
@@ -214,10 +241,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
214241
if !this.machine.native_call_mem_warned.replace(true) {
215242
// Newly set, so first time we get here.
216243
this.emit_diagnostic(NonHaltingDiagnostic::NativeCallSharedMem {
217-
//#[cfg(target_os = "linux")]
218-
//tracing: self::trace::Supervisor::is_enabled(),
219-
//#[cfg(not(target_os = "linux"))]
220-
tracing: false,
244+
tracing: self::trace::Supervisor::is_enabled(),
221245
});
222246
}
223247

0 commit comments

Comments
 (0)