]> git.proxmox.com Git - cargo.git/blobdiff - vendor/backtrace/src/backtrace/libunwind.rs
New upstream version 0.35.0
[cargo.git] / vendor / backtrace / src / backtrace / libunwind.rs
index b2d6fa6d38db1afa64f716c99a2967863abcaa46..f1e35a42e76efaa2ceb0f716828970ab974ca916 100644 (file)
@@ -8,17 +8,49 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+//! Backtrace support using libunwind/gcc_s/etc APIs.
+//!
+//! This module contains the ability to unwind the stack using libunwind-style
+//! APIs. Note that there's a whole bunch of implementations of the
+//! libunwind-like API, and this is just trying to be compatible with most of
+//! them all at once instead of being picky.
+//!
+//! The libunwind API is powered by `_Unwind_Backtrace` and is in practice very
+//! reliable at generating a backtrace. It's not entirely clear how it does it
+//! (frame pointers? eh_frame info? both?) but it seems to work!
+//!
+//! Most of the complexity of this module is handling the various platform
+//! differences across libunwind implementations. Otherwise this is a pretty
+//! straightforward Rust binding to the libunwind APIs.
+//!
+//! This is the default unwinding API for all non-Windows platforms currently.
+
 use types::c_void;
 
-pub struct Frame {
-    ctx: *mut uw::_Unwind_Context,
+pub enum Frame {
+    Raw(*mut uw::_Unwind_Context),
+    Cloned {
+        ip: *mut c_void,
+        symbol_address: *mut c_void,
+    },
 }
 
+// With a raw libunwind pointer it should only ever be access in a readonly
+// threadsafe fashion, so it's `Sync`. When sending to other threads via `Clone`
+// we always switch to a version which doesn't retain interior pointers, so we
+// should be `Send` as well.
+unsafe impl Send for Frame {}
+unsafe impl Sync for Frame {}
+
 impl Frame {
     pub fn ip(&self) -> *mut c_void {
+        let ctx = match *self {
+            Frame::Raw(ctx) => ctx,
+            Frame::Cloned { ip, .. } => return ip,
+        };
         let mut ip_before_insn = 0;
         let mut ip = unsafe {
-            uw::_Unwind_GetIPInfo(self.ctx, &mut ip_before_insn) as *mut c_void
+            uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut c_void
         };
         if !ip.is_null() && ip_before_insn == 0 {
             // this is a non-signaling frame, so `ip` refers to the address
@@ -29,6 +61,10 @@ impl Frame {
     }
 
     pub fn symbol_address(&self) -> *mut c_void {
+        if let Frame::Cloned { symbol_address, .. } = *self {
+            return symbol_address;
+        }
+
         // 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
@@ -47,6 +83,15 @@ impl Frame {
     }
 }
 
+impl Clone for Frame {
+    fn clone(&self) -> Frame {
+        Frame::Cloned {
+            ip: self.ip(),
+            symbol_address: self.symbol_address(),
+        }
+    }
+}
+
 #[inline(always)]
 pub unsafe fn trace(mut cb: &mut FnMut(&super::Frame) -> bool) {
     uw::_Unwind_Backtrace(trace_fn, &mut cb as *mut _ as *mut _);
@@ -55,7 +100,7 @@ pub unsafe fn trace(mut cb: &mut FnMut(&super::Frame) -> bool) {
                        arg: *mut c_void) -> uw::_Unwind_Reason_Code {
         let cb = unsafe { &mut *(arg as *mut &mut FnMut(&super::Frame) -> bool) };
         let cx = super::Frame {
-            inner: Frame { ctx: ctx },
+            inner: Frame::Raw(ctx),
         };
 
         let mut bomb = ::Bomb { enabled: true };
@@ -113,12 +158,14 @@ mod uw {
 
         // 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 = "freebsd", target_arch = "arm")),
                   not(all(target_os = "linux", target_arch = "arm"))))]
         pub fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context,
                                  ip_before_insn: *mut c_int)
                     -> libc::uintptr_t;
 
         #[cfg(all(not(target_os = "android"),
+                  not(all(target_os = "freebsd", target_arch = "arm")),
                   not(all(target_os = "linux", target_arch = "arm"))))]
         pub fn _Unwind_FindEnclosingFunction(pc: *mut c_void)
             -> *mut c_void;
@@ -128,6 +175,7 @@ mod uw {
     // 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 = "freebsd", target_arch = "arm"),
               all(target_os = "linux", target_arch = "arm")))]
     pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> libc::uintptr_t {
         #[repr(C)]
@@ -175,6 +223,7 @@ mod uw {
     // 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 = "freebsd", target_arch = "arm"),
               all(target_os = "linux", target_arch = "arm")))]
     pub unsafe fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context,
                                     ip_before_insn: *mut c_int)
@@ -187,6 +236,7 @@ mod uw {
     // 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 = "freebsd", target_arch = "arm"),
               all(target_os = "linux", target_arch = "arm")))]
     pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut c_void)
         -> *mut c_void