diff options
Diffstat (limited to 'src/libstd/sys/unix/backtrace')
| -rw-r--r-- | src/libstd/sys/unix/backtrace/mod.rs | 119 | ||||
| -rw-r--r-- | src/libstd/sys/unix/backtrace/printing/dladdr.rs | 35 | ||||
| -rw-r--r-- | src/libstd/sys/unix/backtrace/printing/libbacktrace.rs | 206 | ||||
| -rw-r--r-- | src/libstd/sys/unix/backtrace/printing/mod.rs | 19 | ||||
| -rw-r--r-- | src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs | 57 | ||||
| -rw-r--r-- | src/libstd/sys/unix/backtrace/tracing/gcc_s.rs | 227 | ||||
| -rw-r--r-- | src/libstd/sys/unix/backtrace/tracing/mod.rs | 18 | 
7 files changed, 681 insertions, 0 deletions
| diff --git a/src/libstd/sys/unix/backtrace/mod.rs b/src/libstd/sys/unix/backtrace/mod.rs new file mode 100644 index 00000000000..80dcffd0e63 --- /dev/null +++ b/src/libstd/sys/unix/backtrace/mod.rs @@ -0,0 +1,119 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/// Backtrace support built on libgcc with some extra OS-specific support +/// +/// Some methods of getting a backtrace: +/// +/// * The backtrace() functions on unix. It turns out this doesn't work very +/// well for green threads on OSX, and the address to symbol portion of it +/// suffers problems that are described below. +/// +/// * Using libunwind. This is more difficult than it sounds because libunwind +/// isn't installed everywhere by default. It's also a bit of a hefty library, +/// so possibly not the best option. When testing, libunwind was excellent at +/// getting both accurate backtraces and accurate symbols across platforms. +/// This route was not chosen in favor of the next option, however. +/// +/// * We're already using libgcc_s for exceptions in rust (triggering thread +/// unwinding and running destructors on the stack), and it turns out that it +/// conveniently comes with a function that also gives us a backtrace. All of +/// these functions look like _Unwind_*, but it's not quite the full +/// repertoire of the libunwind API. Due to it already being in use, this was +/// the chosen route of getting a backtrace. +/// +/// After choosing libgcc_s for backtraces, the sad part is that it will only +/// give us a stack trace of instruction pointers. Thankfully these instruction +/// pointers are accurate (they work for green and native threads), but it's +/// then up to us again to figure out how to translate these addresses to +/// symbols. As with before, we have a few options. Before, that, a little bit +/// of an interlude about symbols. This is my very limited knowledge about +/// symbol tables, and this information is likely slightly wrong, but the +/// general idea should be correct. +/// +/// When talking about symbols, it's helpful to know a few things about where +/// symbols are located. Some symbols are located in the dynamic symbol table +/// of the executable which in theory means that they're available for dynamic +/// linking and lookup. Other symbols end up only in the local symbol table of +/// the file. This loosely corresponds to pub and priv functions in Rust. +/// +/// Armed with this knowledge, we know that our solution for address to symbol +/// translation will need to consult both the local and dynamic symbol tables. +/// With that in mind, here's our options of translating an address to +/// a symbol. +/// +/// * Use dladdr(). The original backtrace()-based idea actually uses dladdr() +/// behind the scenes to translate, and this is why backtrace() was not used. +/// Conveniently, this method works fantastically on OSX. It appears dladdr() +/// uses magic to consult the local symbol table, or we're putting everything +/// in the dynamic symbol table anyway. Regardless, for OSX, this is the +/// method used for translation. It's provided by the system and easy to do.o +/// +/// Sadly, all other systems have a dladdr() implementation that does not +/// consult the local symbol table. This means that most functions are blank +/// because they don't have symbols. This means that we need another solution. +/// +/// * Use unw_get_proc_name(). This is part of the libunwind api (not the +/// libgcc_s version of the libunwind api), but involves taking a dependency +/// to libunwind. We may pursue this route in the future if we bundle +/// libunwind, but libunwind was unwieldy enough that it was not chosen at +/// this time to provide this functionality. +/// +/// * Shell out to a utility like `readelf`. Crazy though it may sound, it's a +/// semi-reasonable solution. The stdlib already knows how to spawn processes, +/// so in theory it could invoke readelf, parse the output, and consult the +/// local/dynamic symbol tables from there. This ended up not getting chosen +/// due to the craziness of the idea plus the advent of the next option. +/// +/// * Use `libbacktrace`. It turns out that this is a small library bundled in +/// the gcc repository which provides backtrace and symbol translation +/// functionality. All we really need from it is the backtrace functionality, +/// and we only really need this on everything that's not OSX, so this is the +/// chosen route for now. +/// +/// In summary, the current situation uses libgcc_s to get a trace of stack +/// pointers, and we use dladdr() or libbacktrace to translate these addresses +/// to symbols. This is a bit of a hokey implementation as-is, but it works for +/// all unix platforms we support right now, so it at least gets the job done. + +pub use self::tracing::write; + +use io; +use io::prelude::*; +use libc; +use str; + +use sys_common::backtrace::{demangle, HEX_WIDTH}; + +// tracing impls: +mod tracing; +// symbol resolvers: +mod printing; + +pub fn output(w: &mut Write, idx: isize, addr: *mut libc::c_void, + s: Option<&[u8]>) -> io::Result<()> { + try!(write!(w, " {:2}: {:2$?} - ", idx, addr, HEX_WIDTH)); + match s.and_then(|s| str::from_utf8(s).ok()) { + Some(string) => try!(demangle(w, string)), + None => try!(write!(w, "<unknown>")), + } + w.write_all(&['\n' as u8]) +} + +pub fn output_fileline(w: &mut Write, file: &[u8], line: libc::c_int, + more: bool) -> io::Result<()> { + let file = str::from_utf8(file).unwrap_or("<unknown>"); + // prior line: " ##: {:2$} - func" + try!(write!(w, " {:3$}at {}:{}", "", file, line, HEX_WIDTH)); + if more { + try!(write!(w, " <... and possibly more>")); + } + w.write_all(&['\n' as u8]) +} diff --git a/src/libstd/sys/unix/backtrace/printing/dladdr.rs b/src/libstd/sys/unix/backtrace/printing/dladdr.rs new file mode 100644 index 00000000000..fc7894a97b0 --- /dev/null +++ b/src/libstd/sys/unix/backtrace/printing/dladdr.rs @@ -0,0 +1,35 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub fn print(w: &mut Write, idx: isize, addr: *mut libc::c_void, + _symaddr: *mut libc::c_void) -> io::Result<()> { + use sys::backtrace::{output}; + use intrinsics; + #[repr(C)] + struct Dl_info { + dli_fname: *const libc::c_char, + dli_fbase: *mut libc::c_void, + dli_sname: *const libc::c_char, + dli_saddr: *mut libc::c_void, + } + extern { + fn dladdr(addr: *const libc::c_void, + info: *mut Dl_info) -> libc::c_int; + } + + let mut info: Dl_info = unsafe { intrinsics::init() }; + if unsafe { dladdr(addr, &mut info) == 0 } { + output(w, idx,addr, None) + } else { + output(w, idx, addr, Some(unsafe { + CStr::from_ptr(info.dli_sname).to_bytes() + })) + } +} diff --git a/src/libstd/sys/unix/backtrace/printing/libbacktrace.rs b/src/libstd/sys/unix/backtrace/printing/libbacktrace.rs new file mode 100644 index 00000000000..711e241161d --- /dev/null +++ b/src/libstd/sys/unix/backtrace/printing/libbacktrace.rs @@ -0,0 +1,206 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use io; +use io::prelude::*; +use libc; + +use sys::backtrace::{output, output_fileline}; +pub fn print(w: &mut Write, idx: isize, addr: *mut libc::c_void, + symaddr: *mut libc::c_void) -> io::Result<()> { + use env; + use ffi::CStr; + use os::unix::prelude::*; + use ptr; + + //////////////////////////////////////////////////////////////////////// + // libbacktrace.h API + //////////////////////////////////////////////////////////////////////// + type backtrace_syminfo_callback = + extern "C" fn(data: *mut libc::c_void, + pc: libc::uintptr_t, + symname: *const libc::c_char, + symval: libc::uintptr_t, + symsize: libc::uintptr_t); + type backtrace_full_callback = + extern "C" fn(data: *mut libc::c_void, + pc: libc::uintptr_t, + filename: *const libc::c_char, + lineno: libc::c_int, + function: *const libc::c_char) -> libc::c_int; + type backtrace_error_callback = + extern "C" fn(data: *mut libc::c_void, + msg: *const libc::c_char, + errnum: libc::c_int); + enum backtrace_state {} + #[link(name = "backtrace", kind = "static")] + #[cfg(not(test))] + extern {} + + extern { + fn backtrace_create_state(filename: *const libc::c_char, + threaded: libc::c_int, + error: backtrace_error_callback, + data: *mut libc::c_void) + -> *mut backtrace_state; + fn backtrace_syminfo(state: *mut backtrace_state, + addr: libc::uintptr_t, + cb: backtrace_syminfo_callback, + error: backtrace_error_callback, + data: *mut libc::c_void) -> libc::c_int; + fn backtrace_pcinfo(state: *mut backtrace_state, + addr: libc::uintptr_t, + cb: backtrace_full_callback, + error: backtrace_error_callback, + data: *mut libc::c_void) -> libc::c_int; + } + + //////////////////////////////////////////////////////////////////////// + // helper callbacks + //////////////////////////////////////////////////////////////////////// + + type FileLine = (*const libc::c_char, libc::c_int); + + extern fn error_cb(_data: *mut libc::c_void, _msg: *const libc::c_char, + _errnum: libc::c_int) { + // do nothing for now + } + extern fn syminfo_cb(data: *mut libc::c_void, + _pc: libc::uintptr_t, + symname: *const libc::c_char, + _symval: libc::uintptr_t, + _symsize: libc::uintptr_t) { + let slot = data as *mut *const libc::c_char; + unsafe { *slot = symname; } + } + extern fn pcinfo_cb(data: *mut libc::c_void, + _pc: libc::uintptr_t, + filename: *const libc::c_char, + lineno: libc::c_int, + _function: *const libc::c_char) -> libc::c_int { + if !filename.is_null() { + let slot = data as *mut &mut [FileLine]; + let buffer = unsafe {ptr::read(slot)}; + + // if the buffer is not full, add file:line to the buffer + // and adjust the buffer for next possible calls to pcinfo_cb. + if !buffer.is_empty() { + buffer[0] = (filename, lineno); + unsafe { ptr::write(slot, &mut buffer[1..]); } + } + } + + 0 + } + + // The libbacktrace API supports creating a state, but it does not + // support destroying a state. I personally take this to mean that a + // state is meant to be created and then live forever. + // + // I would love to register an at_exit() handler which cleans up this + // state, but libbacktrace provides no way to do so. + // + // With these constraints, this function has a statically cached state + // that is calculated the first time this is requested. Remember that + // backtracing all happens serially (one global lock). + // + // An additionally oddity in this function is that we initialize the + // filename via self_exe_name() to pass to libbacktrace. It turns out + // that on Linux libbacktrace seamlessly gets the filename of the + // current executable, but this fails on freebsd. by always providing + // it, we make sure that libbacktrace never has a reason to not look up + // the symbols. The libbacktrace API also states that the filename must + // be in "permanent memory", so we copy it to a static and then use the + // static as the pointer. + // + // FIXME: We also call self_exe_name() on DragonFly BSD. I haven't + // tested if this is required or not. + unsafe fn init_state() -> *mut backtrace_state { + static mut STATE: *mut backtrace_state = 0 as *mut backtrace_state; + static mut LAST_FILENAME: [libc::c_char; 256] = [0; 256]; + if !STATE.is_null() { return STATE } + let selfname = if cfg!(target_os = "freebsd") || + cfg!(target_os = "dragonfly") || + cfg!(target_os = "bitrig") || + cfg!(target_os = "openbsd") { + env::current_exe().ok() + } else { + None + }; + let filename = match selfname { + Some(path) => { + let bytes = path.as_os_str().as_bytes(); + if bytes.len() < LAST_FILENAME.len() { + let i = bytes.iter(); + for (slot, val) in LAST_FILENAME.iter_mut().zip(i) { + *slot = *val as libc::c_char; + } + LAST_FILENAME.as_ptr() + } else { + ptr::null() + } + } + None => ptr::null(), + }; + STATE = backtrace_create_state(filename, 0, error_cb, + ptr::null_mut()); + return STATE + } + + //////////////////////////////////////////////////////////////////////// + // translation + //////////////////////////////////////////////////////////////////////// + + // backtrace errors are currently swept under the rug, only I/O + // errors are reported + let state = unsafe { init_state() }; + if state.is_null() { + return output(w, idx, addr, None) + } + let mut data = ptr::null(); + let data_addr = &mut data as *mut *const libc::c_char; + let ret = unsafe { + backtrace_syminfo(state, symaddr as libc::uintptr_t, + syminfo_cb, error_cb, + data_addr as *mut libc::c_void) + }; + if ret == 0 || data.is_null() { + try!(output(w, idx, addr, None)); + } else { + try!(output(w, idx, addr, Some(unsafe { CStr::from_ptr(data).to_bytes() }))); + } + + // pcinfo may return an arbitrary number of file:line pairs, + // in the order of stack trace (i.e. inlined calls first). + // in order to avoid allocation, we stack-allocate a fixed size of entries. + const FILELINE_SIZE: usize = 32; + let mut fileline_buf = [(ptr::null(), -1); FILELINE_SIZE]; + let ret; + let fileline_count; + { + let mut fileline_win: &mut [FileLine] = &mut fileline_buf; + let fileline_addr = &mut fileline_win as *mut &mut [FileLine]; + ret = unsafe { + backtrace_pcinfo(state, addr as libc::uintptr_t, + pcinfo_cb, error_cb, + fileline_addr as *mut libc::c_void) + }; + fileline_count = FILELINE_SIZE - fileline_win.len(); + } + if ret == 0 { + for (i, &(file, line)) in fileline_buf[..fileline_count].iter().enumerate() { + if file.is_null() { continue; } // just to be sure + let file = unsafe { CStr::from_ptr(file).to_bytes() }; + try!(output_fileline(w, file, line, i == FILELINE_SIZE - 1)); + } + } + + Ok(()) +} diff --git a/src/libstd/sys/unix/backtrace/printing/mod.rs b/src/libstd/sys/unix/backtrace/printing/mod.rs new file mode 100644 index 00000000000..a3bd45566f1 --- /dev/null +++ b/src/libstd/sys/unix/backtrace/printing/mod.rs @@ -0,0 +1,19 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub use self::imp::*; + +#[cfg(any(target_os = "macos", target_os = "ios"))] +#[path = "dladdr.rs"] +mod imp; + +#[cfg(not(any(target_os = "macos", target_os = "ios")))] +#[path = "libbacktrace.rs"] +mod imp; diff --git a/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs b/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs new file mode 100644 index 00000000000..2865abb254c --- /dev/null +++ b/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs @@ -0,0 +1,57 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/// 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 +/// +/// As mentioned in a huge comment block in `super::super`, backtrace +/// doesn't play well with green threads, so while it is extremely nice and +/// simple to use it should be used only on iOS devices as the only viable +/// option. + +use io; +use io::prelude::*; +use iter::Iterator; +use libc; +use mem; +use result::Result::Ok; +use sync::StaticMutex; + +use super::printer::print; + +#[inline(never)] +pub fn write(w: &mut Write) -> io::Result<()> { + use mem; + + extern { + fn backtrace(buf: *mut *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 nicer backtraces when a + // couple of threads panic simultaneously + static LOCK: StaticMutex = StaticMutex::new(); + let _g = LOCK.lock(); + + try!(writeln!(w, "stack backtrace:")); + // 100 lines should be enough + const SIZE: usize = 100; + let mut buf: [*mut libc::c_void; SIZE] = unsafe { mem::zeroed() }; + let cnt = unsafe { backtrace(buf.as_mut_ptr(), SIZE as libc::c_int) as usize}; + + // skipping the first one as it is write itself + for i in 1..cnt { + try!(print(w, i as isize, buf[i], buf[i])) + } + Ok(()) +} diff --git a/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs b/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs new file mode 100644 index 00000000000..cdaf69c4882 --- /dev/null +++ b/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs @@ -0,0 +1,227 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use io; +use io::prelude::*; +use libc; +use mem; +use sync::StaticMutex; + +use super::super::printing::print; + +#[inline(never)] // if we know this is a function call, we can skip it when + // tracing +pub fn write(w: &mut Write) -> io::Result<()> { + struct Context<'a> { + idx: isize, + writer: &'a mut (Write+'a), + last_error: Option<io::Error>, + } + + // 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 + // I/O done here is blocking I/O, not green I/O, so we don't have to + // worry about this being a native vs green mutex. + static LOCK: StaticMutex = StaticMutex::new(); + let _g = LOCK.lock(); + + try!(writeln!(w, "stack backtrace:")); + + let mut cx = Context { writer: w, last_error: None, idx: 0 }; + return match unsafe { + uw::_Unwind_Backtrace(trace_fn, + &mut cx as *mut Context as *mut libc::c_void) + } { + uw::_URC_NO_REASON => { + match cx.last_error { + Some(err) => Err(err), + None => Ok(()) + } + } + _ => Ok(()), + }; + + extern fn trace_fn(ctx: *mut uw::_Unwind_Context, + arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code { + let cx: &mut Context = unsafe { mem::transmute(arg) }; + let mut ip_before_insn = 0; + let mut ip = unsafe { + uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void + }; + if !ip.is_null() && ip_before_insn == 0 { + // this is a non-signaling frame, so `ip` refers to the address + // after the calling instruction. account for that. + ip = (ip as usize - 1) as *mut _; + } + + // dladdr() on osx gets whiny when we use FindEnclosingFunction, and + // it appears to work fine without it, so we only use + // FindEnclosingFunction on non-osx platforms. In doing so, we get a + // slightly more accurate stack trace in the process. + // + // This is often because panic involves the last instruction of a + // function being "call std::rt::begin_unwind", with no ret + // 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 symaddr = if cfg!(target_os = "macos") || cfg!(target_os = "ios") { + ip + } else { + unsafe { uw::_Unwind_FindEnclosingFunction(ip) } + }; + + // Don't print out the first few frames (they're not user frames) + cx.idx += 1; + if cx.idx <= 0 { return uw::_URC_NO_REASON } + // Don't print ginormous backtraces + if cx.idx > 100 { + match write!(cx.writer, " ... <frames omitted>\n") { + Ok(()) => {} + Err(e) => { cx.last_error = Some(e); } + } + return uw::_URC_FAILURE + } + + // Once we hit an error, stop trying to print more frames + if cx.last_error.is_some() { return uw::_URC_FAILURE } + + match print(cx.writer, cx.idx, ip, symaddr) { + Ok(()) => {} + Err(e) => { cx.last_error = Some(e); } + } + + // keep going + return uw::_URC_NO_REASON + } +} + +/// Unwind library interface used for backtraces +/// +/// 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)] +mod uw { + pub use self::_Unwind_Reason_Code::*; + + use libc; + + #[repr(C)] + pub enum _Unwind_Reason_Code { + _URC_NO_REASON = 0, + _URC_FOREIGN_EXCEPTION_CAUGHT = 1, + _URC_FATAL_PHASE2_ERROR = 2, + _URC_FATAL_PHASE1_ERROR = 3, + _URC_NORMAL_STOP = 4, + _URC_END_OF_STACK = 5, + _URC_HANDLER_FOUND = 6, + _URC_INSTALL_CONTEXT = 7, + _URC_CONTINUE_UNWIND = 8, + _URC_FAILURE = 9, // used only by ARM EABI + } + + pub enum _Unwind_Context {} + + pub type _Unwind_Trace_Fn = + extern fn(ctx: *mut _Unwind_Context, + arg: *mut libc::c_void) -> _Unwind_Reason_Code; + + extern { + // No native _Unwind_Backtrace on iOS + #[cfg(not(all(target_os = "ios", target_arch = "arm")))] + pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn, + trace_argument: *mut libc::c_void) + -> _Unwind_Reason_Code; + + // available since GCC 4.2.0, should be fine for our purpose + #[cfg(all(not(all(target_os = "android", target_arch = "arm")), + not(all(target_os = "linux", target_arch = "arm"))))] + pub fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context, + ip_before_insn: *mut libc::c_int) + -> libc::uintptr_t; + + #[cfg(all(not(target_os = "android"), + not(all(target_os = "linux", target_arch = "arm"))))] + pub fn _Unwind_FindEnclosingFunction(pc: *mut libc::c_void) + -> *mut libc::c_void; + } + + // On android, the function _Unwind_GetIP is a macro, and this is the + // expansion of the macro. This is all copy/pasted directly from the + // header file with the definition of _Unwind_GetIP. + #[cfg(any(all(target_os = "android", target_arch = "arm"), + all(target_os = "linux", target_arch = "arm")))] + pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> libc::uintptr_t { + #[repr(C)] + enum _Unwind_VRS_Result { + _UVRSR_OK = 0, + _UVRSR_NOT_IMPLEMENTED = 1, + _UVRSR_FAILED = 2, + } + #[repr(C)] + enum _Unwind_VRS_RegClass { + _UVRSC_CORE = 0, + _UVRSC_VFP = 1, + _UVRSC_FPA = 2, + _UVRSC_WMMXD = 3, + _UVRSC_WMMXC = 4, + } + #[repr(C)] + enum _Unwind_VRS_DataRepresentation { + _UVRSD_UINT32 = 0, + _UVRSD_VFPX = 1, + _UVRSD_FPAX = 2, + _UVRSD_UINT64 = 3, + _UVRSD_FLOAT = 4, + _UVRSD_DOUBLE = 5, + } + + type _Unwind_Word = libc::c_uint; + extern { + fn _Unwind_VRS_Get(ctx: *mut _Unwind_Context, + klass: _Unwind_VRS_RegClass, + word: _Unwind_Word, + repr: _Unwind_VRS_DataRepresentation, + data: *mut libc::c_void) + -> _Unwind_VRS_Result; + } + + let mut val: _Unwind_Word = 0; + let ptr = &mut val as *mut _Unwind_Word; + let _ = _Unwind_VRS_Get(ctx, _Unwind_VRS_RegClass::_UVRSC_CORE, 15, + _Unwind_VRS_DataRepresentation::_UVRSD_UINT32, + ptr as *mut libc::c_void); + (val & !1) as libc::uintptr_t + } + + // This function doesn't exist on Android or ARM/Linux, so make it same + // to _Unwind_GetIP + #[cfg(any(all(target_os = "android", target_arch = "arm"), + all(target_os = "linux", target_arch = "arm")))] + pub unsafe fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context, + ip_before_insn: *mut libc::c_int) + -> libc::uintptr_t + { + *ip_before_insn = 0; + _Unwind_GetIP(ctx) + } + + // This function also doesn't exist on Android or ARM/Linux, so make it + // a no-op + #[cfg(any(target_os = "android", + all(target_os = "linux", target_arch = "arm")))] + pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut libc::c_void) + -> *mut libc::c_void + { + pc + } +} diff --git a/src/libstd/sys/unix/backtrace/tracing/mod.rs b/src/libstd/sys/unix/backtrace/tracing/mod.rs new file mode 100644 index 00000000000..c9c8e260d2f --- /dev/null +++ b/src/libstd/sys/unix/backtrace/tracing/mod.rs @@ -0,0 +1,18 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub use self::imp::*; + +#[cfg(not(all(target_os = "ios", target_arch = "arm")))] +#[path = "gcc_s.rs"] +mod imp; +#[cfg(all(target_os = "ios", target_arch = "arm"))] +#[path = "backtrace_fn.rs"] +mod imp; | 
