]> git.proxmox.com Git - rustc.git/blame - src/libstd/sys/unix/backtrace.rs
Imported Upstream version 1.3.0+dfsg1
[rustc.git] / src / libstd / sys / unix / backtrace.rs
CommitLineData
85aaf69f 1// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
1a4d82fc
JJ
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/// Backtrace support built on libgcc with some extra OS-specific support
12///
13/// Some methods of getting a backtrace:
14///
15/// * The backtrace() functions on unix. It turns out this doesn't work very
16/// well for green threads on OSX, and the address to symbol portion of it
17/// suffers problems that are described below.
18///
19/// * Using libunwind. This is more difficult than it sounds because libunwind
20/// isn't installed everywhere by default. It's also a bit of a hefty library,
21/// so possibly not the best option. When testing, libunwind was excellent at
22/// getting both accurate backtraces and accurate symbols across platforms.
23/// This route was not chosen in favor of the next option, however.
24///
bd371182 25/// * We're already using libgcc_s for exceptions in rust (triggering thread
1a4d82fc
JJ
26/// unwinding and running destructors on the stack), and it turns out that it
27/// conveniently comes with a function that also gives us a backtrace. All of
28/// these functions look like _Unwind_*, but it's not quite the full
29/// repertoire of the libunwind API. Due to it already being in use, this was
30/// the chosen route of getting a backtrace.
31///
32/// After choosing libgcc_s for backtraces, the sad part is that it will only
33/// give us a stack trace of instruction pointers. Thankfully these instruction
34/// pointers are accurate (they work for green and native threads), but it's
35/// then up to us again to figure out how to translate these addresses to
36/// symbols. As with before, we have a few options. Before, that, a little bit
37/// of an interlude about symbols. This is my very limited knowledge about
38/// symbol tables, and this information is likely slightly wrong, but the
39/// general idea should be correct.
40///
41/// When talking about symbols, it's helpful to know a few things about where
42/// symbols are located. Some symbols are located in the dynamic symbol table
43/// of the executable which in theory means that they're available for dynamic
44/// linking and lookup. Other symbols end up only in the local symbol table of
45/// the file. This loosely corresponds to pub and priv functions in Rust.
46///
47/// Armed with this knowledge, we know that our solution for address to symbol
48/// translation will need to consult both the local and dynamic symbol tables.
49/// With that in mind, here's our options of translating an address to
50/// a symbol.
51///
52/// * Use dladdr(). The original backtrace()-based idea actually uses dladdr()
53/// behind the scenes to translate, and this is why backtrace() was not used.
54/// Conveniently, this method works fantastically on OSX. It appears dladdr()
55/// uses magic to consult the local symbol table, or we're putting everything
56/// in the dynamic symbol table anyway. Regardless, for OSX, this is the
57/// method used for translation. It's provided by the system and easy to do.o
58///
59/// Sadly, all other systems have a dladdr() implementation that does not
60/// consult the local symbol table. This means that most functions are blank
61/// because they don't have symbols. This means that we need another solution.
62///
63/// * Use unw_get_proc_name(). This is part of the libunwind api (not the
64/// libgcc_s version of the libunwind api), but involves taking a dependency
65/// to libunwind. We may pursue this route in the future if we bundle
66/// libunwind, but libunwind was unwieldy enough that it was not chosen at
67/// this time to provide this functionality.
68///
69/// * Shell out to a utility like `readelf`. Crazy though it may sound, it's a
70/// semi-reasonable solution. The stdlib already knows how to spawn processes,
71/// so in theory it could invoke readelf, parse the output, and consult the
72/// local/dynamic symbol tables from there. This ended up not getting chosen
73/// due to the craziness of the idea plus the advent of the next option.
74///
75/// * Use `libbacktrace`. It turns out that this is a small library bundled in
76/// the gcc repository which provides backtrace and symbol translation
77/// functionality. All we really need from it is the backtrace functionality,
78/// and we only really need this on everything that's not OSX, so this is the
79/// chosen route for now.
80///
81/// In summary, the current situation uses libgcc_s to get a trace of stack
82/// pointers, and we use dladdr() or libbacktrace to translate these addresses
83/// to symbols. This is a bit of a hokey implementation as-is, but it works for
84/// all unix platforms we support right now, so it at least gets the job done.
85
86use prelude::v1::*;
c34b1796 87use io::prelude::*;
1a4d82fc 88
85aaf69f 89use ffi::CStr;
c34b1796 90use io;
1a4d82fc
JJ
91use libc;
92use mem;
93use str;
62682a34 94use sync::StaticMutex;
1a4d82fc
JJ
95
96use sys_common::backtrace::*;
97
98/// As always - iOS on arm uses SjLj exceptions and
99/// _Unwind_Backtrace is even not available there. Still,
100/// backtraces could be extracted using a backtrace function,
101/// which thanks god is public
102///
103/// As mentioned in a huge comment block above, backtrace doesn't
104/// play well with green threads, so while it is extremely nice
105/// and simple to use it should be used only on iOS devices as the
106/// only viable option.
107#[cfg(all(target_os = "ios", target_arch = "arm"))]
108#[inline(never)]
c34b1796 109pub fn write(w: &mut Write) -> io::Result<()> {
1a4d82fc
JJ
110 extern {
111 fn backtrace(buf: *mut *mut libc::c_void,
112 sz: libc::c_int) -> libc::c_int;
113 }
114
115 // while it doesn't requires lock for work as everything is
116 // local, it still displays much nicer backtraces when a
bd371182 117 // couple of threads panic simultaneously
62682a34 118 static LOCK: StaticMutex = StaticMutex::new();
c34b1796 119 let _g = LOCK.lock();
1a4d82fc
JJ
120
121 try!(writeln!(w, "stack backtrace:"));
122 // 100 lines should be enough
c34b1796 123 const SIZE: usize = 100;
1a4d82fc 124 let mut buf: [*mut libc::c_void; SIZE] = unsafe {mem::zeroed()};
c34b1796 125 let cnt = unsafe { backtrace(buf.as_mut_ptr(), SIZE as libc::c_int) as usize};
1a4d82fc
JJ
126
127 // skipping the first one as it is write itself
c1a9b12d
SL
128 for i in 1..cnt {
129 try!(print(w, i as isize, buf[i], buf[i]))
130 }
131 Ok(())
1a4d82fc
JJ
132}
133
134#[cfg(not(all(target_os = "ios", target_arch = "arm")))]
135#[inline(never)] // if we know this is a function call, we can skip it when
136 // tracing
c34b1796 137pub fn write(w: &mut Write) -> io::Result<()> {
1a4d82fc 138 struct Context<'a> {
c34b1796
AL
139 idx: isize,
140 writer: &'a mut (Write+'a),
141 last_error: Option<io::Error>,
1a4d82fc
JJ
142 }
143
144 // When using libbacktrace, we use some necessary global state, so we
145 // need to prevent more than one thread from entering this block. This
146 // is semi-reasonable in terms of printing anyway, and we know that all
147 // I/O done here is blocking I/O, not green I/O, so we don't have to
148 // worry about this being a native vs green mutex.
62682a34 149 static LOCK: StaticMutex = StaticMutex::new();
c34b1796 150 let _g = LOCK.lock();
1a4d82fc
JJ
151
152 try!(writeln!(w, "stack backtrace:"));
153
154 let mut cx = Context { writer: w, last_error: None, idx: 0 };
155 return match unsafe {
156 uw::_Unwind_Backtrace(trace_fn,
157 &mut cx as *mut Context as *mut libc::c_void)
158 } {
159 uw::_URC_NO_REASON => {
160 match cx.last_error {
161 Some(err) => Err(err),
162 None => Ok(())
163 }
164 }
165 _ => Ok(()),
166 };
167
168 extern fn trace_fn(ctx: *mut uw::_Unwind_Context,
169 arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code {
170 let cx: &mut Context = unsafe { mem::transmute(arg) };
c34b1796
AL
171 let mut ip_before_insn = 0;
172 let mut ip = unsafe {
173 uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void
174 };
175 if !ip.is_null() && ip_before_insn == 0 {
176 // this is a non-signaling frame, so `ip` refers to the address
177 // after the calling instruction. account for that.
178 ip = (ip as usize - 1) as *mut _;
179 }
180
1a4d82fc
JJ
181 // dladdr() on osx gets whiny when we use FindEnclosingFunction, and
182 // it appears to work fine without it, so we only use
183 // FindEnclosingFunction on non-osx platforms. In doing so, we get a
184 // slightly more accurate stack trace in the process.
185 //
186 // This is often because panic involves the last instruction of a
187 // function being "call std::rt::begin_unwind", with no ret
188 // instructions after it. This means that the return instruction
189 // pointer points *outside* of the calling function, and by
190 // unwinding it we go back to the original function.
c34b1796 191 let symaddr = if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
1a4d82fc
JJ
192 ip
193 } else {
194 unsafe { uw::_Unwind_FindEnclosingFunction(ip) }
195 };
196
197 // Don't print out the first few frames (they're not user frames)
198 cx.idx += 1;
199 if cx.idx <= 0 { return uw::_URC_NO_REASON }
200 // Don't print ginormous backtraces
201 if cx.idx > 100 {
202 match write!(cx.writer, " ... <frames omitted>\n") {
203 Ok(()) => {}
204 Err(e) => { cx.last_error = Some(e); }
205 }
206 return uw::_URC_FAILURE
207 }
208
209 // Once we hit an error, stop trying to print more frames
210 if cx.last_error.is_some() { return uw::_URC_FAILURE }
211
c34b1796 212 match print(cx.writer, cx.idx, ip, symaddr) {
1a4d82fc
JJ
213 Ok(()) => {}
214 Err(e) => { cx.last_error = Some(e); }
215 }
216
217 // keep going
218 return uw::_URC_NO_REASON
219 }
220}
221
222#[cfg(any(target_os = "macos", target_os = "ios"))]
c34b1796
AL
223fn print(w: &mut Write, idx: isize, addr: *mut libc::c_void,
224 _symaddr: *mut libc::c_void) -> io::Result<()> {
1a4d82fc
JJ
225 use intrinsics;
226 #[repr(C)]
227 struct Dl_info {
228 dli_fname: *const libc::c_char,
229 dli_fbase: *mut libc::c_void,
230 dli_sname: *const libc::c_char,
231 dli_saddr: *mut libc::c_void,
232 }
233 extern {
234 fn dladdr(addr: *const libc::c_void,
235 info: *mut Dl_info) -> libc::c_int;
236 }
237
238 let mut info: Dl_info = unsafe { intrinsics::init() };
85aaf69f 239 if unsafe { dladdr(addr, &mut info) == 0 } {
1a4d82fc
JJ
240 output(w, idx,addr, None)
241 } else {
242 output(w, idx, addr, Some(unsafe {
85aaf69f 243 CStr::from_ptr(info.dli_sname).to_bytes()
1a4d82fc
JJ
244 }))
245 }
246}
247
248#[cfg(not(any(target_os = "macos", target_os = "ios")))]
c34b1796
AL
249fn print(w: &mut Write, idx: isize, addr: *mut libc::c_void,
250 symaddr: *mut libc::c_void) -> io::Result<()> {
85aaf69f 251 use env;
c34b1796 252 use os::unix::prelude::*;
1a4d82fc
JJ
253 use ptr;
254
255 ////////////////////////////////////////////////////////////////////////
256 // libbacktrace.h API
257 ////////////////////////////////////////////////////////////////////////
258 type backtrace_syminfo_callback =
259 extern "C" fn(data: *mut libc::c_void,
260 pc: libc::uintptr_t,
261 symname: *const libc::c_char,
262 symval: libc::uintptr_t,
263 symsize: libc::uintptr_t);
c34b1796
AL
264 type backtrace_full_callback =
265 extern "C" fn(data: *mut libc::c_void,
266 pc: libc::uintptr_t,
267 filename: *const libc::c_char,
268 lineno: libc::c_int,
269 function: *const libc::c_char) -> libc::c_int;
1a4d82fc
JJ
270 type backtrace_error_callback =
271 extern "C" fn(data: *mut libc::c_void,
272 msg: *const libc::c_char,
273 errnum: libc::c_int);
274 enum backtrace_state {}
275 #[link(name = "backtrace", kind = "static")]
276 #[cfg(not(test))]
277 extern {}
278
279 extern {
280 fn backtrace_create_state(filename: *const libc::c_char,
281 threaded: libc::c_int,
282 error: backtrace_error_callback,
283 data: *mut libc::c_void)
284 -> *mut backtrace_state;
285 fn backtrace_syminfo(state: *mut backtrace_state,
286 addr: libc::uintptr_t,
287 cb: backtrace_syminfo_callback,
288 error: backtrace_error_callback,
289 data: *mut libc::c_void) -> libc::c_int;
c34b1796
AL
290 fn backtrace_pcinfo(state: *mut backtrace_state,
291 addr: libc::uintptr_t,
292 cb: backtrace_full_callback,
293 error: backtrace_error_callback,
294 data: *mut libc::c_void) -> libc::c_int;
1a4d82fc
JJ
295 }
296
297 ////////////////////////////////////////////////////////////////////////
298 // helper callbacks
299 ////////////////////////////////////////////////////////////////////////
300
c34b1796
AL
301 type FileLine = (*const libc::c_char, libc::c_int);
302
1a4d82fc
JJ
303 extern fn error_cb(_data: *mut libc::c_void, _msg: *const libc::c_char,
304 _errnum: libc::c_int) {
305 // do nothing for now
306 }
307 extern fn syminfo_cb(data: *mut libc::c_void,
308 _pc: libc::uintptr_t,
309 symname: *const libc::c_char,
310 _symval: libc::uintptr_t,
311 _symsize: libc::uintptr_t) {
312 let slot = data as *mut *const libc::c_char;
313 unsafe { *slot = symname; }
314 }
c34b1796
AL
315 extern fn pcinfo_cb(data: *mut libc::c_void,
316 _pc: libc::uintptr_t,
317 filename: *const libc::c_char,
318 lineno: libc::c_int,
319 _function: *const libc::c_char) -> libc::c_int {
320 if !filename.is_null() {
321 let slot = data as *mut &mut [FileLine];
322 let buffer = unsafe {ptr::read(slot)};
323
324 // if the buffer is not full, add file:line to the buffer
325 // and adjust the buffer for next possible calls to pcinfo_cb.
326 if !buffer.is_empty() {
327 buffer[0] = (filename, lineno);
328 unsafe { ptr::write(slot, &mut buffer[1..]); }
329 }
330 }
331
332 0
333 }
1a4d82fc
JJ
334
335 // The libbacktrace API supports creating a state, but it does not
336 // support destroying a state. I personally take this to mean that a
337 // state is meant to be created and then live forever.
338 //
339 // I would love to register an at_exit() handler which cleans up this
340 // state, but libbacktrace provides no way to do so.
341 //
342 // With these constraints, this function has a statically cached state
343 // that is calculated the first time this is requested. Remember that
344 // backtracing all happens serially (one global lock).
345 //
346 // An additionally oddity in this function is that we initialize the
347 // filename via self_exe_name() to pass to libbacktrace. It turns out
348 // that on Linux libbacktrace seamlessly gets the filename of the
349 // current executable, but this fails on freebsd. by always providing
350 // it, we make sure that libbacktrace never has a reason to not look up
351 // the symbols. The libbacktrace API also states that the filename must
352 // be in "permanent memory", so we copy it to a static and then use the
353 // static as the pointer.
354 //
355 // FIXME: We also call self_exe_name() on DragonFly BSD. I haven't
356 // tested if this is required or not.
357 unsafe fn init_state() -> *mut backtrace_state {
358 static mut STATE: *mut backtrace_state = 0 as *mut backtrace_state;
359 static mut LAST_FILENAME: [libc::c_char; 256] = [0; 256];
360 if !STATE.is_null() { return STATE }
361 let selfname = if cfg!(target_os = "freebsd") ||
85aaf69f 362 cfg!(target_os = "dragonfly") ||
c34b1796 363 cfg!(target_os = "bitrig") ||
c1a9b12d 364 cfg!(target_os = "netbsd") ||
85aaf69f
SL
365 cfg!(target_os = "openbsd") {
366 env::current_exe().ok()
1a4d82fc
JJ
367 } else {
368 None
369 };
370 let filename = match selfname {
371 Some(path) => {
c34b1796 372 let bytes = path.as_os_str().as_bytes();
1a4d82fc
JJ
373 if bytes.len() < LAST_FILENAME.len() {
374 let i = bytes.iter();
375 for (slot, val) in LAST_FILENAME.iter_mut().zip(i) {
376 *slot = *val as libc::c_char;
377 }
378 LAST_FILENAME.as_ptr()
379 } else {
380 ptr::null()
381 }
382 }
383 None => ptr::null(),
384 };
385 STATE = backtrace_create_state(filename, 0, error_cb,
386 ptr::null_mut());
387 return STATE
388 }
389
390 ////////////////////////////////////////////////////////////////////////
391 // translation
392 ////////////////////////////////////////////////////////////////////////
393
394 // backtrace errors are currently swept under the rug, only I/O
395 // errors are reported
396 let state = unsafe { init_state() };
397 if state.is_null() {
398 return output(w, idx, addr, None)
399 }
85aaf69f 400 let mut data = ptr::null();
1a4d82fc
JJ
401 let data_addr = &mut data as *mut *const libc::c_char;
402 let ret = unsafe {
c34b1796 403 backtrace_syminfo(state, symaddr as libc::uintptr_t,
1a4d82fc
JJ
404 syminfo_cb, error_cb,
405 data_addr as *mut libc::c_void)
406 };
407 if ret == 0 || data.is_null() {
c34b1796 408 try!(output(w, idx, addr, None));
1a4d82fc 409 } else {
c34b1796
AL
410 try!(output(w, idx, addr, Some(unsafe { CStr::from_ptr(data).to_bytes() })));
411 }
412
413 // pcinfo may return an arbitrary number of file:line pairs,
414 // in the order of stack trace (i.e. inlined calls first).
415 // in order to avoid allocation, we stack-allocate a fixed size of entries.
416 const FILELINE_SIZE: usize = 32;
417 let mut fileline_buf = [(ptr::null(), -1); FILELINE_SIZE];
418 let ret;
419 let fileline_count;
420 {
421 let mut fileline_win: &mut [FileLine] = &mut fileline_buf;
422 let fileline_addr = &mut fileline_win as *mut &mut [FileLine];
423 ret = unsafe {
424 backtrace_pcinfo(state, addr as libc::uintptr_t,
425 pcinfo_cb, error_cb,
426 fileline_addr as *mut libc::c_void)
427 };
428 fileline_count = FILELINE_SIZE - fileline_win.len();
429 }
430 if ret == 0 {
431 for (i, &(file, line)) in fileline_buf[..fileline_count].iter().enumerate() {
432 if file.is_null() { continue; } // just to be sure
433 let file = unsafe { CStr::from_ptr(file).to_bytes() };
434 try!(output_fileline(w, file, line, i == FILELINE_SIZE - 1));
435 }
1a4d82fc 436 }
c34b1796
AL
437
438 Ok(())
1a4d82fc
JJ
439}
440
441// Finally, after all that work above, we can emit a symbol.
c34b1796
AL
442fn output(w: &mut Write, idx: isize, addr: *mut libc::c_void,
443 s: Option<&[u8]>) -> io::Result<()> {
1a4d82fc
JJ
444 try!(write!(w, " {:2}: {:2$?} - ", idx, addr, HEX_WIDTH));
445 match s.and_then(|s| str::from_utf8(s).ok()) {
446 Some(string) => try!(demangle(w, string)),
447 None => try!(write!(w, "<unknown>")),
448 }
85aaf69f 449 w.write_all(&['\n' as u8])
1a4d82fc
JJ
450}
451
c34b1796
AL
452#[allow(dead_code)]
453fn output_fileline(w: &mut Write, file: &[u8], line: libc::c_int,
454 more: bool) -> io::Result<()> {
455 let file = str::from_utf8(file).unwrap_or("<unknown>");
456 // prior line: " ##: {:2$} - func"
457 try!(write!(w, " {:3$}at {}:{}", "", file, line, HEX_WIDTH));
458 if more {
459 try!(write!(w, " <... and possibly more>"));
460 }
461 w.write_all(&['\n' as u8])
462}
463
1a4d82fc
JJ
464/// Unwind library interface used for backtraces
465///
466/// Note that dead code is allowed as here are just bindings
467/// iOS doesn't use all of them it but adding more
468/// platform-specific configs pollutes the code too much
469#[allow(non_camel_case_types)]
470#[allow(non_snake_case)]
471#[allow(dead_code)]
472mod uw {
473 pub use self::_Unwind_Reason_Code::*;
474
475 use libc;
476
477 #[repr(C)]
478 pub enum _Unwind_Reason_Code {
479 _URC_NO_REASON = 0,
480 _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
481 _URC_FATAL_PHASE2_ERROR = 2,
482 _URC_FATAL_PHASE1_ERROR = 3,
483 _URC_NORMAL_STOP = 4,
484 _URC_END_OF_STACK = 5,
485 _URC_HANDLER_FOUND = 6,
486 _URC_INSTALL_CONTEXT = 7,
487 _URC_CONTINUE_UNWIND = 8,
488 _URC_FAILURE = 9, // used only by ARM EABI
489 }
490
491 pub enum _Unwind_Context {}
492
493 pub type _Unwind_Trace_Fn =
494 extern fn(ctx: *mut _Unwind_Context,
495 arg: *mut libc::c_void) -> _Unwind_Reason_Code;
496
497 extern {
498 // No native _Unwind_Backtrace on iOS
499 #[cfg(not(all(target_os = "ios", target_arch = "arm")))]
500 pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn,
501 trace_argument: *mut libc::c_void)
502 -> _Unwind_Reason_Code;
503
c34b1796 504 // available since GCC 4.2.0, should be fine for our purpose
85aaf69f 505 #[cfg(all(not(all(target_os = "android", target_arch = "arm")),
1a4d82fc 506 not(all(target_os = "linux", target_arch = "arm"))))]
c34b1796
AL
507 pub fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context,
508 ip_before_insn: *mut libc::c_int)
509 -> libc::uintptr_t;
1a4d82fc
JJ
510
511 #[cfg(all(not(target_os = "android"),
512 not(all(target_os = "linux", target_arch = "arm"))))]
513 pub fn _Unwind_FindEnclosingFunction(pc: *mut libc::c_void)
514 -> *mut libc::c_void;
515 }
516
517 // On android, the function _Unwind_GetIP is a macro, and this is the
518 // expansion of the macro. This is all copy/pasted directly from the
519 // header file with the definition of _Unwind_GetIP.
85aaf69f 520 #[cfg(any(all(target_os = "android", target_arch = "arm"),
1a4d82fc
JJ
521 all(target_os = "linux", target_arch = "arm")))]
522 pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> libc::uintptr_t {
523 #[repr(C)]
524 enum _Unwind_VRS_Result {
525 _UVRSR_OK = 0,
526 _UVRSR_NOT_IMPLEMENTED = 1,
527 _UVRSR_FAILED = 2,
528 }
529 #[repr(C)]
530 enum _Unwind_VRS_RegClass {
531 _UVRSC_CORE = 0,
532 _UVRSC_VFP = 1,
533 _UVRSC_FPA = 2,
534 _UVRSC_WMMXD = 3,
535 _UVRSC_WMMXC = 4,
536 }
537 #[repr(C)]
538 enum _Unwind_VRS_DataRepresentation {
539 _UVRSD_UINT32 = 0,
540 _UVRSD_VFPX = 1,
541 _UVRSD_FPAX = 2,
542 _UVRSD_UINT64 = 3,
543 _UVRSD_FLOAT = 4,
544 _UVRSD_DOUBLE = 5,
545 }
546
547 type _Unwind_Word = libc::c_uint;
548 extern {
549 fn _Unwind_VRS_Get(ctx: *mut _Unwind_Context,
550 klass: _Unwind_VRS_RegClass,
551 word: _Unwind_Word,
552 repr: _Unwind_VRS_DataRepresentation,
553 data: *mut libc::c_void)
554 -> _Unwind_VRS_Result;
555 }
556
557 let mut val: _Unwind_Word = 0;
558 let ptr = &mut val as *mut _Unwind_Word;
559 let _ = _Unwind_VRS_Get(ctx, _Unwind_VRS_RegClass::_UVRSC_CORE, 15,
560 _Unwind_VRS_DataRepresentation::_UVRSD_UINT32,
561 ptr as *mut libc::c_void);
562 (val & !1) as libc::uintptr_t
563 }
564
c34b1796
AL
565 // This function doesn't exist on Android or ARM/Linux, so make it same
566 // to _Unwind_GetIP
567 #[cfg(any(all(target_os = "android", target_arch = "arm"),
568 all(target_os = "linux", target_arch = "arm")))]
569 pub unsafe fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context,
570 ip_before_insn: *mut libc::c_int)
571 -> libc::uintptr_t
572 {
573 *ip_before_insn = 0;
574 _Unwind_GetIP(ctx)
575 }
576
1a4d82fc
JJ
577 // This function also doesn't exist on Android or ARM/Linux, so make it
578 // a no-op
579 #[cfg(any(target_os = "android",
580 all(target_os = "linux", target_arch = "arm")))]
581 pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut libc::c_void)
582 -> *mut libc::c_void
583 {
584 pc
585 }
586}