about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/dynamic_lib.rs3
-rw-r--r--src/libstd/os.rs81
-rw-r--r--src/libstd/rand/os.rs69
-rw-r--r--src/libstd/rt/backtrace.rs60
-rw-r--r--src/libstd/rtdeps.rs4
5 files changed, 206 insertions, 11 deletions
diff --git a/src/libstd/dynamic_lib.rs b/src/libstd/dynamic_lib.rs
index fa6efc8a4b1..5dbed6844c3 100644
--- a/src/libstd/dynamic_lib.rs
+++ b/src/libstd/dynamic_lib.rs
@@ -153,7 +153,7 @@ impl DynamicLibrary {
     }
 }
 
-#[cfg(test)]
+#[cfg(test, not(target_os = "ios"))]
 mod test {
     use super::*;
     use prelude::*;
@@ -205,6 +205,7 @@ mod test {
 #[cfg(target_os = "linux")]
 #[cfg(target_os = "android")]
 #[cfg(target_os = "macos")]
+#[cfg(target_os = "ios")]
 #[cfg(target_os = "freebsd")]
 pub mod dl {
     use prelude::*;
diff --git a/src/libstd/os.rs b/src/libstd/os.rs
index cc76cde7baf..f6b1c04dd34 100644
--- a/src/libstd/os.rs
+++ b/src/libstd/os.rs
@@ -552,6 +552,7 @@ pub fn pipe() -> Pipe {
 
 /// Returns the proper dll filename for the given basename of a file
 /// as a String.
+#[cfg(not(target_os="ios"))]
 pub fn dll_filename(base: &str) -> String {
     format!("{}{}{}", consts::DLL_PREFIX, base, consts::DLL_SUFFIX)
 }
@@ -608,6 +609,7 @@ pub fn self_exe_name() -> Option<Path> {
     }
 
     #[cfg(target_os = "macos")]
+    #[cfg(target_os = "ios")]
     fn load_self() -> Option<Vec<u8>> {
         unsafe {
             use libc::funcs::extra::_NSGetExecutablePath;
@@ -802,6 +804,7 @@ pub fn change_dir(p: &Path) -> bool {
 /// Returns the platform-specific value of errno
 pub fn errno() -> int {
     #[cfg(target_os = "macos")]
+    #[cfg(target_os = "ios")]
     #[cfg(target_os = "freebsd")]
     fn errno_location() -> *c_int {
         extern {
@@ -850,6 +853,7 @@ pub fn error_string(errnum: uint) -> String {
     #[cfg(unix)]
     fn strerror(errnum: uint) -> String {
         #[cfg(target_os = "macos")]
+        #[cfg(target_os = "ios")]
         #[cfg(target_os = "android")]
         #[cfg(target_os = "freebsd")]
         fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t)
@@ -995,6 +999,64 @@ fn real_args_as_bytes() -> Vec<Vec<u8>> {
     }
 }
 
+// As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
+// and use underscores in their names - they're most probably
+// are considered private and therefore should be avoided
+// Here is another way to get arguments using Objective C
+// runtime
+//
+// In general it looks like:
+// res = Vec::new()
+// let args = [[NSProcessInfo processInfo] arguments]
+// for i in range(0, [args count])
+//      res.push([args objectAtIndex:i])
+// res
+#[cfg(target_os = "ios")]
+fn real_args_as_bytes() -> Vec<Vec<u8>> {
+    use c_str::CString;
+    use iter::range;
+    use mem;
+
+    #[link(name = "objc")]
+    extern {
+        fn sel_registerName(name: *libc::c_uchar) -> Sel;
+        fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId;
+        fn objc_getClass(class_name: *libc::c_uchar) -> NsId;
+    }
+
+    #[link(name = "Foundation", kind = "framework")]
+    extern {}
+
+    type Sel = *libc::c_void;
+    type NsId = *libc::c_void;
+
+    let mut res = Vec::new();
+
+    unsafe {
+        let processInfoSel = sel_registerName("processInfo\0".as_ptr());
+        let argumentsSel = sel_registerName("arguments\0".as_ptr());
+        let utf8Sel = sel_registerName("UTF8String\0".as_ptr());
+        let countSel = sel_registerName("count\0".as_ptr());
+        let objectAtSel = sel_registerName("objectAtIndex:\0".as_ptr());
+
+        let klass = objc_getClass("NSProcessInfo\0".as_ptr());
+        let info = objc_msgSend(klass, processInfoSel);
+        let args = objc_msgSend(info, argumentsSel);
+
+        let cnt: int = mem::transmute(objc_msgSend(args, countSel));
+        for i in range(0, cnt) {
+            let tmp = objc_msgSend(args, objectAtSel, i);
+            let utf_c_str: *libc::c_char = mem::transmute(objc_msgSend(tmp, utf8Sel));
+            let s = CString::new(utf_c_str, false);
+            if s.is_not_null() {
+                res.push(Vec::from_slice(s.as_bytes_no_nul()))
+            }
+        }
+    }
+
+    res
+}
+
 #[cfg(target_os = "linux")]
 #[cfg(target_os = "android")]
 #[cfg(target_os = "freebsd")]
@@ -1532,6 +1594,25 @@ pub mod consts {
     pub static EXE_EXTENSION: &'static str = "";
 }
 
+#[cfg(target_os = "ios")]
+pub mod consts {
+    pub use os::arch_consts::ARCH;
+
+    pub static FAMILY: &'static str = "unix";
+
+    /// A string describing the specific operating system in use: in this
+    /// case, `ios`.
+    pub static SYSNAME: &'static str = "ios";
+
+    /// Specifies the filename suffix used for executable binaries on this
+    /// platform: in this case, the empty string.
+    pub static EXE_SUFFIX: &'static str = "";
+
+    /// Specifies the file extension, if any, used for executable binaries
+    /// on this platform: in this case, the empty string.
+    pub static EXE_EXTENSION: &'static str = "";
+}
+
 #[cfg(target_os = "freebsd")]
 pub mod consts {
     pub use os::arch_consts::ARCH;
diff --git a/src/libstd/rand/os.rs b/src/libstd/rand/os.rs
index 2654b7a1acc..f507011c2b9 100644
--- a/src/libstd/rand/os.rs
+++ b/src/libstd/rand/os.rs
@@ -13,7 +13,7 @@
 
 pub use self::imp::OsRng;
 
-#[cfg(unix)]
+#[cfg(unix, not(target_os = "ios"))]
 mod imp {
     use io::{IoResult, File};
     use path::Path;
@@ -28,7 +28,7 @@ mod imp {
     ///   `/dev/urandom`.
     /// - Windows: calls `CryptGenRandom`, using the default cryptographic
     ///   service provider with the `PROV_RSA_FULL` type.
-    ///
+    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed
     /// This does not block.
     #[cfg(unix)]
     pub struct OsRng {
@@ -58,6 +58,71 @@ mod imp {
     }
 }
 
+#[cfg(target_os = "ios")]
+mod imp {
+    extern crate libc;
+
+    use collections::Collection;
+    use io::{IoResult};
+    use kinds::marker;
+    use mem;
+    use os;
+    use rand::Rng;
+    use result::{Ok};
+    use self::libc::{c_int, size_t};
+    use slice::MutableVector;
+
+    /// A random number generator that retrieves randomness straight from
+    /// the operating system. Platform sources:
+    ///
+    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
+    ///   `/dev/urandom`.
+    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
+    ///   service provider with the `PROV_RSA_FULL` type.
+    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed
+    /// This does not block.
+    pub struct OsRng {
+        marker: marker::NoCopy
+    }
+
+    struct SecRandom;
+
+    static kSecRandomDefault: *SecRandom = 0 as *SecRandom;
+
+    #[link(name = "Security", kind = "framework")]
+    extern "C" {
+        fn SecRandomCopyBytes(rnd: *SecRandom, count: size_t, bytes: *mut u8) -> c_int;
+    }
+
+    impl OsRng {
+        /// Create a new `OsRng`.
+        pub fn new() -> IoResult<OsRng> {
+            Ok(OsRng {marker: marker::NoCopy} )
+        }
+    }
+
+    impl Rng for OsRng {
+        fn next_u32(&mut self) -> u32 {
+            let mut v = [0u8, .. 4];
+            self.fill_bytes(v);
+            unsafe { mem::transmute(v) }
+        }
+        fn next_u64(&mut self) -> u64 {
+            let mut v = [0u8, .. 8];
+            self.fill_bytes(v);
+            unsafe { mem::transmute(v) }
+        }
+        fn fill_bytes(&mut self, v: &mut [u8]) {
+            let ret = unsafe {
+                SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, v.as_mut_ptr())
+            };
+            if ret == -1 {
+                fail!("couldn't generate random bytes: {}", os::last_os_error());
+            }
+        }
+    }
+}
+
 #[cfg(windows)]
 mod imp {
     extern crate libc;
diff --git a/src/libstd/rt/backtrace.rs b/src/libstd/rt/backtrace.rs
index a1372b51d47..16b598b3ae7 100644
--- a/src/libstd/rt/backtrace.rs
+++ b/src/libstd/rt/backtrace.rs
@@ -237,22 +237,58 @@ fn demangle(writer: &mut Writer, s: &str) -> IoResult<()> {
 #[cfg(unix)]
 mod imp {
     use c_str::CString;
-    use io::{IoResult, IoError, Writer};
+    use io::{IoResult, Writer};
     use libc;
     use mem;
     use option::{Some, None, Option};
     use result::{Ok, Err};
     use rt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
 
-    struct Context<'a> {
-        idx: int,
-        writer: &'a mut Writer,
-        last_error: Option<IoError>,
+    /// As always - iOS on arm uses SjLj exceptions and
+    /// _Unwind_Backtrace is even not available there. Still,
+    /// backtraces could be extracted using a backtrace function,
+    /// which thanks god is public
+    #[cfg(target_os = "ios", target_arch = "arm")]
+    #[inline(never)]
+    pub fn write(w: &mut Writer) -> IoResult<()> {
+        use iter::{Iterator, range};
+        use result;
+        use slice::{MutableVector};
+
+        extern {
+            fn backtrace(buf: *mut *libc::c_void, sz: libc::c_int) -> libc::c_int;
+        }
+
+        // while it doesn't requires lock for work as everything is
+        // local, it still displays much nicier backtraces when a
+        // couple of tasks fail simultaneously
+        static mut LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
+        let _g = unsafe { LOCK.lock() };
+
+        try!(writeln!(w, "stack backtrace:"));
+        // 100 lines should be enough
+        static size: libc::c_int = 100;
+        let mut buf: [*libc::c_void, ..size] = unsafe {mem::zeroed()};
+        let cnt = unsafe { backtrace(buf.as_mut_ptr(), size) as uint};
+
+        // skipping the first one as it is write itself
+        result::fold_(range(1, cnt).map(|i| {
+            print(w, i as int, buf[i])
+        }))
     }
 
+    #[cfg(not(target_os = "ios", target_arch = "arm"))]
     #[inline(never)] // if we know this is a function call, we can skip it when
                      // tracing
     pub fn write(w: &mut Writer) -> IoResult<()> {
+        use io::IoError;
+
+        struct Context<'a> {
+            idx: int,
+            writer: &'a mut Writer,
+            last_error: Option<IoError>,
+        }
+
         // When using libbacktrace, we use some necessary global state, so we
         // need to prevent more than one thread from entering this block. This
         // is semi-reasonable in terms of printing anyway, and we know that all
@@ -291,7 +327,7 @@ mod imp {
             // instructions after it. This means that the return instruction
             // pointer points *outside* of the calling function, and by
             // unwinding it we go back to the original function.
-            let ip = if cfg!(target_os = "macos") {
+            let ip = if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
                 ip
             } else {
                 unsafe { uw::_Unwind_FindEnclosingFunction(ip) }
@@ -323,6 +359,7 @@ mod imp {
     }
 
     #[cfg(target_os = "macos")]
+    #[cfg(target_os = "ios")]
     fn print(w: &mut Writer, idx: int, addr: *libc::c_void) -> IoResult<()> {
         use intrinsics;
         #[repr(C)]
@@ -347,7 +384,7 @@ mod imp {
         }
     }
 
-    #[cfg(not(target_os = "macos"))]
+    #[cfg(not(target_os = "macos"), not(target_os = "ios"))]
     fn print(w: &mut Writer, idx: int, addr: *libc::c_void) -> IoResult<()> {
         use collections::Collection;
         use iter::Iterator;
@@ -487,9 +524,14 @@ mod imp {
 
     /// Unwind library interface used for backtraces
     ///
-    /// Note that the native libraries come from librustrt, not this module.
+    /// Note that the native libraries come from librustrt, not this
+    /// module.
+    /// Note that dead code is allowed as here are just bindings
+    /// iOS doesn't use all of them it but adding more
+    /// platform-specific configs pollutes the code too much
     #[allow(non_camel_case_types)]
     #[allow(non_snake_case_functions)]
+    #[allow(dead_code)]
     mod uw {
         use libc;
 
@@ -514,6 +556,8 @@ mod imp {
                           arg: *libc::c_void) -> _Unwind_Reason_Code;
 
         extern {
+            // No native _Unwind_Backtrace on iOS
+            #[cfg(not(target_os = "ios", target_arch = "arm"))]
             pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn,
                                      trace_argument: *libc::c_void)
                         -> _Unwind_Reason_Code;
diff --git a/src/libstd/rtdeps.rs b/src/libstd/rtdeps.rs
index c804918ae4b..f8bfde52261 100644
--- a/src/libstd/rtdeps.rs
+++ b/src/libstd/rtdeps.rs
@@ -39,3 +39,7 @@ extern {}
 #[cfg(target_os = "macos")]
 #[link(name = "System")]
 extern {}
+
+#[cfg(target_os = "ios")]
+#[link(name = "System")]
+extern {}