1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
//! Memory-mapping operations

use core::{mem, num::NonZeroUsize, ops::{Deref, DerefMut}, ptr, slice};
use libc;

use Error;
use file::*;
use util::*;

/// Memory-mapping, unmapped on drop
#[derive(Debug)]
pub struct Map {
    ptr: *mut u8,
    length: usize,
}

impl Map {
    /// Leak the mapping: it will never be unmapped while the calling program is loaded.
    #[inline]
    pub fn leak(self) -> &'static mut [u8] {
        let Map { ptr, length } = self;
        mem::forget(self);
        unsafe { slice::from_raw_parts_mut(ptr, length) }
    }
}

impl Deref for Map {
    type Target = [u8];
    #[inline]
    fn deref(&self) -> &[u8] { unsafe { slice::from_raw_parts(self.ptr, self.length) } }
}

impl DerefMut for Map {
    #[inline]
    fn deref_mut(&mut self) -> &mut [u8] {
        unsafe { slice::from_raw_parts_mut(self.ptr, self.length) }
    }
}

impl Drop for Map {
    #[inline]
    fn drop(&mut self) {
        unsafe { syscall!(MUNMAP, self.ptr, self.length) };
    }
}

bitflags! {
    struct Prot: usize {
        const EXEC  = libc::PROT_EXEC  as usize;
        const READ  = libc::PROT_READ  as usize;
        const WRITE = libc::PROT_WRITE as usize;
    }
}

impl From<Perm> for Prot {
    #[inline]
    fn from(perm: Perm) -> Prot {
        let mut prot = Prot::empty();
        for &(prt, prm) in &[(Prot::READ,  Perm::Read),
                             (Prot::WRITE, Perm::Write),
                             (Prot::EXEC,  Perm::Exec)] {
            if perm.contains(prm) { prot |= prt; }
        }
        prot
    }
}

/// Values which can be mapped into memory
pub trait MapExt {
    /// Specifier of which part of value to map
    type MapSpec;

    /// Map the value into memory at an unspecified location.
    fn map(&self, perm: Perm, seg: Self::MapSpec) -> Result<Map, Error>;
    /// Map the value into memory at the given location.
    unsafe fn map_at(&self, loc: *mut u8, perm: Perm, seg: Self::MapSpec) -> Result<Map, Error>;
}

#[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Segment {
    pub offset: u64,
    pub length: usize,
}

impl MapExt for File {
    type MapSpec = Option<Segment>;

    #[inline]
    fn map(&self, perm: Perm, seg: Option<Segment>) -> Result<Map, Error> {
        unsafe { do_map_file(self, ptr::null_mut(), perm, seg) }
    }

    #[inline]
    unsafe fn map_at(&self, loc: *mut u8, perm: Perm, seg: Option<Segment>) ->
      Result<Map, Error> { do_map_file(self, loc, perm, seg) }
}

impl MapExt for () {
    type MapSpec = usize;

    #[inline]
    fn map(&self, perm: Perm, length: usize) -> Result<Map, Error> {
        unsafe { do_map(-1, ptr::null_mut(), perm, 0, length) }
    }

    #[inline]
    unsafe fn map_at(&self, loc: *mut u8, perm: Perm, length: usize) -> Result<Map, Error> {
        do_map(-1, loc, perm, 0, length)
    }
}

#[inline]
unsafe fn do_map_file(f: &File, loc: *mut u8, perm: Perm, seg: Option<Segment>) ->
  Result<Map, Error> {
    let Segment { offset, length } = seg.unwrap_or(Segment {
        offset: 0, length: try_to_usize(f.stat()?.size as _)?
    });
    do_map(f.fd(), loc, perm, offset, length)
}

#[inline]
unsafe fn do_map(fd: isize, loc: *mut u8, perm: Perm, offset: u64, length: usize) ->
  Result<Map, Error> {
    let ptr = syscall!(MMAP, loc, length, Prot::from(perm).bits,
                       if loc.is_null() { 0 } else { libc::MAP_FIXED }, fd, offset) as *mut u8;
    if (ptr as usize) > 0x1000usize.wrapping_neg() {
        Err(Error::from(NonZeroUsize::new_unchecked((ptr as usize).wrapping_neg())))
    } else { Ok(Map { ptr: ptr as *mut u8, length }) }
}