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