]> git.proxmox.com Git - cargo.git/blob - vendor/backtrace/src/symbolize/libbacktrace.rs
New upstream version 0.33.0
[cargo.git] / vendor / backtrace / src / symbolize / libbacktrace.rs
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.
4 //
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.
10
11 #![allow(bad_style)]
12
13 extern crate backtrace_sys as bt;
14
15 use std::ffi::CStr;
16 use std::{ptr, slice};
17 use std::sync::{ONCE_INIT, Once};
18
19 use libc::{self, c_char, c_int, c_void, uintptr_t};
20
21 use SymbolName;
22
23 use types::BytesOrWideString;
24
25 pub enum Symbol {
26 Syminfo {
27 pc: uintptr_t,
28 symname: *const c_char,
29 },
30 Pcinfo {
31 pc: uintptr_t,
32 filename: *const c_char,
33 lineno: c_int,
34 function: *const c_char,
35 },
36 }
37
38 impl Symbol {
39 pub fn name(&self) -> Option<SymbolName> {
40 let ptr = match *self {
41 Symbol::Syminfo { symname, .. } => symname,
42 Symbol::Pcinfo { function, .. } => function,
43 };
44 if ptr.is_null() {
45 None
46 } else {
47 Some(SymbolName::new(unsafe { CStr::from_ptr(ptr).to_bytes() }))
48 }
49 }
50
51 pub fn addr(&self) -> Option<*mut c_void> {
52 let pc = match *self {
53 Symbol::Syminfo { pc, .. } => pc,
54 Symbol::Pcinfo { pc, .. } => pc,
55 };
56 if pc == 0 {None} else {Some(pc as *mut _)}
57 }
58
59 pub fn filename_raw(&self) -> Option<BytesOrWideString> {
60 match *self {
61 Symbol::Syminfo { .. } => None,
62 Symbol::Pcinfo { filename, .. } => {
63 let ptr = filename as *const u8;
64 unsafe {
65 let len = libc::strlen(filename);
66 Some(BytesOrWideString::Bytes(slice::from_raw_parts(ptr, len)))
67 }
68 }
69 }
70 }
71
72 pub fn lineno(&self) -> Option<u32> {
73 match *self {
74 Symbol::Syminfo { .. } => None,
75 Symbol::Pcinfo { lineno, .. } => Some(lineno as u32),
76 }
77 }
78 }
79
80 extern fn error_cb(_data: *mut c_void, _msg: *const c_char,
81 _errnum: c_int) {
82 // do nothing for now
83 }
84
85 extern fn syminfo_cb(data: *mut c_void,
86 pc: uintptr_t,
87 symname: *const c_char,
88 _symval: uintptr_t,
89 _symsize: uintptr_t) {
90 unsafe {
91 call(data, &super::Symbol {
92 inner: Symbol::Syminfo {
93 pc: pc,
94 symname: symname,
95 },
96 });
97 }
98 }
99
100 extern fn pcinfo_cb(data: *mut c_void,
101 pc: uintptr_t,
102 filename: *const c_char,
103 lineno: c_int,
104 function: *const c_char) -> c_int {
105 unsafe {
106 if filename.is_null() || function.is_null() {
107 return -1
108 }
109 call(data, &super::Symbol {
110 inner: Symbol::Pcinfo {
111 pc: pc,
112 filename: filename,
113 lineno: lineno,
114 function: function,
115 },
116 });
117 return 0
118 }
119 }
120
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 };
124 (*cb)(sym);
125 bomb.enabled = false;
126 }
127
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.
131 //
132 // I would love to register an at_exit() handler which cleans up this
133 // state, but libbacktrace provides no way to do so.
134 //
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).
138 //
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.
142 //
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;
153 INIT.call_once(|| {
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,
157 ptr::null_mut());
158 });
159
160 STATE
161 }
162
163 pub unsafe fn resolve(symaddr: *mut c_void, mut cb: &mut FnMut(&super::Symbol))
164 {
165 // backtrace errors are currently swept under the rug
166 let state = init_state();
167 if state.is_null() {
168 return
169 }
170
171 let ret = bt::backtrace_pcinfo(state, symaddr as uintptr_t,
172 pcinfo_cb, error_cb,
173 &mut cb as *mut _ as *mut _);
174 if ret != 0 {
175 bt::backtrace_syminfo(state, symaddr as uintptr_t,
176 syminfo_cb, error_cb,
177 &mut cb as *mut _ as *mut _);
178 }
179 }