Commit 0e1e7d5d authored by Jeremy Soller's avatar Jeremy Soller

Merge branch 'ptrace-6' into 'master'

Ptrace overhaul & bitflags

See merge request redox-os/syscall!40
parents 9e9f47d2 bf5e138d
......@@ -6,6 +6,10 @@ license = "MIT"
authors = ["Jeremy Soller <jackpot51@gmail.com>"]
repository = "https://gitlab.redox-os.org/redox-os/syscall"
documentation = "https://docs.rs/redox_syscall"
edition = "2018"
[lib]
name = "syscall"
[dependencies]
bitflags = "1.1.0"
use super::arch::*;
use super::data::{Map, SigAction, Stat, StatVfs, TimeSpec};
use super::error::Result;
use super::flag::*;
use super::number::*;
use core::{mem, ptr};
......@@ -52,8 +53,8 @@ pub fn chmod<T: AsRef<[u8]>>(path: T, mode: usize) -> Result<usize> {
}
/// Produce a fork of the current process, or a new process thread
pub unsafe fn clone(flags: usize) -> Result<usize> {
syscall1_clobber(SYS_CLONE, flags)
pub unsafe fn clone(flags: CloneFlags) -> Result<usize> {
syscall1_clobber(SYS_CLONE, flags.bits())
}
/// Close a file
......@@ -235,8 +236,8 @@ pub fn mkns(schemes: &[[usize; 2]]) -> Result<usize> {
}
/// Change mapping flags
pub unsafe fn mprotect(addr: usize, size: usize, flags: usize) -> Result<usize> {
syscall3(SYS_MPROTECT, addr, size, flags)
pub unsafe fn mprotect(addr: usize, size: usize, flags: MapFlags) -> Result<usize> {
syscall3(SYS_MPROTECT, addr, size, flags.bits())
}
/// Sleep for the time specified in `req`
......@@ -274,8 +275,8 @@ pub unsafe fn physfree(physical_address: usize, size: usize) -> Result<usize> {
/// # Errors
///
/// * `EPERM` - `uid != 0`
pub unsafe fn physmap(physical_address: usize, size: usize, flags: usize) -> Result<usize> {
syscall3(SYS_PHYSMAP, physical_address, size, flags)
pub unsafe fn physmap(physical_address: usize, size: usize, flags: PhysmapFlags) -> Result<usize> {
syscall3(SYS_PHYSMAP, physical_address, size, flags.bits())
}
/// Unmap previously mapped physical memory
......@@ -363,8 +364,8 @@ pub unsafe fn virttophys(virtual_address: usize) -> Result<usize> {
}
/// Check if a child process has exited or received a signal
pub fn waitpid(pid: usize, status: &mut usize, options: usize) -> Result<usize> {
unsafe { syscall3(SYS_WAITPID, pid, status as *mut usize as usize, options) }
pub fn waitpid(pid: usize, status: &mut usize, options: WaitFlags) -> Result<usize> {
unsafe { syscall3(SYS_WAITPID, pid, status as *mut usize as usize, options.bits()) }
}
/// Write a buffer to a file descriptor
......
use core::ops::{Deref, DerefMut};
use core::{fmt, mem, slice};
use core::{mem, slice};
use crate::flag::{EventFlags, MapFlags, PtraceFlags, SigActionFlags};
#[derive(Copy, Clone, Debug, Default)]
#[repr(C)]
pub struct Event {
pub id: usize,
pub flags: usize,
pub flags: EventFlags,
pub data: usize
}
......@@ -57,7 +58,7 @@ impl DerefMut for ITimerSpec {
pub struct Map {
pub offset: usize,
pub size: usize,
pub flags: usize,
pub flags: MapFlags,
}
impl Deref for Map {
......@@ -112,7 +113,7 @@ impl DerefMut for Packet {
pub struct SigAction {
pub sa_handler: Option<extern "C" fn(usize)>,
pub sa_mask: [u64; 2],
pub sa_flags: usize,
pub sa_flags: SigActionFlags,
}
#[allow(dead_code)]
......@@ -303,32 +304,16 @@ impl DerefMut for FloatRegisters {
}
}
#[derive(Clone, Copy)]
#[repr(C)]
pub union PtraceEventData {
pub clone: usize,
pub signal: usize
}
impl Default for PtraceEventData {
fn default() -> Self {
Self {
clone: 0,
}
}
}
impl fmt::Debug for PtraceEventData {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "PtraceEventData(...)")
}
}
#[derive(Clone, Copy, Debug, Default)]
#[repr(C)]
pub struct PtraceEvent {
pub tag: u16,
pub data: PtraceEventData,
pub cause: PtraceFlags,
pub a: usize,
pub b: usize,
pub c: usize,
pub d: usize,
pub e: usize,
pub f: usize
}
impl Deref for PtraceEvent {
......@@ -347,3 +332,18 @@ impl DerefMut for PtraceEvent {
}
}
}
#[macro_export]
macro_rules! ptrace_event {
($cause:expr $(, $a:expr $(, $b:expr $(, $c:expr)?)?)?) => {
PtraceEvent {
cause: $cause,
$(a: $a,
$(b: $b,
$(c: $c,)?
)?
)?
..Default::default()
}
}
}
pub const CLONE_VM: usize = 0x100;
pub const CLONE_FS: usize = 0x200;
pub const CLONE_FILES: usize = 0x400;
pub const CLONE_SIGHAND: usize = 0x800;
pub const CLONE_VFORK: usize = 0x4000;
pub const CLONE_THREAD: usize = 0x10000;
pub const CLONE_STACK: usize = 0x1000_0000;
use bitflags::bitflags as inner_bitflags;
use core::{mem, ops::Deref, slice};
macro_rules! bitflags {
(
$(#[$outer:meta])*
pub struct $BitFlags:ident: $T:ty {
$(
$(#[$inner:ident $($args:tt)*])*
const $Flag:ident = $value:expr;
)+
}
) => {
// First, use the inner bitflags
inner_bitflags! {
#[derive(Default)]
$(#[$outer])*
pub struct $BitFlags: $T {
$(
$(#[$inner $($args)*])*
const $Flag = $value;
)+
}
}
// Secondly, re-export all inner constants
// (`pub use self::Struct::*` doesn't work)
$(
$(#[$inner $($args)*])*
pub const $Flag: $BitFlags = $BitFlags::$Flag;
)+
}
}
bitflags! {
pub struct CloneFlags: usize {
const CLONE_VM = 0x100;
const CLONE_FS = 0x200;
const CLONE_FILES = 0x400;
const CLONE_SIGHAND = 0x800;
const CLONE_VFORK = 0x4000;
const CLONE_THREAD = 0x10000;
const CLONE_STACK = 0x1000_0000;
}
}
pub const CLOCK_REALTIME: usize = 1;
pub const CLOCK_MONOTONIC: usize = 4;
pub const EVENT_NONE: usize = 0;
pub const EVENT_READ: usize = 1;
pub const EVENT_WRITE: usize = 2;
bitflags! {
pub struct EventFlags: usize {
const EVENT_NONE = 0;
const EVENT_READ = 1;
const EVENT_WRITE = 2;
}
}
pub const F_DUPFD: usize = 0;
pub const F_GETFD: usize = 1;
......@@ -23,8 +65,17 @@ pub const FUTEX_WAIT: usize = 0;
pub const FUTEX_WAKE: usize = 1;
pub const FUTEX_REQUEUE: usize = 2;
pub const MAP_SHARED: usize = 0x0001;
pub const MAP_PRIVATE: usize = 0x0002;
bitflags! {
pub struct MapFlags: usize {
const PROT_NONE = 0x0000_0000;
const PROT_EXEC = 0x0001_0000;
const PROT_WRITE = 0x0002_0000;
const PROT_READ = 0x0004_0000;
const MAP_SHARED = 0x0001;
const MAP_PRIVATE = 0x0002;
}
}
pub const MODE_TYPE: u16 = 0xF000;
pub const MODE_DIR: u16 = 0x4000;
......@@ -56,26 +107,45 @@ pub const O_SYMLINK: usize = 0x4000_0000;
pub const O_NOFOLLOW: usize = 0x8000_0000;
pub const O_ACCMODE: usize = O_RDONLY | O_WRONLY | O_RDWR;
pub const PHYSMAP_WRITE: usize = 0x0000_0001;
pub const PHYSMAP_WRITE_COMBINE: usize = 0x0000_0002;
pub const PHYSMAP_NO_CACHE: usize = 0x0000_0004;
bitflags! {
pub struct PhysmapFlags: usize {
const PHYSMAP_WRITE = 0x0000_0001;
const PHYSMAP_WRITE_COMBINE = 0x0000_0002;
const PHYSMAP_NO_CACHE = 0x0000_0004;
}
}
pub const PROT_NONE: usize = 0x0000_0000;
pub const PROT_EXEC: usize = 0x0001_0000;
pub const PROT_WRITE: usize = 0x0002_0000;
pub const PROT_READ: usize = 0x0004_0000;
// The top 48 bits of PTRACE_* are reserved, for now
pub const PTRACE_CONT: u8 = 0b0000_0001;
pub const PTRACE_SINGLESTEP: u8 = 0b0000_0010;
pub const PTRACE_SYSCALL: u8 = 0b0000_0011;
pub const PTRACE_WAIT: u8 = 0b0000_0100;
pub const PTRACE_SIGNAL: u8 = 0b0000_0101;
bitflags! {
pub struct PtraceFlags: u64 {
const PTRACE_STOP_PRE_SYSCALL = 0x0000_0000_0000_0001;
const PTRACE_STOP_POST_SYSCALL = 0x0000_0000_0000_0002;
const PTRACE_STOP_SINGLESTEP = 0x0000_0000_0000_0004;
const PTRACE_STOP_SIGNAL = 0x0000_0000_0000_0008;
const PTRACE_STOP_BREAKPOINT = 0x0000_0000_0000_0010;
const PTRACE_STOP_MASK = 0x0000_0000_0000_00FF;
pub const PTRACE_OPERATIONMASK: u8 = 0b0000_1111;
pub const PTRACE_SYSEMU: u8 = 0b0001_0000;
const PTRACE_EVENT_CLONE = 0x0000_0000_0000_0100;
const PTRACE_EVENT_MASK = 0x0000_0000_0000_0F00;
pub const PTRACE_EVENT_CLONE: u16 = 0;
pub const PTRACE_EVENT_SIGNAL: u16 = 1;
const PTRACE_FLAG_IGNORE = 0x0000_0000_0000_1000;
const PTRACE_FLAG_WAIT = 0x0000_0000_0000_2000;
const PTRACE_FLAG_MASK = 0x0000_0000_0000_F000;
}
}
impl Deref for PtraceFlags {
type Target = [u8];
fn deref(&self) -> &Self::Target {
// Same as to_ne_bytes but in-place
unsafe {
slice::from_raw_parts(
&self.bits as *const _ as *const u8,
mem::size_of::<u64>()
)
}
}
}
pub const SEEK_SET: usize = 0;
pub const SEEK_CUR: usize = 1;
......@@ -120,18 +190,26 @@ pub const SIG_BLOCK: usize = 0;
pub const SIG_UNBLOCK: usize = 1;
pub const SIG_SETMASK: usize = 2;
pub const SA_NOCLDSTOP: usize = 0x00000001;
pub const SA_NOCLDWAIT: usize = 0x00000002;
pub const SA_SIGINFO: usize = 0x00000004;
pub const SA_RESTORER: usize = 0x04000000;
pub const SA_ONSTACK: usize = 0x08000000;
pub const SA_RESTART: usize = 0x10000000;
pub const SA_NODEFER: usize = 0x40000000;
pub const SA_RESETHAND: usize = 0x80000000;
pub const WNOHANG: usize = 0x01;
pub const WUNTRACED: usize = 0x02;
pub const WCONTINUED: usize = 0x08;
bitflags! {
pub struct SigActionFlags: usize {
const SA_NOCLDSTOP = 0x00000001;
const SA_NOCLDWAIT = 0x00000002;
const SA_SIGINFO = 0x00000004;
const SA_RESTORER = 0x04000000;
const SA_ONSTACK = 0x08000000;
const SA_RESTART = 0x10000000;
const SA_NODEFER = 0x40000000;
const SA_RESETHAND = 0x80000000;
}
}
bitflags! {
pub struct WaitFlags: usize {
const WNOHANG = 0x01;
const WUNTRACED = 0x02;
const WCONTINUED = 0x08;
}
}
/// True if status indicates the child is stopped.
pub fn wifstopped(status: usize) -> bool {
......
use core::{mem, ptr};
use core::ops::{Deref, DerefMut};
use Result;
use crate::Result;
struct PhysBox {
address: usize,
......@@ -10,7 +10,7 @@ struct PhysBox {
impl PhysBox {
fn new(size: usize) -> Result<PhysBox> {
let address = unsafe { ::physalloc(size)? };
let address = unsafe { crate::physalloc(size)? };
Ok(PhysBox {
address: address,
size: size
......@@ -20,7 +20,7 @@ impl PhysBox {
impl Drop for PhysBox {
fn drop(&mut self) {
let _ = unsafe { ::physfree(self.address, self.size) };
let _ = unsafe { crate::physfree(self.address, self.size) };
}
}
......@@ -32,7 +32,7 @@ pub struct Dma<T> {
impl<T> Dma<T> {
pub fn new(value: T) -> Result<Dma<T>> {
let phys = PhysBox::new(mem::size_of::<T>())?;
let virt = unsafe { ::physmap(phys.address, phys.size, ::PHYSMAP_WRITE)? } as *mut T;
let virt = unsafe { crate::physmap(phys.address, phys.size, crate::PHYSMAP_WRITE)? } as *mut T;
unsafe { ptr::write(virt, value); }
Ok(Dma {
phys: phys,
......@@ -42,7 +42,7 @@ impl<T> Dma<T> {
pub fn zeroed() -> Result<Dma<T>> {
let phys = PhysBox::new(mem::size_of::<T>())?;
let virt = unsafe { ::physmap(phys.address, phys.size, ::PHYSMAP_WRITE)? } as *mut T;
let virt = unsafe { crate::physmap(phys.address, phys.size, crate::PHYSMAP_WRITE)? } as *mut T;
unsafe { ptr::write_bytes(virt as *mut u8, 0, phys.size); }
Ok(Dma {
phys: phys,
......@@ -71,6 +71,6 @@ impl<T> DerefMut for Dma<T> {
impl<T> Drop for Dma<T> {
fn drop(&mut self) {
unsafe { drop(ptr::read(self.virt)); }
let _ = unsafe { ::physunmap(self.virt as usize) };
let _ = unsafe { crate::physunmap(self.virt as usize) };
}
}
use core::ptr::{read_volatile, write_volatile};
use core::mem::uninitialized;
use core::mem::MaybeUninit;
use core::ops::{BitAnd, BitOr, Not};
use super::io::Io;
#[repr(packed)]
pub struct Mmio<T> {
value: T,
value: MaybeUninit<T>,
}
impl<T> Mmio<T> {
/// Create a new Mmio without initializing
pub fn new() -> Self {
Mmio {
value: unsafe { uninitialized() }
value: MaybeUninit::uninit()
}
}
}
......@@ -22,10 +22,10 @@ impl<T> Io for Mmio<T> where T: Copy + PartialEq + BitAnd<Output = T> + BitOr<Ou
type Value = T;
fn read(&self) -> T {
unsafe { read_volatile(&self.value) }
unsafe { read_volatile(self.value.as_ptr()) }
}
fn write(&mut self, value: T) {
unsafe { write_volatile(&mut self.value, value) };
unsafe { write_volatile(self.value.as_mut_ptr(), value) };
}
}
#![feature(asm)]
#![feature(const_fn)]
#![feature(maybe_uninit)] // remove when Redox updates their rust version
#![cfg_attr(not(test), no_std)]
#[cfg(test)]
......
......@@ -11,7 +11,8 @@ echo "Generating SchemeBlock from Scheme"
sed 's/trait Scheme/trait SchemeBlock/' scheme.rs \
| sed 's/fn handle(\&self, packet: \&mut Packet)/fn handle(\&self, packet: \&Packet) -> Option<usize>/' \
| sed 's/packet.a = Error::mux(res);/res.transpose().map(Error::mux)/' \
| sed 's/Result<usize>/Result<Option<usize>>/g' \
| sed 's/\.map(|f| f\.bits())/\.map(|f| f.map(|f| f.bits()))/' \
| sed 's/Result<\([^>]\+\)>/Result<Option<\1>>/g' \
> scheme_block.rs
echo "Generating SchemeBlockMut from SchemeBlock"
......
use core::{mem, slice};
use data::*;
use error::*;
use number::*;
use crate::data::*;
use crate::error::*;
use crate::flag::*;
use crate::number::*;
pub trait Scheme {
fn handle(&self, packet: &mut Packet) {
......@@ -19,7 +20,7 @@ pub trait Scheme {
SYS_FCHMOD => self.fchmod(packet.b, packet.c as u16),
SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32),
SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d),
SYS_FEVENT => self.fevent(packet.b, packet.c),
SYS_FEVENT => self.fevent(packet.b, EventFlags::from_bits_truncate(packet.c)).map(|f| f.bits()),
SYS_FMAP => if packet.d >= mem::size_of::<Map>() {
self.fmap(packet.b, unsafe { &*(packet.c as *const Map) })
} else {
......@@ -111,7 +112,7 @@ pub trait Scheme {
}
#[allow(unused_variables)]
fn fevent(&self, id: usize, flags: usize) -> Result<usize> {
fn fevent(&self, id: usize, flags: EventFlags) -> Result<EventFlags> {
Err(Error::new(EBADF))
}
......
use core::{mem, slice};
use data::*;
use error::*;
use number::*;
use crate::data::*;
use crate::error::*;
use crate::flag::*;
use crate::number::*;
pub trait SchemeBlock {
fn handle(&self, packet: &Packet) -> Option<usize> {
......@@ -19,7 +20,7 @@ pub trait SchemeBlock {
SYS_FCHMOD => self.fchmod(packet.b, packet.c as u16),
SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32),
SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d),
SYS_FEVENT => self.fevent(packet.b, packet.c),
SYS_FEVENT => self.fevent(packet.b, EventFlags::from_bits_truncate(packet.c)).map(|f| f.map(|f| f.bits())),
SYS_FMAP => if packet.d >= mem::size_of::<Map>() {
self.fmap(packet.b, unsafe { &*(packet.c as *const Map) })
} else {
......@@ -111,7 +112,7 @@ pub trait SchemeBlock {
}
#[allow(unused_variables)]
fn fevent(&self, id: usize, flags: usize) -> Result<Option<usize>> {
fn fevent(&self, id: usize, flags: EventFlags) -> Result<Option<EventFlags>> {
Err(Error::new(EBADF))
}
......
use core::{mem, slice};
use data::*;
use error::*;
use number::*;
use crate::data::*;
use crate::error::*;
use crate::flag::*;
use crate::number::*;
pub trait SchemeBlockMut {
fn handle(&mut self, packet: &Packet) -> Option<usize> {
......@@ -19,7 +20,7 @@ pub trait SchemeBlockMut {
SYS_FCHMOD => self.fchmod(packet.b, packet.c as u16),
SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32),
SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d),
SYS_FEVENT => self.fevent(packet.b, packet.c),
SYS_FEVENT => self.fevent(packet.b, EventFlags::from_bits_truncate(packet.c)).map(|f| f.map(|f| f.bits())),
SYS_FMAP => if packet.d >= mem::size_of::<Map>() {
self.fmap(packet.b, unsafe { &*(packet.c as *const Map) })
} else {
......@@ -111,7 +112,7 @@ pub trait SchemeBlockMut {
}
#[allow(unused_variables)]
fn fevent(&mut self, id: usize, flags: usize) -> Result<Option<usize>> {
fn fevent(&mut self, id: usize, flags: EventFlags) -> Result<Option<EventFlags>> {
Err(Error::new(EBADF))
}
......
use core::{mem, slice};
use data::*;
use error::*;
use number::*;
use crate::data::*;
use crate::error::*;
use crate::flag::*;
use crate::number::*;
pub trait SchemeMut {
fn handle(&mut self, packet: &mut Packet) {
......@@ -19,7 +20,7 @@ pub trait SchemeMut {
SYS_FCHMOD => self.fchmod(packet.b, packet.c as u16),
SYS_FCHOWN => self.fchown(packet.b, packet.c as u32, packet.d as u32),
SYS_FCNTL => self.fcntl(packet.b, packet.c, packet.d),
SYS_FEVENT => self.fevent(packet.b, packet.c),
SYS_FEVENT => self.fevent(packet.b, EventFlags::from_bits_truncate(packet.c)).map(|f| f.bits()),
SYS_FMAP => if packet.d >= mem::size_of::<Map>() {
self.fmap(packet.b, unsafe { &*(packet.c as *const Map) })
} else {
......@@ -111,7 +112,7 @@ pub trait SchemeMut {
}
#[allow(unused_variables)]
fn fevent(&mut self, id: usize, flags: usize) -> Result<usize> {
fn fevent(&mut self, id: usize, flags: EventFlags) -> Result<EventFlags> {
Err(Error::new(EBADF))
}
......
......@@ -36,14 +36,14 @@ fn chdir() {
#[test]
fn clone() {
let expected_status = 42;
let pid_res = unsafe { crate::clone(0) };
let pid_res = unsafe { crate::clone(crate::CloneFlags::empty()) };
if pid_res == Ok(0) {
crate::exit(expected_status).unwrap();
panic!("failed to exit");
} else {
let pid = dbg!(pid_res).unwrap();
let mut status = 0;
assert_eq!(dbg!(crate::waitpid(pid, &mut status, 0)), Ok(pid));
assert_eq!(dbg!(crate::waitpid(pid, &mut status, crate::WaitFlags::empty())), Ok(pid));
assert_eq!(dbg!(crate::wifexited(status)), true);
assert_eq!(dbg!(crate::wexitstatus(status)), expected_status);
}
......@@ -90,7 +90,7 @@ fn fexec() {
let vars = &[];
let pid_res = unsafe { crate::clone(0) };
let pid_res = unsafe { crate::clone(crate::CloneFlags::empty()) };
if pid_res == Ok(0) {
crate::fexec(fd, args, vars).unwrap();
panic!("failed to fexec");
......@@ -99,7 +99,7 @@ fn fexec() {
let pid = dbg!(pid_res).unwrap();
let mut status = 0;
assert_eq!(dbg!(crate::waitpid(pid, &mut status, 0)), Ok(pid));
assert_eq!(dbg!(crate::waitpid(pid, &mut status, crate::WaitFlags::empty())), Ok(pid));
assert_eq!(dbg!(crate::wifexited(status)), true);
assert_eq!(dbg!(crate::wexitstatus(status)), 0);
}
......@@ -465,7 +465,7 @@ fn sigaction() {
crate::kill(pid, crate::SIGUSR1).unwrap(); // actually exits
} else {
let mut status = 0;
dbg!(crate::waitpid(child, &mut status, 0)).unwrap();
dbg!(crate::waitpid(child, &mut status, crate::WaitFlags::empty())).unwrap();
assert!(crate::wifsignaled(status));
assert_eq!(crate::wtermsig(status), crate::SIGUSR1);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment