1 // Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
13 extern crate backtrace_sys
as bt
;
16 use std
::{ptr, slice}
;
17 use std
::sync
::{ONCE_INIT, Once}
;
19 use libc
::{self, c_char, c_int, c_void, uintptr_t}
;
23 use types
::BytesOrWideString
;
28 symname
: *const c_char
,
32 filename
: *const c_char
,
34 function
: *const c_char
,
39 pub fn name(&self) -> Option
<SymbolName
> {
40 let ptr
= match *self {
41 Symbol
::Syminfo { symname, .. }
=> symname
,
42 Symbol
::Pcinfo { function, .. }
=> function
,
47 Some(SymbolName
::new(unsafe { CStr::from_ptr(ptr).to_bytes() }
))
51 pub fn addr(&self) -> Option
<*mut c_void
> {
52 let pc
= match *self {
53 Symbol
::Syminfo { pc, .. }
=> pc
,
54 Symbol
::Pcinfo { pc, .. }
=> pc
,
56 if pc
== 0 {None}
else {Some(pc as *mut _)}
59 pub fn filename_raw(&self) -> Option
<BytesOrWideString
> {
61 Symbol
::Syminfo { .. }
=> None
,
62 Symbol
::Pcinfo { filename, .. }
=> {
63 let ptr
= filename
as *const u8;
65 let len
= libc
::strlen(filename
);
66 Some(BytesOrWideString
::Bytes(slice
::from_raw_parts(ptr
, len
)))
72 pub fn lineno(&self) -> Option
<u32> {
74 Symbol
::Syminfo { .. }
=> None
,
75 Symbol
::Pcinfo { lineno, .. }
=> Some(lineno
as u32),
80 extern fn error_cb(_data
: *mut c_void
, _msg
: *const c_char
,
85 extern fn syminfo_cb(data
: *mut c_void
,
87 symname
: *const c_char
,
89 _symsize
: uintptr_t
) {
91 call(data
, &super::Symbol
{
92 inner
: Symbol
::Syminfo
{
100 extern fn pcinfo_cb(data
: *mut c_void
,
102 filename
: *const c_char
,
104 function
: *const c_char
) -> c_int
{
106 if filename
.is_null() || function
.is_null() {
109 call(data
, &super::Symbol
{
110 inner
: Symbol
::Pcinfo
{
121 unsafe fn call(data
: *mut c_void
, sym
: &super::Symbol
) {
122 let cb
= data
as *mut &mut FnMut(&super::Symbol
);
123 let mut bomb
= ::Bomb { enabled: true }
;
125 bomb
.enabled
= false;
128 // The libbacktrace API supports creating a state, but it does not
129 // support destroying a state. I personally take this to mean that a
130 // state is meant to be created and then live forever.
132 // I would love to register an at_exit() handler which cleans up this
133 // state, but libbacktrace provides no way to do so.
135 // With these constraints, this function has a statically cached state
136 // that is calculated the first time this is requested. Remember that
137 // backtracing all happens serially (one global lock).
139 // Things don't work so well on not-Linux since libbacktrace can't track down
140 // that executable this is. We at one point used env::current_exe but it turns
141 // out that there are some serious security issues with that approach.
143 // Specifically, on certain platforms like BSDs, a malicious actor can cause an
144 // arbitrary file to be placed at the path returned by current_exe. libbacktrace
145 // does not behave defensively in the presence of ill-formed DWARF information,
146 // and has been demonstrated to segfault in at least one case. There is no
147 // evidence at the moment to suggest that a more carefully constructed file
148 // can't cause arbitrary code execution. As a result of all of this, we don't
149 // hint libbacktrace with the path to the current process.
150 unsafe fn init_state() -> *mut bt
::backtrace_state
{
151 static mut STATE
: *mut bt
::backtrace_state
= 0 as *mut _
;
152 static INIT
: Once
= ONCE_INIT
;
154 // Our libbacktrace may not have multithreading support, so
155 // set `threaded = 0` and synchronize ourselves.
156 STATE
= bt
::backtrace_create_state(ptr
::null(), 0, error_cb
,
163 pub unsafe fn resolve(symaddr
: *mut c_void
, mut cb
: &mut FnMut(&super::Symbol
))
165 // backtrace errors are currently swept under the rug
166 let state
= init_state();
171 let ret
= bt
::backtrace_pcinfo(state
, symaddr
as uintptr_t
,
173 &mut cb
as *mut _
as *mut _
);
175 bt
::backtrace_syminfo(state
, symaddr
as uintptr_t
,
176 syminfo_cb
, error_cb
,
177 &mut cb
as *mut _
as *mut _
);