diff options
| author | Valerii Hiora <valerii.hiora@gmail.com> | 2014-05-05 10:07:49 +0300 |
|---|---|---|
| committer | Valerii Hiora <valerii.hiora@gmail.com> | 2014-06-12 21:15:14 +0300 |
| commit | a49b765f9a5b5926e338da30fcaae59ff1ae5c02 (patch) | |
| tree | 489f1930d52ae1e9050e840940b3bcb1daedb615 /src/libstd | |
| parent | 0c10c686824bf37084af87af84f338bcd2a7551a (diff) | |
| download | rust-a49b765f9a5b5926e338da30fcaae59ff1ae5c02.tar.gz rust-a49b765f9a5b5926e338da30fcaae59ff1ae5c02.zip | |
Basic iOS support
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/dynamic_lib.rs | 3 | ||||
| -rw-r--r-- | src/libstd/os.rs | 81 | ||||
| -rw-r--r-- | src/libstd/rand/os.rs | 69 | ||||
| -rw-r--r-- | src/libstd/rt/backtrace.rs | 60 | ||||
| -rw-r--r-- | src/libstd/rtdeps.rs | 4 |
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 {} |
