freebsd add *stat calls interception support
This commit is contained in:
parent
535db18002
commit
9911d8d9bf
@ -225,6 +225,21 @@ fn project_field_named<P: Projectable<'tcx, Provenance>>(
|
|||||||
bug!("No field named {} in type {}", name, base.layout().ty);
|
bug!("No field named {} in type {}", name, base.layout().ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Search if Project (which must be a struct or union type) contains the `name` field.
|
||||||
|
fn projectable_has_field<P: Projectable<'tcx, Provenance>>(
|
||||||
|
&self,
|
||||||
|
base: &P,
|
||||||
|
name: &str,
|
||||||
|
) -> bool {
|
||||||
|
let adt = base.layout().ty.ty_adt_def().unwrap();
|
||||||
|
for field in adt.non_enum_variant().fields.iter() {
|
||||||
|
if field.name.as_str() == name {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
/// Write an int of the appropriate size to `dest`. The target type may be signed or unsigned,
|
/// Write an int of the appropriate size to `dest`. The target type may be signed or unsigned,
|
||||||
/// we try to do the right thing anyway. `i128` can fit all integer types except for `u128` so
|
/// we try to do the right thing anyway. `i128` can fit all integer types except for `u128` so
|
||||||
/// this method is fine for almost all integer types.
|
/// this method is fine for almost all integer types.
|
||||||
|
@ -155,6 +155,17 @@ fn emulate_foreign_item_inner(
|
|||||||
}
|
}
|
||||||
"lseek64" => {
|
"lseek64" => {
|
||||||
let [fd, offset, whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
let [fd, offset, whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||||
|
let fd = this.read_scalar(fd)?.to_i32()?;
|
||||||
|
let offset = this.read_scalar(offset)?.to_i64()?;
|
||||||
|
let whence = this.read_scalar(whence)?.to_i32()?;
|
||||||
|
let result = this.lseek64(fd, offset.into(), whence)?;
|
||||||
|
this.write_scalar(result, dest)?;
|
||||||
|
}
|
||||||
|
"lseek" => {
|
||||||
|
let [fd, offset, whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||||
|
let fd = this.read_scalar(fd)?.to_i32()?;
|
||||||
|
let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
|
||||||
|
let whence = this.read_scalar(whence)?.to_i32()?;
|
||||||
let result = this.lseek64(fd, offset, whence)?;
|
let result = this.lseek64(fd, offset, whence)?;
|
||||||
this.write_scalar(result, dest)?;
|
this.write_scalar(result, dest)?;
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use shims::foreign_items::EmulateForeignItemResult;
|
use shims::foreign_items::EmulateForeignItemResult;
|
||||||
|
use shims::unix::fs::EvalContextExt as _;
|
||||||
use shims::unix::thread::EvalContextExt as _;
|
use shims::unix::thread::EvalContextExt as _;
|
||||||
|
|
||||||
pub fn is_dyn_sym(_name: &str) -> bool {
|
pub fn is_dyn_sym(_name: &str) -> bool {
|
||||||
@ -63,6 +64,33 @@ fn emulate_foreign_item_inner(
|
|||||||
this.write_scalar(Scalar::from_target_usize(len, this), dest)?;
|
this.write_scalar(Scalar::from_target_usize(len, this), dest)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// File related shims
|
||||||
|
// For those, we both intercept `func` and `call@FBSD_1.0` symbols cases
|
||||||
|
// since freebsd 12 the former form can be expected.
|
||||||
|
"stat" | "stat@FBSD_1.0" => {
|
||||||
|
let [path, buf] =
|
||||||
|
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||||
|
let result = this.macos_fbsd_stat(path, buf)?;
|
||||||
|
this.write_scalar(result, dest)?;
|
||||||
|
}
|
||||||
|
"lstat" | "lstat@FBSD_1.0" => {
|
||||||
|
let [path, buf] =
|
||||||
|
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||||
|
let result = this.macos_fbsd_lstat(path, buf)?;
|
||||||
|
this.write_scalar(result, dest)?;
|
||||||
|
}
|
||||||
|
"fstat" | "fstat@FBSD_1.0" => {
|
||||||
|
let [fd, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||||
|
let result = this.macos_fbsd_fstat(fd, buf)?;
|
||||||
|
this.write_scalar(result, dest)?;
|
||||||
|
}
|
||||||
|
"readdir_r" | "readdir_r@FBSD_1.0" => {
|
||||||
|
let [dirp, entry, result] =
|
||||||
|
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||||
|
let result = this.macos_fbsd_readdir_r(dirp, entry, result)?;
|
||||||
|
this.write_scalar(result, dest)?;
|
||||||
|
}
|
||||||
|
|
||||||
// errno
|
// errno
|
||||||
"__error" => {
|
"__error" => {
|
||||||
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||||
|
@ -827,24 +827,20 @@ fn write(
|
|||||||
|
|
||||||
fn lseek64(
|
fn lseek64(
|
||||||
&mut self,
|
&mut self,
|
||||||
fd_op: &OpTy<'tcx, Provenance>,
|
fd: i32,
|
||||||
offset_op: &OpTy<'tcx, Provenance>,
|
offset: i128,
|
||||||
whence_op: &OpTy<'tcx, Provenance>,
|
whence: i32,
|
||||||
) -> InterpResult<'tcx, Scalar<Provenance>> {
|
) -> InterpResult<'tcx, Scalar<Provenance>> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
|
|
||||||
// Isolation check is done via `FileDescriptor` trait.
|
// Isolation check is done via `FileDescriptor` trait.
|
||||||
|
|
||||||
let fd = this.read_scalar(fd_op)?.to_i32()?;
|
|
||||||
let offset = this.read_scalar(offset_op)?.to_i64()?;
|
|
||||||
let whence = this.read_scalar(whence_op)?.to_i32()?;
|
|
||||||
|
|
||||||
let seek_from = if whence == this.eval_libc_i32("SEEK_SET") {
|
let seek_from = if whence == this.eval_libc_i32("SEEK_SET") {
|
||||||
SeekFrom::Start(u64::try_from(offset).unwrap())
|
SeekFrom::Start(u64::try_from(offset).unwrap())
|
||||||
} else if whence == this.eval_libc_i32("SEEK_CUR") {
|
} else if whence == this.eval_libc_i32("SEEK_CUR") {
|
||||||
SeekFrom::Current(offset)
|
SeekFrom::Current(i64::try_from(offset).unwrap())
|
||||||
} else if whence == this.eval_libc_i32("SEEK_END") {
|
} else if whence == this.eval_libc_i32("SEEK_END") {
|
||||||
SeekFrom::End(offset)
|
SeekFrom::End(i64::try_from(offset).unwrap())
|
||||||
} else {
|
} else {
|
||||||
let einval = this.eval_libc("EINVAL");
|
let einval = this.eval_libc("EINVAL");
|
||||||
this.set_last_error(einval)?;
|
this.set_last_error(einval)?;
|
||||||
@ -911,13 +907,16 @@ fn create_link(src: &Path, dst: &Path) -> std::io::Result<()> {
|
|||||||
this.try_unwrap_io_result(result)
|
this.try_unwrap_io_result(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn macos_stat(
|
fn macos_fbsd_stat(
|
||||||
&mut self,
|
&mut self,
|
||||||
path_op: &OpTy<'tcx, Provenance>,
|
path_op: &OpTy<'tcx, Provenance>,
|
||||||
buf_op: &OpTy<'tcx, Provenance>,
|
buf_op: &OpTy<'tcx, Provenance>,
|
||||||
) -> InterpResult<'tcx, Scalar<Provenance>> {
|
) -> InterpResult<'tcx, Scalar<Provenance>> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
this.assert_target_os("macos", "stat");
|
|
||||||
|
if !matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") {
|
||||||
|
panic!("`macos_fbsd_stat` should not be called on {}", this.tcx.sess.target.os);
|
||||||
|
}
|
||||||
|
|
||||||
let path_scalar = this.read_pointer(path_op)?;
|
let path_scalar = this.read_pointer(path_op)?;
|
||||||
let path = this.read_path_from_c_str(path_scalar)?.into_owned();
|
let path = this.read_path_from_c_str(path_scalar)?.into_owned();
|
||||||
@ -940,13 +939,16 @@ fn macos_stat(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// `lstat` is used to get symlink metadata.
|
// `lstat` is used to get symlink metadata.
|
||||||
fn macos_lstat(
|
fn macos_fbsd_lstat(
|
||||||
&mut self,
|
&mut self,
|
||||||
path_op: &OpTy<'tcx, Provenance>,
|
path_op: &OpTy<'tcx, Provenance>,
|
||||||
buf_op: &OpTy<'tcx, Provenance>,
|
buf_op: &OpTy<'tcx, Provenance>,
|
||||||
) -> InterpResult<'tcx, Scalar<Provenance>> {
|
) -> InterpResult<'tcx, Scalar<Provenance>> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
this.assert_target_os("macos", "lstat");
|
|
||||||
|
if !matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") {
|
||||||
|
panic!("`macos_fbsd_lstat` should not be called on {}", this.tcx.sess.target.os);
|
||||||
|
}
|
||||||
|
|
||||||
let path_scalar = this.read_pointer(path_op)?;
|
let path_scalar = this.read_pointer(path_op)?;
|
||||||
let path = this.read_path_from_c_str(path_scalar)?.into_owned();
|
let path = this.read_path_from_c_str(path_scalar)?.into_owned();
|
||||||
@ -967,14 +969,16 @@ fn macos_lstat(
|
|||||||
Ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?))
|
Ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn macos_fstat(
|
fn macos_fbsd_fstat(
|
||||||
&mut self,
|
&mut self,
|
||||||
fd_op: &OpTy<'tcx, Provenance>,
|
fd_op: &OpTy<'tcx, Provenance>,
|
||||||
buf_op: &OpTy<'tcx, Provenance>,
|
buf_op: &OpTy<'tcx, Provenance>,
|
||||||
) -> InterpResult<'tcx, Scalar<Provenance>> {
|
) -> InterpResult<'tcx, Scalar<Provenance>> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
|
|
||||||
this.assert_target_os("macos", "fstat");
|
if !matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") {
|
||||||
|
panic!("`macos_fbsd_fstat` should not be called on {}", this.tcx.sess.target.os);
|
||||||
|
}
|
||||||
|
|
||||||
let fd = this.read_scalar(fd_op)?.to_i32()?;
|
let fd = this.read_scalar(fd_op)?.to_i32()?;
|
||||||
|
|
||||||
@ -1213,7 +1217,7 @@ fn mkdir(
|
|||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
|
|
||||||
#[cfg_attr(not(unix), allow(unused_variables))]
|
#[cfg_attr(not(unix), allow(unused_variables))]
|
||||||
let mode = if this.tcx.sess.target.os == "macos" {
|
let mode = if matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") {
|
||||||
u32::from(this.read_scalar(mode_op)?.to_u16()?)
|
u32::from(this.read_scalar(mode_op)?.to_u16()?)
|
||||||
} else {
|
} else {
|
||||||
this.read_scalar(mode_op)?.to_u32()?
|
this.read_scalar(mode_op)?.to_u32()?
|
||||||
@ -1385,7 +1389,7 @@ fn linux_readdir64(
|
|||||||
Ok(Scalar::from_maybe_pointer(entry, this))
|
Ok(Scalar::from_maybe_pointer(entry, this))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn macos_readdir_r(
|
fn macos_fbsd_readdir_r(
|
||||||
&mut self,
|
&mut self,
|
||||||
dirp_op: &OpTy<'tcx, Provenance>,
|
dirp_op: &OpTy<'tcx, Provenance>,
|
||||||
entry_op: &OpTy<'tcx, Provenance>,
|
entry_op: &OpTy<'tcx, Provenance>,
|
||||||
@ -1393,7 +1397,9 @@ fn macos_readdir_r(
|
|||||||
) -> InterpResult<'tcx, Scalar<Provenance>> {
|
) -> InterpResult<'tcx, Scalar<Provenance>> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
|
|
||||||
this.assert_target_os("macos", "readdir_r");
|
if !matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") {
|
||||||
|
panic!("`macos_fbsd_readdir_r` should not be called on {}", this.tcx.sess.target.os);
|
||||||
|
}
|
||||||
|
|
||||||
let dirp = this.read_target_usize(dirp_op)?;
|
let dirp = this.read_target_usize(dirp_op)?;
|
||||||
|
|
||||||
@ -1424,7 +1430,7 @@ fn macos_readdir_r(
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
let entry_place = this.deref_pointer_as(entry_op, this.libc_ty_layout("dirent"))?;
|
let entry_place = this.deref_pointer_as(entry_op, this.libc_ty_layout("dirent"))?;
|
||||||
let name_place = this.project_field(&entry_place, 5)?;
|
let name_place = this.project_field_named(&entry_place, "d_name")?;
|
||||||
|
|
||||||
let file_name = dir_entry.file_name(); // not a Path as there are no separators!
|
let file_name = dir_entry.file_name(); // not a Path as there are no separators!
|
||||||
let (name_fits, file_name_buf_len) = this.write_os_str_to_c_str(
|
let (name_fits, file_name_buf_len) = this.write_os_str_to_c_str(
|
||||||
@ -1448,16 +1454,41 @@ fn macos_readdir_r(
|
|||||||
|
|
||||||
let file_type = this.file_type_to_d_type(dir_entry.file_type())?;
|
let file_type = this.file_type_to_d_type(dir_entry.file_type())?;
|
||||||
|
|
||||||
this.write_int_fields_named(
|
// macOS offset field is d_seekoff
|
||||||
&[
|
if this.projectable_has_field(&entry_place, "d_seekoff") {
|
||||||
("d_ino", ino.into()),
|
this.write_int_fields_named(
|
||||||
("d_seekoff", 0),
|
&[
|
||||||
("d_reclen", 0),
|
("d_ino", ino.into()),
|
||||||
("d_namlen", file_name_len.into()),
|
("d_seekoff", 0),
|
||||||
("d_type", file_type.into()),
|
("d_reclen", 0),
|
||||||
],
|
("d_namlen", file_name_len.into()),
|
||||||
&entry_place,
|
("d_type", file_type.into()),
|
||||||
)?;
|
],
|
||||||
|
&entry_place,
|
||||||
|
)?;
|
||||||
|
// freebsd 12 and onwards had added the d_off field
|
||||||
|
} else if this.projectable_has_field(&entry_place, "d_off") {
|
||||||
|
this.write_int_fields_named(
|
||||||
|
&[
|
||||||
|
("d_fileno", ino.into()),
|
||||||
|
("d_off", 0),
|
||||||
|
("d_reclen", 0),
|
||||||
|
("d_type", file_type.into()),
|
||||||
|
("d_namlen", file_name_len.into()),
|
||||||
|
],
|
||||||
|
&entry_place,
|
||||||
|
)?;
|
||||||
|
} else {
|
||||||
|
this.write_int_fields_named(
|
||||||
|
&[
|
||||||
|
("d_fileno", ino.into()),
|
||||||
|
("d_reclen", 0),
|
||||||
|
("d_type", file_type.into()),
|
||||||
|
("d_namlen", file_name_len.into()),
|
||||||
|
],
|
||||||
|
&entry_place,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
let result_place = this.deref_pointer(result_op)?;
|
let result_place = this.deref_pointer(result_op)?;
|
||||||
this.write_scalar(this.read_scalar(entry_op)?, &result_place)?;
|
this.write_scalar(this.read_scalar(entry_op)?, &result_place)?;
|
||||||
|
@ -40,18 +40,18 @@ fn emulate_foreign_item_inner(
|
|||||||
"stat" | "stat64" | "stat$INODE64" => {
|
"stat" | "stat64" | "stat$INODE64" => {
|
||||||
let [path, buf] =
|
let [path, buf] =
|
||||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||||
let result = this.macos_stat(path, buf)?;
|
let result = this.macos_fbsd_stat(path, buf)?;
|
||||||
this.write_scalar(result, dest)?;
|
this.write_scalar(result, dest)?;
|
||||||
}
|
}
|
||||||
"lstat" | "lstat64" | "lstat$INODE64" => {
|
"lstat" | "lstat64" | "lstat$INODE64" => {
|
||||||
let [path, buf] =
|
let [path, buf] =
|
||||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||||
let result = this.macos_lstat(path, buf)?;
|
let result = this.macos_fbsd_lstat(path, buf)?;
|
||||||
this.write_scalar(result, dest)?;
|
this.write_scalar(result, dest)?;
|
||||||
}
|
}
|
||||||
"fstat" | "fstat64" | "fstat$INODE64" => {
|
"fstat" | "fstat64" | "fstat$INODE64" => {
|
||||||
let [fd, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
let [fd, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||||
let result = this.macos_fstat(fd, buf)?;
|
let result = this.macos_fbsd_fstat(fd, buf)?;
|
||||||
this.write_scalar(result, dest)?;
|
this.write_scalar(result, dest)?;
|
||||||
}
|
}
|
||||||
"opendir$INODE64" => {
|
"opendir$INODE64" => {
|
||||||
@ -62,14 +62,7 @@ fn emulate_foreign_item_inner(
|
|||||||
"readdir_r" | "readdir_r$INODE64" => {
|
"readdir_r" | "readdir_r$INODE64" => {
|
||||||
let [dirp, entry, result] =
|
let [dirp, entry, result] =
|
||||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||||
let result = this.macos_readdir_r(dirp, entry, result)?;
|
let result = this.macos_fbsd_readdir_r(dirp, entry, result)?;
|
||||||
this.write_scalar(result, dest)?;
|
|
||||||
}
|
|
||||||
"lseek" => {
|
|
||||||
let [fd, offset, whence] =
|
|
||||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
|
||||||
// macOS is 64bit-only, so this is lseek64
|
|
||||||
let result = this.lseek64(fd, offset, whence)?;
|
|
||||||
this.write_scalar(result, dest)?;
|
this.write_scalar(result, dest)?;
|
||||||
}
|
}
|
||||||
"realpath$DARWIN_EXTSN" => {
|
"realpath$DARWIN_EXTSN" => {
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
//@ignore-target-windows: no libc on Windows
|
//@ignore-target-windows: no libc on Windows
|
||||||
//@ignore-target-freebsd: FIXME needs foreign function `stat@FBSD_1.0`
|
|
||||||
//@compile-flags: -Zmiri-isolation-error=warn-nobacktrace
|
//@compile-flags: -Zmiri-isolation-error=warn-nobacktrace
|
||||||
//@normalize-stderr-test: "(stat(x)?)" -> "$$STAT"
|
//@normalize-stderr-test: "(stat(x)?)" -> "$$STAT"
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user