summaryrefslogtreecommitdiff
path: root/src/sys/ptrace
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2018-10-21 17:23:58 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2018-10-21 17:23:58 +0000
commit9ed9a1dccb98e6a2f91269c09e49641c4ff395b8 (patch)
tree588c18b2f92397d9593ef1726ad7b6b2514952a4 /src/sys/ptrace
parenteef3a432d57e8f830e05fede6e3099dcb689aa6b (diff)
parentf1573a7efa8368507d581adeb3bff9bbf5aa0ead (diff)
downloadnix-9ed9a1dccb98e6a2f91269c09e49641c4ff395b8.zip
Merge #949
949: ptrace support for BSDs r=Susurrus a=xd009642 This PR adds support to the ptrace API for BSDs to close #947. It also adds a read and write method for reading and writing to a traced processes memory. The ptrace API created for linux offers this via a deprecated function so I added this so they can be feature equivalent without replicating a deprecated part of the API. Due to the differences in ptrace on BSD and linux I've made a ptrace module to keep things readable. Still to do - revert travis config to remove my feature branch and update the changelog. Co-authored-by: xd009642 <danielmckenna93@gmail.com>
Diffstat (limited to 'src/sys/ptrace')
-rw-r--r--src/sys/ptrace/bsd.rs170
-rw-r--r--src/sys/ptrace/linux.rs380
-rw-r--r--src/sys/ptrace/mod.rs22
3 files changed, 572 insertions, 0 deletions
diff --git a/src/sys/ptrace/bsd.rs b/src/sys/ptrace/bsd.rs
new file mode 100644
index 00000000..71cfd80a
--- /dev/null
+++ b/src/sys/ptrace/bsd.rs
@@ -0,0 +1,170 @@
+use errno::Errno;
+use libc::{self, c_int};
+use std::ptr;
+use sys::signal::Signal;
+use unistd::Pid;
+use Result;
+
+pub type RequestType = c_int;
+
+cfg_if! {
+ if #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "macos",
+ target_os = "openbsd"))] {
+ #[doc(hidden)]
+ pub type AddressType = *mut ::libc::c_char;
+ } else {
+ #[doc(hidden)]
+ pub type AddressType = *mut ::libc::c_void;
+ }
+}
+
+libc_enum! {
+ #[repr(i32)]
+ /// Ptrace Request enum defining the action to be taken.
+ pub enum Request {
+ PT_TRACE_ME,
+ PT_READ_I,
+ PT_READ_D,
+ #[cfg(target_os = "macos")]
+ PT_READ_U,
+ PT_WRITE_I,
+ PT_WRITE_D,
+ #[cfg(target_os = "macos")]
+ PT_WRITE_U,
+ PT_CONTINUE,
+ PT_KILL,
+ #[cfg(any(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "macos"),
+ all(target_os = "openbsd", target_arch = "x86_64"),
+ all(target_os = "netbsd", any(target_arch = "x86_64",
+ target_arch = "powerpc"))))]
+ PT_STEP,
+ PT_ATTACH,
+ PT_DETACH,
+ #[cfg(target_os = "macos")]
+ PT_SIGEXC,
+ #[cfg(target_os = "macos")]
+ PT_THUPDATE,
+ #[cfg(target_os = "macos")]
+ PT_ATTACHEXC
+ }
+}
+
+unsafe fn ptrace_other(
+ request: Request,
+ pid: Pid,
+ addr: AddressType,
+ data: c_int,
+) -> Result<c_int> {
+ Errno::result(libc::ptrace(
+ request as RequestType,
+ libc::pid_t::from(pid),
+ addr,
+ data,
+ )).map(|_| 0)
+}
+
+/// Sets the process as traceable, as with `ptrace(PT_TRACEME, ...)`
+///
+/// Indicates that this process is to be traced by its parent.
+/// This is the only ptrace request to be issued by the tracee.
+pub fn traceme() -> Result<()> {
+ unsafe { ptrace_other(Request::PT_TRACE_ME, Pid::from_raw(0), ptr::null_mut(), 0).map(|_| ()) }
+}
+
+/// Attach to a running process, as with `ptrace(PT_ATTACH, ...)`
+///
+/// Attaches to the process specified in pid, making it a tracee of the calling process.
+pub fn attach(pid: Pid) -> Result<()> {
+ unsafe { ptrace_other(Request::PT_ATTACH, pid, ptr::null_mut(), 0).map(|_| ()) }
+}
+
+/// Detaches the current running process, as with `ptrace(PT_DETACH, ...)`
+///
+/// Detaches from the process specified in pid allowing it to run freely
+pub fn detach(pid: Pid) -> Result<()> {
+ unsafe { ptrace_other(Request::PT_DETACH, pid, ptr::null_mut(), 0).map(|_| ()) }
+}
+
+/// Restart the stopped tracee process, as with `ptrace(PTRACE_CONT, ...)`
+///
+/// Continues the execution of the process with PID `pid`, optionally
+/// delivering a signal specified by `sig`.
+pub fn cont<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
+ let data = match sig.into() {
+ Some(s) => s as c_int,
+ None => 0,
+ };
+ unsafe {
+ // Ignore the useless return value
+ ptrace_other(Request::PT_CONTINUE, pid, 1 as AddressType, data).map(|_| ())
+ }
+}
+
+/// Issues a kill request as with `ptrace(PT_KILL, ...)`
+///
+/// This request is equivalent to `ptrace(PT_CONTINUE, ..., SIGKILL);`
+pub fn kill(pid: Pid) -> Result<()> {
+ unsafe {
+ ptrace_other(Request::PT_KILL, pid, 0 as AddressType, 0).map(|_| ())
+ }
+}
+
+/// Move the stopped tracee process forward by a single step as with
+/// `ptrace(PT_STEP, ...)`
+///
+/// Advances the execution of the process with PID `pid` by a single step optionally delivering a
+/// signal specified by `sig`.
+///
+/// # Example
+/// ```rust
+/// extern crate nix;
+/// use nix::sys::ptrace::step;
+/// use nix::unistd::Pid;
+/// use nix::sys::signal::Signal;
+/// use nix::sys::wait::*;
+/// fn main() {
+/// // If a process changes state to the stopped state because of a SIGUSR1
+/// // signal, this will step the process forward and forward the user
+/// // signal to the stopped process
+/// match waitpid(Pid::from_raw(-1), None) {
+/// Ok(WaitStatus::Stopped(pid, Signal::SIGUSR1)) => {
+/// let _ = step(pid, Signal::SIGUSR1);
+/// }
+/// _ => {},
+/// }
+/// }
+/// ```
+#[cfg(
+ any(
+ any(target_os = "dragonfly", target_os = "freebsd", target_os = "macos"),
+ all(target_os = "openbsd", target_arch = "x86_64"),
+ all(target_os = "netbsd",
+ any(target_arch = "x86_64", target_arch = "powerpc")
+ )
+ )
+)]
+pub fn step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
+ let data = match sig.into() {
+ Some(s) => s as c_int,
+ None => 0,
+ };
+ unsafe { ptrace_other(Request::PT_STEP, pid, ptr::null_mut(), data).map(|_| ()) }
+}
+
+/// Reads a word from a processes memory at the given address
+pub fn read(pid: Pid, addr: AddressType) -> Result<c_int> {
+ unsafe {
+ // Traditionally there was a difference between reading data or
+ // instruction memory but not in modern systems.
+ ptrace_other(Request::PT_READ_D, pid, addr, 0)
+ }
+}
+
+/// Writes a word into the processes memory at the given address
+pub fn write(pid: Pid, addr: AddressType, data: c_int) -> Result<()> {
+ unsafe { ptrace_other(Request::PT_WRITE_D, pid, addr, data).map(|_| ()) }
+}
diff --git a/src/sys/ptrace/linux.rs b/src/sys/ptrace/linux.rs
new file mode 100644
index 00000000..70404ade
--- /dev/null
+++ b/src/sys/ptrace/linux.rs
@@ -0,0 +1,380 @@
+//! For detailed description of the ptrace requests, consult `man ptrace`.
+
+use std::{mem, ptr};
+use {Error, Result};
+use errno::Errno;
+use libc::{self, c_void, c_long, siginfo_t};
+use ::unistd::Pid;
+use sys::signal::Signal;
+
+
+cfg_if! {
+ if #[cfg(any(all(target_os = "linux", arch = "s390x"),
+ all(target_os = "linux", target_env = "gnu")))] {
+ #[doc(hidden)]
+ pub type RequestType = ::libc::c_uint;
+ } else {
+ #[doc(hidden)]
+ pub type RequestType = ::libc::c_int;
+ }
+}
+
+libc_enum!{
+ #[cfg_attr(not(any(target_env = "musl", target_os = "android")), repr(u32))]
+ #[cfg_attr(any(target_env = "musl", target_os = "android"), repr(i32))]
+ /// Ptrace Request enum defining the action to be taken.
+ pub enum Request {
+ PTRACE_TRACEME,
+ PTRACE_PEEKTEXT,
+ PTRACE_PEEKDATA,
+ PTRACE_PEEKUSER,
+ PTRACE_POKETEXT,
+ PTRACE_POKEDATA,
+ PTRACE_POKEUSER,
+ PTRACE_CONT,
+ PTRACE_KILL,
+ PTRACE_SINGLESTEP,
+ #[cfg(any(all(target_os = "android", target_pointer_width = "32"),
+ all(target_os = "linux", any(target_env = "musl",
+ target_arch = "mips",
+ target_arch = "mips64",
+ target_arch = "s390x",
+ target_arch = "x86_64",
+ target_pointer_width = "32"))))]
+ PTRACE_GETREGS,
+ #[cfg(any(all(target_os = "android", target_pointer_width = "32"),
+ all(target_os = "linux", any(target_env = "musl",
+ target_arch = "mips",
+ target_arch = "mips64",
+ target_arch = "s390x",
+ target_arch = "x86_64",
+ target_pointer_width = "32"))))]
+ PTRACE_SETREGS,
+ #[cfg(any(all(target_os = "android", target_pointer_width = "32"),
+ all(target_os = "linux", any(target_env = "musl",
+ target_arch = "mips",
+ target_arch = "mips64",
+ target_arch = "s390x",
+ target_arch = "x86_64",
+ target_pointer_width = "32"))))]
+ PTRACE_GETFPREGS,
+ #[cfg(any(all(target_os = "android", target_pointer_width = "32"),
+ all(target_os = "linux", any(target_env = "musl",
+ target_arch = "mips",
+ target_arch = "mips64",
+ target_arch = "s390x",
+ target_arch = "x86_64",
+ target_pointer_width = "32"))))]
+ PTRACE_SETFPREGS,
+ PTRACE_ATTACH,
+ PTRACE_DETACH,
+ #[cfg(all(target_os = "linux", any(target_env = "musl",
+ target_arch = "mips",
+ target_arch = "mips64",
+ target_arch = "arm",
+ target_arch = "x86",
+ target_arch = "x86_64")))]
+ PTRACE_GETFPXREGS,
+ #[cfg(all(target_os = "linux", any(target_env = "musl",
+ target_arch = "mips",
+ target_arch = "mips64",
+ target_arch = "arm",
+ target_arch = "x86",
+ target_arch = "x86_64")))]
+ PTRACE_SETFPXREGS,
+ PTRACE_SYSCALL,
+ PTRACE_SETOPTIONS,
+ PTRACE_GETEVENTMSG,
+ PTRACE_GETSIGINFO,
+ PTRACE_SETSIGINFO,
+ #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
+ target_arch = "mips64"))))]
+ PTRACE_GETREGSET,
+ #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
+ target_arch = "mips64"))))]
+ PTRACE_SETREGSET,
+ #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
+ target_arch = "mips64"))))]
+ PTRACE_SEIZE,
+ #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
+ target_arch = "mips64"))))]
+ PTRACE_INTERRUPT,
+ #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
+ target_arch = "mips64"))))]
+ PTRACE_LISTEN,
+ #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
+ target_arch = "mips64"))))]
+ PTRACE_PEEKSIGINFO,
+ }
+}
+
+libc_enum!{
+ #[repr(i32)]
+ /// Using the ptrace options the tracer can configure the tracee to stop
+ /// at certain events. This enum is used to define those events as defined
+ /// in `man ptrace`.
+ pub enum Event {
+ /// Event that stops before a return from fork or clone.
+ PTRACE_EVENT_FORK,
+ /// Event that stops before a return from vfork or clone.
+ PTRACE_EVENT_VFORK,
+ /// Event that stops before a return from clone.
+ PTRACE_EVENT_CLONE,
+ /// Event that stops before a return from execve.
+ PTRACE_EVENT_EXEC,
+ /// Event for a return from vfork.
+ PTRACE_EVENT_VFORK_DONE,
+ /// Event for a stop before an exit. Unlike the waitpid Exit status program.
+ /// registers can still be examined
+ PTRACE_EVENT_EXIT,
+ /// STop triggered by a seccomp rule on a tracee.
+ PTRACE_EVENT_SECCOMP,
+ // PTRACE_EVENT_STOP not provided by libc because it's defined in glibc 2.26
+ }
+}
+
+libc_bitflags! {
+ /// Ptrace options used in conjunction with the PTRACE_SETOPTIONS request.
+ /// See `man ptrace` for more details.
+ pub struct Options: libc::c_int {
+ /// When delivering system call traps set a bit to allow tracer to
+ /// distinguish between normal stops or syscall stops. May not work on
+ /// all systems.
+ PTRACE_O_TRACESYSGOOD;
+ /// Stop tracee at next fork and start tracing the forked process.
+ PTRACE_O_TRACEFORK;
+ /// Stop tracee at next vfork call and trace the vforked process.
+ PTRACE_O_TRACEVFORK;
+ /// Stop tracee at next clone call and trace the cloned process.
+ PTRACE_O_TRACECLONE;
+ /// Stop tracee at next execve call.
+ PTRACE_O_TRACEEXEC;
+ /// Stop tracee at vfork completion.
+ PTRACE_O_TRACEVFORKDONE;
+ /// Stop tracee at next exit call. Stops before exit commences allowing
+ /// tracer to see location of exit and register states.
+ PTRACE_O_TRACEEXIT;
+ /// Stop tracee when a SECCOMP_RET_TRACE rule is triggered. See `man seccomp` for more
+ /// details.
+ PTRACE_O_TRACESECCOMP;
+ /// Send a SIGKILL to the tracee if the tracer exits. This is useful
+ /// for ptrace jailers to prevent tracees from escaping their control.
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ PTRACE_O_EXITKILL;
+ }
+}
+
+/// Performs a ptrace request. If the request in question is provided by a specialised function
+/// this function will return an unsupported operation error.
+#[deprecated(
+ since="0.10.0",
+ note="usages of `ptrace()` should be replaced with the specialized helper functions instead"
+)]
+pub unsafe fn ptrace(request: Request, pid: Pid, addr: *mut c_void, data: *mut c_void) -> Result<c_long> {
+ use self::Request::*;
+ match request {
+ PTRACE_PEEKTEXT | PTRACE_PEEKDATA | PTRACE_PEEKUSER | PTRACE_GETSIGINFO |
+ PTRACE_GETEVENTMSG | PTRACE_SETSIGINFO | PTRACE_SETOPTIONS |
+ PTRACE_POKETEXT | PTRACE_POKEDATA | PTRACE_POKEUSER |
+ PTRACE_KILL => Err(Error::UnsupportedOperation),
+ _ => ptrace_other(request, pid, addr, data)
+ }
+}
+
+fn ptrace_peek(request: Request, pid: Pid, addr: *mut c_void, data: *mut c_void) -> Result<c_long> {
+ let ret = unsafe {
+ Errno::clear();
+ libc::ptrace(request as RequestType, libc::pid_t::from(pid), addr, data)
+ };
+ match Errno::result(ret) {
+ Ok(..) | Err(Error::Sys(Errno::UnknownErrno)) => Ok(ret),
+ err @ Err(..) => err,
+ }
+}
+
+/// Function for ptrace requests that return values from the data field.
+/// Some ptrace get requests populate structs or larger elements than `c_long`
+/// and therefore use the data field to return values. This function handles these
+/// requests.
+fn ptrace_get_data<T>(request: Request, pid: Pid) -> Result<T> {
+ // Creates an uninitialized pointer to store result in
+ let data: T = unsafe { mem::uninitialized() };
+ let res = unsafe {
+ libc::ptrace(request as RequestType,
+ libc::pid_t::from(pid),
+ ptr::null_mut::<T>(),
+ &data as *const _ as *const c_void)
+ };
+ Errno::result(res)?;
+ Ok(data)
+}
+
+unsafe fn ptrace_other(request: Request, pid: Pid, addr: *mut c_void, data: *mut c_void) -> Result<c_long> {
+ Errno::result(libc::ptrace(request as RequestType, libc::pid_t::from(pid), addr, data)).map(|_| 0)
+}
+
+/// Set options, as with `ptrace(PTRACE_SETOPTIONS,...)`.
+pub fn setoptions(pid: Pid, options: Options) -> Result<()> {
+ use std::ptr;
+
+ let res = unsafe {
+ libc::ptrace(Request::PTRACE_SETOPTIONS as RequestType,
+ libc::pid_t::from(pid),
+ ptr::null_mut::<c_void>(),
+ options.bits() as *mut c_void)
+ };
+ Errno::result(res).map(|_| ())
+}
+
+/// Gets a ptrace event as described by `ptrace(PTRACE_GETEVENTMSG,...)`
+pub fn getevent(pid: Pid) -> Result<c_long> {
+ ptrace_get_data::<c_long>(Request::PTRACE_GETEVENTMSG, pid)
+}
+
+/// Get siginfo as with `ptrace(PTRACE_GETSIGINFO,...)`
+pub fn getsiginfo(pid: Pid) -> Result<siginfo_t> {
+ ptrace_get_data::<siginfo_t>(Request::PTRACE_GETSIGINFO, pid)
+}
+
+/// Set siginfo as with `ptrace(PTRACE_SETSIGINFO,...)`
+pub fn setsiginfo(pid: Pid, sig: &siginfo_t) -> Result<()> {
+ let ret = unsafe{
+ Errno::clear();
+ libc::ptrace(Request::PTRACE_SETSIGINFO as RequestType,
+ libc::pid_t::from(pid),
+ ptr::null_mut::<c_void>(),
+ sig as *const _ as *const c_void)
+ };
+ match Errno::result(ret) {
+ Ok(_) => Ok(()),
+ Err(e) => Err(e),
+ }
+}
+
+/// Sets the process as traceable, as with `ptrace(PTRACE_TRACEME, ...)`
+///
+/// Indicates that this process is to be traced by its parent.
+/// This is the only ptrace request to be issued by the tracee.
+pub fn traceme() -> Result<()> {
+ unsafe {
+ ptrace_other(
+ Request::PTRACE_TRACEME,
+ Pid::from_raw(0),
+ ptr::null_mut(),
+ ptr::null_mut(),
+ ).map(|_| ()) // ignore the useless return value
+ }
+}
+
+/// Ask for next syscall, as with `ptrace(PTRACE_SYSCALL, ...)`
+///
+/// Arranges for the tracee to be stopped at the next entry to or exit from a system call.
+pub fn syscall(pid: Pid) -> Result<()> {
+ unsafe {
+ ptrace_other(
+ Request::PTRACE_SYSCALL,
+ pid,
+ ptr::null_mut(),
+ ptr::null_mut(),
+ ).map(|_| ()) // ignore the useless return value
+ }
+}
+
+/// Attach to a running process, as with `ptrace(PTRACE_ATTACH, ...)`
+///
+/// Attaches to the process specified in pid, making it a tracee of the calling process.
+pub fn attach(pid: Pid) -> Result<()> {
+ unsafe {
+ ptrace_other(
+ Request::PTRACE_ATTACH,
+ pid,
+ ptr::null_mut(),
+ ptr::null_mut(),
+ ).map(|_| ()) // ignore the useless return value
+ }
+}
+
+/// Detaches the current running process, as with `ptrace(PTRACE_DETACH, ...)`
+///
+/// Detaches from the process specified in pid allowing it to run freely
+pub fn detach(pid: Pid) -> Result<()> {
+ unsafe {
+ ptrace_other(
+ Request::PTRACE_DETACH,
+ pid,
+ ptr::null_mut(),
+ ptr::null_mut()
+ ).map(|_| ())
+ }
+}
+
+/// Restart the stopped tracee process, as with `ptrace(PTRACE_CONT, ...)`
+///
+/// Continues the execution of the process with PID `pid`, optionally
+/// delivering a signal specified by `sig`.
+pub fn cont<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
+ let data = match sig.into() {
+ Some(s) => s as i32 as *mut c_void,
+ None => ptr::null_mut(),
+ };
+ unsafe {
+ ptrace_other(Request::PTRACE_CONT, pid, ptr::null_mut(), data).map(|_| ()) // ignore the useless return value
+ }
+}
+
+/// Issues a kill request as with `ptrace(PTRACE_KILL, ...)`
+///
+/// This request is equivalent to `ptrace(PTRACE_CONT, ..., SIGKILL);`
+pub fn kill(pid: Pid) -> Result<()> {
+ unsafe {
+ ptrace_other(Request::PTRACE_KILL, pid, ptr::null_mut(), ptr::null_mut()).map(|_| ())
+ }
+}
+
+/// Move the stopped tracee process forward by a single step as with
+/// `ptrace(PTRACE_SINGLESTEP, ...)`
+///
+/// Advances the execution of the process with PID `pid` by a single step optionally delivering a
+/// signal specified by `sig`.
+///
+/// # Example
+/// ```rust
+/// extern crate nix;
+/// use nix::sys::ptrace::step;
+/// use nix::unistd::Pid;
+/// use nix::sys::signal::Signal;
+/// use nix::sys::wait::*;
+/// fn main() {
+/// // If a process changes state to the stopped state because of a SIGUSR1
+/// // signal, this will step the process forward and forward the user
+/// // signal to the stopped process
+/// match waitpid(Pid::from_raw(-1), None) {
+/// Ok(WaitStatus::Stopped(pid, Signal::SIGUSR1)) => {
+/// let _ = step(pid, Signal::SIGUSR1);
+/// }
+/// _ => {},
+/// }
+/// }
+/// ```
+pub fn step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
+ let data = match sig.into() {
+ Some(s) => s as i32 as *mut c_void,
+ None => ptr::null_mut(),
+ };
+ unsafe {
+ ptrace_other(Request::PTRACE_SINGLESTEP, pid, ptr::null_mut(), data).map(|_| ())
+ }
+}
+
+
+/// Reads a word from a processes memory at the given address
+pub fn read(pid: Pid, addr: *mut c_void) -> Result<c_long> {
+ ptrace_peek(Request::PTRACE_PEEKDATA, pid, addr, ptr::null_mut())
+}
+
+/// Writes a word into the processes memory at the given address
+pub fn write(pid: Pid, addr: *mut c_void, data: *mut c_void) -> Result<()> {
+ unsafe {
+ ptrace_other(Request::PTRACE_POKEDATA, pid, addr, data).map(|_| ())
+ }
+}
diff --git a/src/sys/ptrace/mod.rs b/src/sys/ptrace/mod.rs
new file mode 100644
index 00000000..782c3040
--- /dev/null
+++ b/src/sys/ptrace/mod.rs
@@ -0,0 +1,22 @@
+///! Provides helpers for making ptrace system calls
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+mod linux;
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+pub use self::linux::*;
+
+#[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+mod bsd;
+
+#[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
+pub use self::bsd::*;