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);
|
||||
}
|
||||
|
||||
/// 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,
|
||||
/// 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.
|
||||
|
@ -155,6 +155,17 @@ fn emulate_foreign_item_inner(
|
||||
}
|
||||
"lseek64" => {
|
||||
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)?;
|
||||
this.write_scalar(result, dest)?;
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
use crate::*;
|
||||
use shims::foreign_items::EmulateForeignItemResult;
|
||||
use shims::unix::fs::EvalContextExt as _;
|
||||
use shims::unix::thread::EvalContextExt as _;
|
||||
|
||||
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)?;
|
||||
}
|
||||
|
||||
// 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
|
||||
"__error" => {
|
||||
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
|
@ -827,24 +827,20 @@ fn write(
|
||||
|
||||
fn lseek64(
|
||||
&mut self,
|
||||
fd_op: &OpTy<'tcx, Provenance>,
|
||||
offset_op: &OpTy<'tcx, Provenance>,
|
||||
whence_op: &OpTy<'tcx, Provenance>,
|
||||
fd: i32,
|
||||
offset: i128,
|
||||
whence: i32,
|
||||
) -> InterpResult<'tcx, Scalar<Provenance>> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
// 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") {
|
||||
SeekFrom::Start(u64::try_from(offset).unwrap())
|
||||
} 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") {
|
||||
SeekFrom::End(offset)
|
||||
SeekFrom::End(i64::try_from(offset).unwrap())
|
||||
} else {
|
||||
let einval = this.eval_libc("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)
|
||||
}
|
||||
|
||||
fn macos_stat(
|
||||
fn macos_fbsd_stat(
|
||||
&mut self,
|
||||
path_op: &OpTy<'tcx, Provenance>,
|
||||
buf_op: &OpTy<'tcx, Provenance>,
|
||||
) -> InterpResult<'tcx, Scalar<Provenance>> {
|
||||
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 = this.read_path_from_c_str(path_scalar)?.into_owned();
|
||||
@ -940,13 +939,16 @@ fn macos_stat(
|
||||
}
|
||||
|
||||
// `lstat` is used to get symlink metadata.
|
||||
fn macos_lstat(
|
||||
fn macos_fbsd_lstat(
|
||||
&mut self,
|
||||
path_op: &OpTy<'tcx, Provenance>,
|
||||
buf_op: &OpTy<'tcx, Provenance>,
|
||||
) -> InterpResult<'tcx, Scalar<Provenance>> {
|
||||
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 = 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)?))
|
||||
}
|
||||
|
||||
fn macos_fstat(
|
||||
fn macos_fbsd_fstat(
|
||||
&mut self,
|
||||
fd_op: &OpTy<'tcx, Provenance>,
|
||||
buf_op: &OpTy<'tcx, Provenance>,
|
||||
) -> InterpResult<'tcx, Scalar<Provenance>> {
|
||||
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()?;
|
||||
|
||||
@ -1213,7 +1217,7 @@ fn mkdir(
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
#[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()?)
|
||||
} else {
|
||||
this.read_scalar(mode_op)?.to_u32()?
|
||||
@ -1385,7 +1389,7 @@ fn linux_readdir64(
|
||||
Ok(Scalar::from_maybe_pointer(entry, this))
|
||||
}
|
||||
|
||||
fn macos_readdir_r(
|
||||
fn macos_fbsd_readdir_r(
|
||||
&mut self,
|
||||
dirp_op: &OpTy<'tcx, Provenance>,
|
||||
entry_op: &OpTy<'tcx, Provenance>,
|
||||
@ -1393,7 +1397,9 @@ fn macos_readdir_r(
|
||||
) -> InterpResult<'tcx, Scalar<Provenance>> {
|
||||
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)?;
|
||||
|
||||
@ -1424,7 +1430,7 @@ fn macos_readdir_r(
|
||||
// }
|
||||
|
||||
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 (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())?;
|
||||
|
||||
this.write_int_fields_named(
|
||||
&[
|
||||
("d_ino", ino.into()),
|
||||
("d_seekoff", 0),
|
||||
("d_reclen", 0),
|
||||
("d_namlen", file_name_len.into()),
|
||||
("d_type", file_type.into()),
|
||||
],
|
||||
&entry_place,
|
||||
)?;
|
||||
// macOS offset field is d_seekoff
|
||||
if this.projectable_has_field(&entry_place, "d_seekoff") {
|
||||
this.write_int_fields_named(
|
||||
&[
|
||||
("d_ino", ino.into()),
|
||||
("d_seekoff", 0),
|
||||
("d_reclen", 0),
|
||||
("d_namlen", file_name_len.into()),
|
||||
("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)?;
|
||||
this.write_scalar(this.read_scalar(entry_op)?, &result_place)?;
|
||||
|
@ -40,18 +40,18 @@ fn emulate_foreign_item_inner(
|
||||
"stat" | "stat64" | "stat$INODE64" => {
|
||||
let [path, buf] =
|
||||
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)?;
|
||||
}
|
||||
"lstat" | "lstat64" | "lstat$INODE64" => {
|
||||
let [path, buf] =
|
||||
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)?;
|
||||
}
|
||||
"fstat" | "fstat64" | "fstat$INODE64" => {
|
||||
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)?;
|
||||
}
|
||||
"opendir$INODE64" => {
|
||||
@ -62,14 +62,7 @@ fn emulate_foreign_item_inner(
|
||||
"readdir_r" | "readdir_r$INODE64" => {
|
||||
let [dirp, entry, result] =
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let result = this.macos_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)?;
|
||||
let result = this.macos_fbsd_readdir_r(dirp, entry, result)?;
|
||||
this.write_scalar(result, dest)?;
|
||||
}
|
||||
"realpath$DARWIN_EXTSN" => {
|
||||
|
@ -1,5 +1,4 @@
|
||||
//@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
|
||||
//@normalize-stderr-test: "(stat(x)?)" -> "$$STAT"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user