]> git.lizzy.rs Git - rust.git/blob - src/libstd/rt/backtrace.rs
0103fe670e76f73188d03be5598e6943fa1b0db1
[rust.git] / src / libstd / rt / backtrace.rs
1 // Copyright 2014 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 //! Simple backtrace functionality (to print on panic)
12
13 #![allow(non_camel_case_types)]
14
15 use io::{IoResult, Writer};
16 use iter::{Iterator, IteratorExt};
17 use option::{Some, None};
18 use os;
19 use result::{Ok, Err};
20 use str::{StrPrelude, from_str};
21 use sync::atomic;
22 use unicode::char::UnicodeChar;
23
24 pub use self::imp::write;
25
26 // For now logging is turned off by default, and this function checks to see
27 // whether the magical environment variable is present to see if it's turned on.
28 pub fn log_enabled() -> bool {
29     static ENABLED: atomic::AtomicInt = atomic::INIT_ATOMIC_INT;
30     match ENABLED.load(atomic::SeqCst) {
31         1 => return false,
32         2 => return true,
33         _ => {}
34     }
35
36     let val = match os::getenv("RUST_BACKTRACE") {
37         Some(..) => 2,
38         None => 1,
39     };
40     ENABLED.store(val, atomic::SeqCst);
41     val == 2
42 }
43
44 #[cfg(target_word_size = "64")] const HEX_WIDTH: uint = 18;
45 #[cfg(target_word_size = "32")] const HEX_WIDTH: uint = 10;
46
47 // All rust symbols are in theory lists of "::"-separated identifiers. Some
48 // assemblers, however, can't handle these characters in symbol names. To get
49 // around this, we use C++-style mangling. The mangling method is:
50 //
51 // 1. Prefix the symbol with "_ZN"
52 // 2. For each element of the path, emit the length plus the element
53 // 3. End the path with "E"
54 //
55 // For example, "_ZN4testE" => "test" and "_ZN3foo3bar" => "foo::bar".
56 //
57 // We're the ones printing our backtraces, so we can't rely on anything else to
58 // demangle our symbols. It's *much* nicer to look at demangled symbols, so
59 // this function is implemented to give us nice pretty output.
60 //
61 // Note that this demangler isn't quite as fancy as it could be. We have lots
62 // of other information in our symbols like hashes, version, type information,
63 // etc. Additionally, this doesn't handle glue symbols at all.
64 fn demangle(writer: &mut Writer, s: &str) -> IoResult<()> {
65     // First validate the symbol. If it doesn't look like anything we're
66     // expecting, we just print it literally. Note that we must handle non-rust
67     // symbols because we could have any function in the backtrace.
68     let mut valid = true;
69     if s.len() > 4 && s.starts_with("_ZN") && s.ends_with("E") {
70         let mut chars = s.slice(3, s.len() - 1).chars();
71         while valid {
72             let mut i = 0;
73             for c in chars {
74                 if c.is_numeric() {
75                     i = i * 10 + c as uint - '0' as uint;
76                 } else {
77                     break
78                 }
79             }
80             if i == 0 {
81                 valid = chars.next().is_none();
82                 break
83             } else if chars.by_ref().take(i - 1).count() != i - 1 {
84                 valid = false;
85             }
86         }
87     } else {
88         valid = false;
89     }
90
91     // Alright, let's do this.
92     if !valid {
93         try!(writer.write_str(s));
94     } else {
95         let mut s = s.slice_from(3);
96         let mut first = true;
97         while s.len() > 1 {
98             if !first {
99                 try!(writer.write_str("::"));
100             } else {
101                 first = false;
102             }
103             let mut rest = s;
104             while rest.char_at(0).is_numeric() {
105                 rest = rest.slice_from(1);
106             }
107             let i: uint = from_str(s.slice_to(s.len() - rest.len())).unwrap();
108             s = rest.slice_from(i);
109             rest = rest.slice_to(i);
110             while rest.len() > 0 {
111                 if rest.starts_with("$") {
112                     macro_rules! demangle(
113                         ($($pat:expr => $demangled:expr),*) => ({
114                             $(if rest.starts_with($pat) {
115                                 try!(writer.write_str($demangled));
116                                 rest = rest.slice_from($pat.len());
117                               } else)*
118                             {
119                                 try!(writer.write_str(rest));
120                                 break;
121                             }
122
123                         })
124                     )
125                     // see src/librustc/back/link.rs for these mappings
126                     demangle! (
127                         "$SP$" => "@",
128                         "$UP$" => "Box",
129                         "$RP$" => "*",
130                         "$BP$" => "&",
131                         "$LT$" => "<",
132                         "$GT$" => ">",
133                         "$LP$" => "(",
134                         "$RP$" => ")",
135                         "$C$"  => ",",
136
137                         // in theory we can demangle any Unicode code point, but
138                         // for simplicity we just catch the common ones.
139                         "$x20" => " ",
140                         "$x27" => "'",
141                         "$x5b" => "[",
142                         "$x5d" => "]"
143                     )
144                 } else {
145                     let idx = match rest.find('$') {
146                         None => rest.len(),
147                         Some(i) => i,
148                     };
149                     try!(writer.write_str(rest.slice_to(idx)));
150                     rest = rest.slice_from(idx);
151                 }
152             }
153         }
154     }
155
156     Ok(())
157 }
158
159 /// Backtrace support built on libgcc with some extra OS-specific support
160 ///
161 /// Some methods of getting a backtrace:
162 ///
163 /// * The backtrace() functions on unix. It turns out this doesn't work very
164 ///   well for green threads on OSX, and the address to symbol portion of it
165 ///   suffers problems that are described below.
166 ///
167 /// * Using libunwind. This is more difficult than it sounds because libunwind
168 ///   isn't installed everywhere by default. It's also a bit of a hefty library,
169 ///   so possibly not the best option. When testing, libunwind was excellent at
170 ///   getting both accurate backtraces and accurate symbols across platforms.
171 ///   This route was not chosen in favor of the next option, however.
172 ///
173 /// * We're already using libgcc_s for exceptions in rust (triggering task
174 ///   unwinding and running destructors on the stack), and it turns out that it
175 ///   conveniently comes with a function that also gives us a backtrace. All of
176 ///   these functions look like _Unwind_*, but it's not quite the full
177 ///   repertoire of the libunwind API. Due to it already being in use, this was
178 ///   the chosen route of getting a backtrace.
179 ///
180 /// After choosing libgcc_s for backtraces, the sad part is that it will only
181 /// give us a stack trace of instruction pointers. Thankfully these instruction
182 /// pointers are accurate (they work for green and native threads), but it's
183 /// then up to us again to figure out how to translate these addresses to
184 /// symbols. As with before, we have a few options. Before, that, a little bit
185 /// of an interlude about symbols. This is my very limited knowledge about
186 /// symbol tables, and this information is likely slightly wrong, but the
187 /// general idea should be correct.
188 ///
189 /// When talking about symbols, it's helpful to know a few things about where
190 /// symbols are located. Some symbols are located in the dynamic symbol table
191 /// of the executable which in theory means that they're available for dynamic
192 /// linking and lookup. Other symbols end up only in the local symbol table of
193 /// the file. This loosely corresponds to pub and priv functions in Rust.
194 ///
195 /// Armed with this knowledge, we know that our solution for address to symbol
196 /// translation will need to consult both the local and dynamic symbol tables.
197 /// With that in mind, here's our options of translating an address to
198 /// a symbol.
199 ///
200 /// * Use dladdr(). The original backtrace()-based idea actually uses dladdr()
201 ///   behind the scenes to translate, and this is why backtrace() was not used.
202 ///   Conveniently, this method works fantastically on OSX. It appears dladdr()
203 ///   uses magic to consult the local symbol table, or we're putting everything
204 ///   in the dynamic symbol table anyway. Regardless, for OSX, this is the
205 ///   method used for translation. It's provided by the system and easy to do.o
206 ///
207 ///   Sadly, all other systems have a dladdr() implementation that does not
208 ///   consult the local symbol table. This means that most functions are blank
209 ///   because they don't have symbols. This means that we need another solution.
210 ///
211 /// * Use unw_get_proc_name(). This is part of the libunwind api (not the
212 ///   libgcc_s version of the libunwind api), but involves taking a dependency
213 ///   to libunwind. We may pursue this route in the future if we bundle
214 ///   libunwind, but libunwind was unwieldy enough that it was not chosen at
215 ///   this time to provide this functionality.
216 ///
217 /// * Shell out to a utility like `readelf`. Crazy though it may sound, it's a
218 ///   semi-reasonable solution. The stdlib already knows how to spawn processes,
219 ///   so in theory it could invoke readelf, parse the output, and consult the
220 ///   local/dynamic symbol tables from there. This ended up not getting chosen
221 ///   due to the craziness of the idea plus the advent of the next option.
222 ///
223 /// * Use `libbacktrace`. It turns out that this is a small library bundled in
224 ///   the gcc repository which provides backtrace and symbol translation
225 ///   functionality. All we really need from it is the backtrace functionality,
226 ///   and we only really need this on everything that's not OSX, so this is the
227 ///   chosen route for now.
228 ///
229 /// In summary, the current situation uses libgcc_s to get a trace of stack
230 /// pointers, and we use dladdr() or libbacktrace to translate these addresses
231 /// to symbols. This is a bit of a hokey implementation as-is, but it works for
232 /// all unix platforms we support right now, so it at least gets the job done.
233 #[cfg(unix)]
234 mod imp {
235     use c_str::CString;
236     use io::{IoResult, Writer};
237     use libc;
238     use mem;
239     use option::{Some, None, Option};
240     use result::{Ok, Err};
241     use rustrt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
242
243     /// As always - iOS on arm uses SjLj exceptions and
244     /// _Unwind_Backtrace is even not available there. Still,
245     /// backtraces could be extracted using a backtrace function,
246     /// which thanks god is public
247     ///
248     /// As mentioned in a huge comment block above, backtrace doesn't
249     /// play well with green threads, so while it is extremely nice
250     /// and simple to use it should be used only on iOS devices as the
251     /// only viable option.
252     #[cfg(all(target_os = "ios", target_arch = "arm"))]
253     #[inline(never)]
254     pub fn write(w: &mut Writer) -> IoResult<()> {
255         use iter::{IteratorExt, range};
256         use result;
257         use slice::{SlicePrelude};
258
259         extern {
260             fn backtrace(buf: *mut *mut libc::c_void,
261                          sz: libc::c_int) -> libc::c_int;
262         }
263
264         // while it doesn't requires lock for work as everything is
265         // local, it still displays much nicer backtraces when a
266         // couple of tasks panic simultaneously
267         static LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
268         let _g = unsafe { LOCK.lock() };
269
270         try!(writeln!(w, "stack backtrace:"));
271         // 100 lines should be enough
272         const SIZE: uint = 100;
273         let mut buf: [*mut libc::c_void, ..SIZE] = unsafe {mem::zeroed()};
274         let cnt = unsafe { backtrace(buf.as_mut_ptr(), SIZE as libc::c_int) as uint};
275
276         // skipping the first one as it is write itself
277         let iter = range(1, cnt).map(|i| {
278             print(w, i as int, buf[i])
279         });
280         result::fold(iter, (), |_, _| ())
281     }
282
283     #[cfg(not(all(target_os = "ios", target_arch = "arm")))]
284     #[inline(never)] // if we know this is a function call, we can skip it when
285                      // tracing
286     pub fn write(w: &mut Writer) -> IoResult<()> {
287         use io::IoError;
288
289         struct Context<'a> {
290             idx: int,
291             writer: &'a mut (Writer+'a),
292             last_error: Option<IoError>,
293         }
294
295         // When using libbacktrace, we use some necessary global state, so we
296         // need to prevent more than one thread from entering this block. This
297         // is semi-reasonable in terms of printing anyway, and we know that all
298         // I/O done here is blocking I/O, not green I/O, so we don't have to
299         // worry about this being a native vs green mutex.
300         static LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
301         let _g = unsafe { LOCK.lock() };
302
303         try!(writeln!(w, "stack backtrace:"));
304
305         let mut cx = Context { writer: w, last_error: None, idx: 0 };
306         return match unsafe {
307             uw::_Unwind_Backtrace(trace_fn,
308                                   &mut cx as *mut Context as *mut libc::c_void)
309         } {
310             uw::_URC_NO_REASON => {
311                 match cx.last_error {
312                     Some(err) => Err(err),
313                     None => Ok(())
314                 }
315             }
316             _ => Ok(()),
317         };
318
319         extern fn trace_fn(ctx: *mut uw::_Unwind_Context,
320                            arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code {
321             let cx: &mut Context = unsafe { mem::transmute(arg) };
322             let ip = unsafe { uw::_Unwind_GetIP(ctx) as *mut libc::c_void };
323             // dladdr() on osx gets whiny when we use FindEnclosingFunction, and
324             // it appears to work fine without it, so we only use
325             // FindEnclosingFunction on non-osx platforms. In doing so, we get a
326             // slightly more accurate stack trace in the process.
327             //
328             // This is often because panic involves the last instruction of a
329             // function being "call std::rt::begin_unwind", with no ret
330             // instructions after it. This means that the return instruction
331             // pointer points *outside* of the calling function, and by
332             // unwinding it we go back to the original function.
333             let ip = if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
334                 ip
335             } else {
336                 unsafe { uw::_Unwind_FindEnclosingFunction(ip) }
337             };
338
339             // Don't print out the first few frames (they're not user frames)
340             cx.idx += 1;
341             if cx.idx <= 0 { return uw::_URC_NO_REASON }
342             // Don't print ginormous backtraces
343             if cx.idx > 100 {
344                 match write!(cx.writer, " ... <frames omitted>\n") {
345                     Ok(()) => {}
346                     Err(e) => { cx.last_error = Some(e); }
347                 }
348                 return uw::_URC_FAILURE
349             }
350
351             // Once we hit an error, stop trying to print more frames
352             if cx.last_error.is_some() { return uw::_URC_FAILURE }
353
354             match print(cx.writer, cx.idx, ip) {
355                 Ok(()) => {}
356                 Err(e) => { cx.last_error = Some(e); }
357             }
358
359             // keep going
360             return uw::_URC_NO_REASON
361         }
362     }
363
364     #[cfg(any(target_os = "macos", target_os = "ios"))]
365     fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> {
366         use intrinsics;
367         #[repr(C)]
368         struct Dl_info {
369             dli_fname: *const libc::c_char,
370             dli_fbase: *mut libc::c_void,
371             dli_sname: *const libc::c_char,
372             dli_saddr: *mut libc::c_void,
373         }
374         extern {
375             fn dladdr(addr: *const libc::c_void,
376                       info: *mut Dl_info) -> libc::c_int;
377         }
378
379         let mut info: Dl_info = unsafe { intrinsics::init() };
380         if unsafe { dladdr(addr as *const libc::c_void, &mut info) == 0 } {
381             output(w, idx,addr, None)
382         } else {
383             output(w, idx, addr, Some(unsafe {
384                 CString::new(info.dli_sname, false)
385             }))
386         }
387     }
388
389     #[cfg(not(any(target_os = "macos", target_os = "ios")))]
390     fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> {
391         use iter::IteratorExt;
392         use os;
393         use path::GenericPath;
394         use ptr::RawPtr;
395         use ptr;
396         use slice::{SlicePrelude};
397
398         ////////////////////////////////////////////////////////////////////////
399         // libbacktrace.h API
400         ////////////////////////////////////////////////////////////////////////
401         type backtrace_syminfo_callback =
402             extern "C" fn(data: *mut libc::c_void,
403                           pc: libc::uintptr_t,
404                           symname: *const libc::c_char,
405                           symval: libc::uintptr_t,
406                           symsize: libc::uintptr_t);
407         type backtrace_error_callback =
408             extern "C" fn(data: *mut libc::c_void,
409                           msg: *const libc::c_char,
410                           errnum: libc::c_int);
411         enum backtrace_state {}
412         #[link(name = "backtrace", kind = "static")]
413         #[cfg(not(test))]
414         extern {}
415
416         extern {
417             fn backtrace_create_state(filename: *const libc::c_char,
418                                       threaded: libc::c_int,
419                                       error: backtrace_error_callback,
420                                       data: *mut libc::c_void)
421                                             -> *mut backtrace_state;
422             fn backtrace_syminfo(state: *mut backtrace_state,
423                                  addr: libc::uintptr_t,
424                                  cb: backtrace_syminfo_callback,
425                                  error: backtrace_error_callback,
426                                  data: *mut libc::c_void) -> libc::c_int;
427         }
428
429         ////////////////////////////////////////////////////////////////////////
430         // helper callbacks
431         ////////////////////////////////////////////////////////////////////////
432
433         extern fn error_cb(_data: *mut libc::c_void, _msg: *const libc::c_char,
434                            _errnum: libc::c_int) {
435             // do nothing for now
436         }
437         extern fn syminfo_cb(data: *mut libc::c_void,
438                              _pc: libc::uintptr_t,
439                              symname: *const libc::c_char,
440                              _symval: libc::uintptr_t,
441                              _symsize: libc::uintptr_t) {
442             let slot = data as *mut *const libc::c_char;
443             unsafe { *slot = symname; }
444         }
445
446         // The libbacktrace API supports creating a state, but it does not
447         // support destroying a state. I personally take this to mean that a
448         // state is meant to be created and then live forever.
449         //
450         // I would love to register an at_exit() handler which cleans up this
451         // state, but libbacktrace provides no way to do so.
452         //
453         // With these constraints, this function has a statically cached state
454         // that is calculated the first time this is requested. Remember that
455         // backtracing all happens serially (one global lock).
456         //
457         // An additionally oddity in this function is that we initialize the
458         // filename via self_exe_name() to pass to libbacktrace. It turns out
459         // that on Linux libbacktrace seamlessly gets the filename of the
460         // current executable, but this fails on freebsd. by always providing
461         // it, we make sure that libbacktrace never has a reason to not look up
462         // the symbols. The libbacktrace API also states that the filename must
463         // be in "permanent memory", so we copy it to a static and then use the
464         // static as the pointer.
465         //
466         // FIXME: We also call self_exe_name() on DragonFly BSD. I haven't
467         //        tested if this is required or not.
468         unsafe fn init_state() -> *mut backtrace_state {
469             static mut STATE: *mut backtrace_state = 0 as *mut backtrace_state;
470             static mut LAST_FILENAME: [libc::c_char, ..256] = [0, ..256];
471             if !STATE.is_null() { return STATE }
472             let selfname = if cfg!(target_os = "freebsd") ||
473                               cfg!(target_os = "dragonfly") {
474                 os::self_exe_name()
475             } else {
476                 None
477             };
478             let filename = match selfname {
479                 Some(path) => {
480                     let bytes = path.as_vec();
481                     if bytes.len() < LAST_FILENAME.len() {
482                         let i = bytes.iter();
483                         for (slot, val) in LAST_FILENAME.iter_mut().zip(i) {
484                             *slot = *val as libc::c_char;
485                         }
486                         LAST_FILENAME.as_ptr()
487                     } else {
488                         ptr::null()
489                     }
490                 }
491                 None => ptr::null(),
492             };
493             STATE = backtrace_create_state(filename, 0, error_cb,
494                                            ptr::null_mut());
495             return STATE
496         }
497
498         ////////////////////////////////////////////////////////////////////////
499         // translation
500         ////////////////////////////////////////////////////////////////////////
501
502         // backtrace errors are currently swept under the rug, only I/O
503         // errors are reported
504         let state = unsafe { init_state() };
505         if state.is_null() {
506             return output(w, idx, addr, None)
507         }
508         let mut data = 0 as *const libc::c_char;
509         let data_addr = &mut data as *mut *const libc::c_char;
510         let ret = unsafe {
511             backtrace_syminfo(state, addr as libc::uintptr_t,
512                               syminfo_cb, error_cb,
513                               data_addr as *mut libc::c_void)
514         };
515         if ret == 0 || data.is_null() {
516             output(w, idx, addr, None)
517         } else {
518             output(w, idx, addr, Some(unsafe { CString::new(data, false) }))
519         }
520     }
521
522     // Finally, after all that work above, we can emit a symbol.
523     fn output(w: &mut Writer, idx: int, addr: *mut libc::c_void,
524               s: Option<CString>) -> IoResult<()> {
525         try!(write!(w, "  {:2}: {:2$} - ", idx, addr, super::HEX_WIDTH));
526         match s.as_ref().and_then(|c| c.as_str()) {
527             Some(string) => try!(super::demangle(w, string)),
528             None => try!(write!(w, "<unknown>")),
529         }
530         w.write(&['\n' as u8])
531     }
532
533     /// Unwind library interface used for backtraces
534     ///
535     /// Note that the native libraries come from librustrt, not this
536     /// module.
537     /// Note that dead code is allowed as here are just bindings
538     /// iOS doesn't use all of them it but adding more
539     /// platform-specific configs pollutes the code too much
540     #[allow(non_camel_case_types)]
541     #[allow(non_snake_case)]
542     #[allow(dead_code)]
543     mod uw {
544         pub use self::_Unwind_Reason_Code::*;
545
546         use libc;
547
548         #[repr(C)]
549         pub enum _Unwind_Reason_Code {
550             _URC_NO_REASON = 0,
551             _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
552             _URC_FATAL_PHASE2_ERROR = 2,
553             _URC_FATAL_PHASE1_ERROR = 3,
554             _URC_NORMAL_STOP = 4,
555             _URC_END_OF_STACK = 5,
556             _URC_HANDLER_FOUND = 6,
557             _URC_INSTALL_CONTEXT = 7,
558             _URC_CONTINUE_UNWIND = 8,
559             _URC_FAILURE = 9, // used only by ARM EABI
560         }
561
562         pub enum _Unwind_Context {}
563
564         pub type _Unwind_Trace_Fn =
565                 extern fn(ctx: *mut _Unwind_Context,
566                           arg: *mut libc::c_void) -> _Unwind_Reason_Code;
567
568         extern {
569             // No native _Unwind_Backtrace on iOS
570             #[cfg(not(all(target_os = "ios", target_arch = "arm")))]
571             pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn,
572                                      trace_argument: *mut libc::c_void)
573                         -> _Unwind_Reason_Code;
574
575             #[cfg(all(not(target_os = "android"),
576                       not(all(target_os = "linux", target_arch = "arm"))))]
577             pub fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> libc::uintptr_t;
578
579             #[cfg(all(not(target_os = "android"),
580                       not(all(target_os = "linux", target_arch = "arm"))))]
581             pub fn _Unwind_FindEnclosingFunction(pc: *mut libc::c_void)
582                 -> *mut libc::c_void;
583         }
584
585         // On android, the function _Unwind_GetIP is a macro, and this is the
586         // expansion of the macro. This is all copy/pasted directly from the
587         // header file with the definition of _Unwind_GetIP.
588         #[cfg(any(target_os = "android",
589                   all(target_os = "linux", target_arch = "arm")))]
590         pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> libc::uintptr_t {
591             #[repr(C)]
592             enum _Unwind_VRS_Result {
593                 _UVRSR_OK = 0,
594                 _UVRSR_NOT_IMPLEMENTED = 1,
595                 _UVRSR_FAILED = 2,
596             }
597             #[repr(C)]
598             enum _Unwind_VRS_RegClass {
599                 _UVRSC_CORE = 0,
600                 _UVRSC_VFP = 1,
601                 _UVRSC_FPA = 2,
602                 _UVRSC_WMMXD = 3,
603                 _UVRSC_WMMXC = 4,
604             }
605             #[repr(C)]
606             enum _Unwind_VRS_DataRepresentation {
607                 _UVRSD_UINT32 = 0,
608                 _UVRSD_VFPX = 1,
609                 _UVRSD_FPAX = 2,
610                 _UVRSD_UINT64 = 3,
611                 _UVRSD_FLOAT = 4,
612                 _UVRSD_DOUBLE = 5,
613             }
614
615             type _Unwind_Word = libc::c_uint;
616             extern {
617                 fn _Unwind_VRS_Get(ctx: *mut _Unwind_Context,
618                                    klass: _Unwind_VRS_RegClass,
619                                    word: _Unwind_Word,
620                                    repr: _Unwind_VRS_DataRepresentation,
621                                    data: *mut libc::c_void)
622                     -> _Unwind_VRS_Result;
623             }
624
625             let mut val: _Unwind_Word = 0;
626             let ptr = &mut val as *mut _Unwind_Word;
627             let _ = _Unwind_VRS_Get(ctx, _Unwind_VRS_RegClass::_UVRSC_CORE, 15,
628                                     _Unwind_VRS_DataRepresentation::_UVRSD_UINT32,
629                                     ptr as *mut libc::c_void);
630             (val & !1) as libc::uintptr_t
631         }
632
633         // This function also doesn't exist on Android or ARM/Linux, so make it
634         // a no-op
635         #[cfg(any(target_os = "android",
636                   all(target_os = "linux", target_arch = "arm")))]
637         pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut libc::c_void)
638             -> *mut libc::c_void
639         {
640             pc
641         }
642     }
643 }
644
645 /// As always, windows has something very different than unix, we mainly want
646 /// to avoid having to depend too much on libunwind for windows.
647 ///
648 /// If you google around, you'll find a fair bit of references to built-in
649 /// functions to get backtraces on windows. It turns out that most of these are
650 /// in an external library called dbghelp. I was unable to find this library
651 /// via `-ldbghelp`, but it is apparently normal to do the `dlopen` equivalent
652 /// of it.
653 ///
654 /// You'll also find that there's a function called CaptureStackBackTrace
655 /// mentioned frequently (which is also easy to use), but sadly I didn't have a
656 /// copy of that function in my mingw install (maybe it was broken?). Instead,
657 /// this takes the route of using StackWalk64 in order to walk the stack.
658 #[cfg(windows)]
659 #[allow(dead_code, non_snake_case)]
660 mod imp {
661     use c_str::CString;
662     use intrinsics;
663     use io::{IoResult, Writer};
664     use libc;
665     use mem;
666     use ops::Drop;
667     use option::{Some, None};
668     use path::Path;
669     use result::{Ok, Err};
670     use rustrt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
671     use slice::SlicePrelude;
672     use str::StrPrelude;
673     use dynamic_lib::DynamicLibrary;
674
675     #[allow(non_snake_case)]
676     extern "system" {
677         fn GetCurrentProcess() -> libc::HANDLE;
678         fn GetCurrentThread() -> libc::HANDLE;
679         fn RtlCaptureContext(ctx: *mut arch::CONTEXT);
680     }
681
682     type SymFromAddrFn =
683         extern "system" fn(libc::HANDLE, u64, *mut u64,
684                            *mut SYMBOL_INFO) -> libc::BOOL;
685     type SymInitializeFn =
686         extern "system" fn(libc::HANDLE, *mut libc::c_void,
687                            libc::BOOL) -> libc::BOOL;
688     type SymCleanupFn =
689         extern "system" fn(libc::HANDLE) -> libc::BOOL;
690
691     type StackWalk64Fn =
692         extern "system" fn(libc::DWORD, libc::HANDLE, libc::HANDLE,
693                            *mut STACKFRAME64, *mut arch::CONTEXT,
694                            *mut libc::c_void, *mut libc::c_void,
695                            *mut libc::c_void, *mut libc::c_void) -> libc::BOOL;
696
697     const MAX_SYM_NAME: uint = 2000;
698     const IMAGE_FILE_MACHINE_I386: libc::DWORD = 0x014c;
699     const IMAGE_FILE_MACHINE_IA64: libc::DWORD = 0x0200;
700     const IMAGE_FILE_MACHINE_AMD64: libc::DWORD = 0x8664;
701
702     #[repr(C)]
703     struct SYMBOL_INFO {
704         SizeOfStruct: libc::c_ulong,
705         TypeIndex: libc::c_ulong,
706         Reserved: [u64, ..2],
707         Index: libc::c_ulong,
708         Size: libc::c_ulong,
709         ModBase: u64,
710         Flags: libc::c_ulong,
711         Value: u64,
712         Address: u64,
713         Register: libc::c_ulong,
714         Scope: libc::c_ulong,
715         Tag: libc::c_ulong,
716         NameLen: libc::c_ulong,
717         MaxNameLen: libc::c_ulong,
718         // note that windows has this as 1, but it basically just means that
719         // the name is inline at the end of the struct. For us, we just bump
720         // the struct size up to MAX_SYM_NAME.
721         Name: [libc::c_char, ..MAX_SYM_NAME],
722     }
723
724
725     #[repr(C)]
726     enum ADDRESS_MODE {
727         AddrMode1616,
728         AddrMode1632,
729         AddrModeReal,
730         AddrModeFlat,
731     }
732
733     struct ADDRESS64 {
734         Offset: u64,
735         Segment: u16,
736         Mode: ADDRESS_MODE,
737     }
738
739     struct STACKFRAME64 {
740         AddrPC: ADDRESS64,
741         AddrReturn: ADDRESS64,
742         AddrFrame: ADDRESS64,
743         AddrStack: ADDRESS64,
744         AddrBStore: ADDRESS64,
745         FuncTableEntry: *mut libc::c_void,
746         Params: [u64, ..4],
747         Far: libc::BOOL,
748         Virtual: libc::BOOL,
749         Reserved: [u64, ..3],
750         KdHelp: KDHELP64,
751     }
752
753     struct KDHELP64 {
754         Thread: u64,
755         ThCallbackStack: libc::DWORD,
756         ThCallbackBStore: libc::DWORD,
757         NextCallback: libc::DWORD,
758         FramePointer: libc::DWORD,
759         KiCallUserMode: u64,
760         KeUserCallbackDispatcher: u64,
761         SystemRangeStart: u64,
762         KiUserExceptionDispatcher: u64,
763         StackBase: u64,
764         StackLimit: u64,
765         Reserved: [u64, ..5],
766     }
767
768     #[cfg(target_arch = "x86")]
769     mod arch {
770         use libc;
771
772         const MAXIMUM_SUPPORTED_EXTENSION: uint = 512;
773
774         #[repr(C)]
775         pub struct CONTEXT {
776             ContextFlags: libc::DWORD,
777             Dr0: libc::DWORD,
778             Dr1: libc::DWORD,
779             Dr2: libc::DWORD,
780             Dr3: libc::DWORD,
781             Dr6: libc::DWORD,
782             Dr7: libc::DWORD,
783             FloatSave: FLOATING_SAVE_AREA,
784             SegGs: libc::DWORD,
785             SegFs: libc::DWORD,
786             SegEs: libc::DWORD,
787             SegDs: libc::DWORD,
788             Edi: libc::DWORD,
789             Esi: libc::DWORD,
790             Ebx: libc::DWORD,
791             Edx: libc::DWORD,
792             Ecx: libc::DWORD,
793             Eax: libc::DWORD,
794             Ebp: libc::DWORD,
795             Eip: libc::DWORD,
796             SegCs: libc::DWORD,
797             EFlags: libc::DWORD,
798             Esp: libc::DWORD,
799             SegSs: libc::DWORD,
800             ExtendedRegisters: [u8, ..MAXIMUM_SUPPORTED_EXTENSION],
801         }
802
803         #[repr(C)]
804         pub struct FLOATING_SAVE_AREA {
805             ControlWord: libc::DWORD,
806             StatusWord: libc::DWORD,
807             TagWord: libc::DWORD,
808             ErrorOffset: libc::DWORD,
809             ErrorSelector: libc::DWORD,
810             DataOffset: libc::DWORD,
811             DataSelector: libc::DWORD,
812             RegisterArea: [u8, ..80],
813             Cr0NpxState: libc::DWORD,
814         }
815
816         pub fn init_frame(frame: &mut super::STACKFRAME64,
817                           ctx: &CONTEXT) -> libc::DWORD {
818             frame.AddrPC.Offset = ctx.Eip as u64;
819             frame.AddrPC.Mode = super::ADDRESS_MODE::AddrModeFlat;
820             frame.AddrStack.Offset = ctx.Esp as u64;
821             frame.AddrStack.Mode = super::ADDRESS_MODE::AddrModeFlat;
822             frame.AddrFrame.Offset = ctx.Ebp as u64;
823             frame.AddrFrame.Mode = super::ADDRESS_MODE::AddrModeFlat;
824             super::IMAGE_FILE_MACHINE_I386
825         }
826     }
827
828     #[cfg(target_arch = "x86_64")]
829     mod arch {
830         use libc::{c_longlong, c_ulonglong};
831         use libc::types::os::arch::extra::{WORD, DWORD, DWORDLONG};
832         use simd;
833
834         #[repr(C)]
835         pub struct CONTEXT {
836             _align_hack: [simd::u64x2, ..0], // FIXME align on 16-byte
837             P1Home: DWORDLONG,
838             P2Home: DWORDLONG,
839             P3Home: DWORDLONG,
840             P4Home: DWORDLONG,
841             P5Home: DWORDLONG,
842             P6Home: DWORDLONG,
843
844             ContextFlags: DWORD,
845             MxCsr: DWORD,
846
847             SegCs: WORD,
848             SegDs: WORD,
849             SegEs: WORD,
850             SegFs: WORD,
851             SegGs: WORD,
852             SegSs: WORD,
853             EFlags: DWORD,
854
855             Dr0: DWORDLONG,
856             Dr1: DWORDLONG,
857             Dr2: DWORDLONG,
858             Dr3: DWORDLONG,
859             Dr6: DWORDLONG,
860             Dr7: DWORDLONG,
861
862             Rax: DWORDLONG,
863             Rcx: DWORDLONG,
864             Rdx: DWORDLONG,
865             Rbx: DWORDLONG,
866             Rsp: DWORDLONG,
867             Rbp: DWORDLONG,
868             Rsi: DWORDLONG,
869             Rdi: DWORDLONG,
870             R8:  DWORDLONG,
871             R9:  DWORDLONG,
872             R10: DWORDLONG,
873             R11: DWORDLONG,
874             R12: DWORDLONG,
875             R13: DWORDLONG,
876             R14: DWORDLONG,
877             R15: DWORDLONG,
878
879             Rip: DWORDLONG,
880
881             FltSave: FLOATING_SAVE_AREA,
882
883             VectorRegister: [M128A, .. 26],
884             VectorControl: DWORDLONG,
885
886             DebugControl: DWORDLONG,
887             LastBranchToRip: DWORDLONG,
888             LastBranchFromRip: DWORDLONG,
889             LastExceptionToRip: DWORDLONG,
890             LastExceptionFromRip: DWORDLONG,
891         }
892
893         #[repr(C)]
894         pub struct M128A {
895             _align_hack: [simd::u64x2, ..0], // FIXME align on 16-byte
896             Low:  c_ulonglong,
897             High: c_longlong
898         }
899
900         #[repr(C)]
901         pub struct FLOATING_SAVE_AREA {
902             _align_hack: [simd::u64x2, ..0], // FIXME align on 16-byte
903             _Dummy: [u8, ..512] // FIXME: Fill this out
904         }
905
906         pub fn init_frame(frame: &mut super::STACKFRAME64,
907                           ctx: &CONTEXT) -> DWORD {
908             frame.AddrPC.Offset = ctx.Rip as u64;
909             frame.AddrPC.Mode = super::ADDRESS_MODE::AddrModeFlat;
910             frame.AddrStack.Offset = ctx.Rsp as u64;
911             frame.AddrStack.Mode = super::ADDRESS_MODE::AddrModeFlat;
912             frame.AddrFrame.Offset = ctx.Rbp as u64;
913             frame.AddrFrame.Mode = super::ADDRESS_MODE::AddrModeFlat;
914             super::IMAGE_FILE_MACHINE_AMD64
915         }
916     }
917
918     #[repr(C)]
919     struct Cleanup {
920         handle: libc::HANDLE,
921         SymCleanup: SymCleanupFn,
922     }
923
924     impl Drop for Cleanup {
925         fn drop(&mut self) { (self.SymCleanup)(self.handle); }
926     }
927
928     pub fn write(w: &mut Writer) -> IoResult<()> {
929         // According to windows documentation, all dbghelp functions are
930         // single-threaded.
931         static LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
932         let _g = unsafe { LOCK.lock() };
933
934         // Open up dbghelp.dll, we don't link to it explicitly because it can't
935         // always be found. Additionally, it's nice having fewer dependencies.
936         let path = Path::new("dbghelp.dll");
937         let lib = match DynamicLibrary::open(Some(&path)) {
938             Ok(lib) => lib,
939             Err(..) => return Ok(()),
940         };
941
942         macro_rules! sym( ($e:expr, $t:ident) => (unsafe {
943             match lib.symbol($e) {
944                 Ok(f) => mem::transmute::<*mut u8, $t>(f),
945                 Err(..) => return Ok(())
946             }
947         }) )
948
949         // Fetch the symbols necessary from dbghelp.dll
950         let SymFromAddr = sym!("SymFromAddr", SymFromAddrFn);
951         let SymInitialize = sym!("SymInitialize", SymInitializeFn);
952         let SymCleanup = sym!("SymCleanup", SymCleanupFn);
953         let StackWalk64 = sym!("StackWalk64", StackWalk64Fn);
954
955         // Allocate necessary structures for doing the stack walk
956         let process = unsafe { GetCurrentProcess() };
957         let thread = unsafe { GetCurrentThread() };
958         let mut context: arch::CONTEXT = unsafe { intrinsics::init() };
959         unsafe { RtlCaptureContext(&mut context); }
960         let mut frame: STACKFRAME64 = unsafe { intrinsics::init() };
961         let image = arch::init_frame(&mut frame, &context);
962
963         // Initialize this process's symbols
964         let ret = SymInitialize(process, 0 as *mut libc::c_void, libc::TRUE);
965         if ret != libc::TRUE { return Ok(()) }
966         let _c = Cleanup { handle: process, SymCleanup: SymCleanup };
967
968         // And now that we're done with all the setup, do the stack walking!
969         let mut i = 0i;
970         try!(write!(w, "stack backtrace:\n"));
971         while StackWalk64(image, process, thread, &mut frame, &mut context,
972                           0 as *mut libc::c_void,
973                           0 as *mut libc::c_void,
974                           0 as *mut libc::c_void,
975                           0 as *mut libc::c_void) == libc::TRUE{
976             let addr = frame.AddrPC.Offset;
977             if addr == frame.AddrReturn.Offset || addr == 0 ||
978                frame.AddrReturn.Offset == 0 { break }
979
980             i += 1;
981             try!(write!(w, "  {:2}: {:#2$x}", i, addr, super::HEX_WIDTH));
982             let mut info: SYMBOL_INFO = unsafe { intrinsics::init() };
983             info.MaxNameLen = MAX_SYM_NAME as libc::c_ulong;
984             // the struct size in C.  the value is different to
985             // `size_of::<SYMBOL_INFO>() - MAX_SYM_NAME + 1` (== 81)
986             // due to struct alignment.
987             info.SizeOfStruct = 88;
988
989             let mut displacement = 0u64;
990             let ret = SymFromAddr(process, addr as u64, &mut displacement,
991                                   &mut info);
992
993             if ret == libc::TRUE {
994                 try!(write!(w, " - "));
995                 let cstr = unsafe { CString::new(info.Name.as_ptr(), false) };
996                 let bytes = cstr.as_bytes();
997                 match cstr.as_str() {
998                     Some(s) => try!(super::demangle(w, s)),
999                     None => try!(w.write(bytes[..bytes.len()-1])),
1000                 }
1001             }
1002             try!(w.write(&['\n' as u8]));
1003         }
1004
1005         Ok(())
1006     }
1007 }
1008
1009 #[cfg(test)]
1010 mod test {
1011     use prelude::*;
1012     macro_rules! t( ($a:expr, $b:expr) => ({
1013         let mut m = Vec::new();
1014         super::demangle(&mut m, $a).unwrap();
1015         assert_eq!(String::from_utf8(m).unwrap(), $b.to_string());
1016     }) )
1017
1018     #[test]
1019     fn demangle() {
1020         t!("test", "test");
1021         t!("_ZN4testE", "test");
1022         t!("_ZN4test", "_ZN4test");
1023         t!("_ZN4test1a2bcE", "test::a::bc");
1024     }
1025
1026     #[test]
1027     fn demangle_dollars() {
1028         t!("_ZN4$UP$E", "Box");
1029         t!("_ZN8$UP$testE", "Boxtest");
1030         t!("_ZN8$UP$test4foobE", "Boxtest::foob");
1031         t!("_ZN8$x20test4foobE", " test::foob");
1032     }
1033
1034     #[test]
1035     fn demangle_many_dollars() {
1036         t!("_ZN12test$x20test4foobE", "test test::foob");
1037         t!("_ZN12test$UP$test4foobE", "testBoxtest::foob");
1038     }
1039 }