miri/shims/unix/freebsd/
foreign_items.rs

1use rustc_middle::ty::Ty;
2use rustc_span::Symbol;
3use rustc_target::callconv::{Conv, FnAbi};
4
5use crate::shims::unix::*;
6use crate::*;
7
8pub fn is_dyn_sym(_name: &str) -> bool {
9    false
10}
11
12impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
13pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
14    fn emulate_foreign_item_inner(
15        &mut self,
16        link_name: Symbol,
17        abi: &FnAbi<'tcx, Ty<'tcx>>,
18        args: &[OpTy<'tcx>],
19        dest: &MPlaceTy<'tcx>,
20    ) -> InterpResult<'tcx, EmulateItemResult> {
21        let this = self.eval_context_mut();
22        match link_name.as_str() {
23            // Threading
24            "pthread_setname_np" => {
25                let [thread, name] = this.check_shim(abi, Conv::C, link_name, args)?;
26                let max_len = usize::MAX; // FreeBSD does not seem to have a limit.
27                let res = match this.pthread_setname_np(
28                    this.read_scalar(thread)?,
29                    this.read_scalar(name)?,
30                    max_len,
31                    /* truncate */ false,
32                )? {
33                    ThreadNameResult::Ok => Scalar::from_u32(0),
34                    ThreadNameResult::NameTooLong => unreachable!(),
35                    ThreadNameResult::ThreadNotFound => this.eval_libc("ESRCH"),
36                };
37                this.write_scalar(res, dest)?;
38            }
39            "pthread_getname_np" => {
40                let [thread, name, len] = this.check_shim(abi, Conv::C, link_name, args)?;
41                // FreeBSD's pthread_getname_np uses strlcpy, which truncates the resulting value,
42                // but always adds a null terminator (except for zero-sized buffers).
43                // https://github.com/freebsd/freebsd-src/blob/c2d93a803acef634bd0eede6673aeea59e90c277/lib/libthr/thread/thr_info.c#L119-L144
44                let res = match this.pthread_getname_np(
45                    this.read_scalar(thread)?,
46                    this.read_scalar(name)?,
47                    this.read_scalar(len)?,
48                    /* truncate */ true,
49                )? {
50                    ThreadNameResult::Ok => Scalar::from_u32(0),
51                    // `NameTooLong` is possible when the buffer is zero sized,
52                    ThreadNameResult::NameTooLong => Scalar::from_u32(0),
53                    ThreadNameResult::ThreadNotFound => this.eval_libc("ESRCH"),
54                };
55                this.write_scalar(res, dest)?;
56            }
57
58            // File related shims
59            // For those, we both intercept `func` and `call@FBSD_1.0` symbols cases
60            // since freebsd 12 the former form can be expected.
61            "stat" | "stat@FBSD_1.0" => {
62                let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?;
63                let result = this.macos_fbsd_solarish_stat(path, buf)?;
64                this.write_scalar(result, dest)?;
65            }
66            "lstat" | "lstat@FBSD_1.0" => {
67                let [path, buf] = this.check_shim(abi, Conv::C, link_name, args)?;
68                let result = this.macos_fbsd_solarish_lstat(path, buf)?;
69                this.write_scalar(result, dest)?;
70            }
71            "fstat" | "fstat@FBSD_1.0" => {
72                let [fd, buf] = this.check_shim(abi, Conv::C, link_name, args)?;
73                let result = this.macos_fbsd_solarish_fstat(fd, buf)?;
74                this.write_scalar(result, dest)?;
75            }
76            "readdir_r" | "readdir_r@FBSD_1.0" => {
77                let [dirp, entry, result] = this.check_shim(abi, Conv::C, link_name, args)?;
78                let result = this.macos_fbsd_readdir_r(dirp, entry, result)?;
79                this.write_scalar(result, dest)?;
80            }
81
82            // Miscellaneous
83            "__error" => {
84                let [] = this.check_shim(abi, Conv::C, link_name, args)?;
85                let errno_place = this.last_error_place()?;
86                this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
87            }
88
89            // Incomplete shims that we "stub out" just to get pre-main initialization code to work.
90            // These shims are enabled only when the caller is in the standard library.
91            "pthread_attr_get_np" if this.frame_in_std() => {
92                let [_thread, _attr] = this.check_shim(abi, Conv::C, link_name, args)?;
93                this.write_null(dest)?;
94            }
95
96            _ => return interp_ok(EmulateItemResult::NotSupported),
97        }
98        interp_ok(EmulateItemResult::NeedsReturn)
99    }
100}