(index<- )        ./libstd/rt/backtrace.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri May  9 13:02:28 2014
   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 char::Char;
  16  use container::Container;
  17  use from_str::from_str;
  18  use io::{IoResult, Writer};
  19  use iter::Iterator;
  20  use option::{Some, None};
  21  use os;
  22  use result::{Ok, Err};
  23  use str::StrSlice;
  24  use sync::atomics;
  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: atomics::AtomicInt = atomics::INIT_ATOMIC_INT;
  32      unsafe {
  33          match ENABLED.load(atomics::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, atomics::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).len() != 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 iuint = 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 cast;
 241      use io::{IoResult, IoError, Writer};
 242      use libc;
 243      use option::{Some, None, Option};
 244      use result::{Ok, Err};
 245      use unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
 246      use uw = rt::libunwind;
 247  
 248      struct Context<'a> {
 249          idx: int,
 250          writer: &'a mut Writer,
 251          last_error: Option<IoError>,
 252      }
 253  
 254      #[inline(never)] // if we know this is a function call, we can skip it when
 255                       // tracing
 256      pub fn write(w: &mut Writer) -> IoResult<()> {
 257          // When using libbacktrace, we use some necessary global state, so we
 258          // need to prevent more than one thread from entering this block. This
 259          // is semi-reasonable in terms of printing anyway, and we know that all
 260          // I/O done here is blocking I/O, not green I/O, so we don't have to
 261          // worry about this being a native vs green mutex.
 262          static mut LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
 263          let _g = unsafe { LOCK.lock() };
 264  
 265          try!(writeln!(w, "stack backtrace:"));
 266  
 267          let mut cx = Context { writer: w, last_error: None, idx: 0 };
 268          return match unsafe {
 269              uw::_Unwind_Backtrace(trace_fn,
 270                                    &mut cx as *mut Context as *libc::c_void)
 271          } {
 272              uw::_URC_NO_REASON => {
 273                  match cx.last_error {
 274                      Some(err) => Err(err),
 275                      None => Ok(())
 276                  }
 277              }
 278              _ => Ok(()),
 279          };
 280  
 281          extern fn trace_fn(ctx*uw::_Unwind_Context,
 282                             arg*libc::c_void) -> uw::_Unwind_Reason_Code {
 283              let cx&mut Context = unsafe { cast::transmute(arg) };
 284              let ip = unsafe { uw::_Unwind_GetIP(ctx) as *libc::c_void };
 285              // dladdr() on osx gets whiny when we use FindEnclosingFunction, and
 286              // it appears to work fine without it, so we only use
 287              // FindEnclosingFunction on non-osx platforms. In doing so, we get a
 288              // slightly more accurate stack trace in the process.
 289              //
 290              // This is often because failure involves the last instruction of a
 291              // function being "call std::rt::begin_unwind", with no ret
 292              // instructions after it. This means that the return instruction
 293              // pointer points *outside* of the calling function, and by
 294              // unwinding it we go back to the original function.
 295              let ip = if cfg!(target_os = "macos") {
 296                  ip
 297              } else {
 298                  unsafe { uw::_Unwind_FindEnclosingFunction(ip) }
 299              };
 300  
 301              // Don't print out the first few frames (they're not user frames)
 302              cx.idx += 1;
 303              if cx.idx <= 0 { return uw::_URC_NO_REASON }
 304              // Don't print ginormous backtraces
 305              if cx.idx > 100 {
 306                  match write!(cx.writer, " ... <frames omitted>\n") {
 307                      Ok(()) => {}
 308                      Err(e) => { cx.last_error = Some(e); }
 309                  }
 310                  return uw::_URC_FAILURE
 311              }
 312  
 313              // Once we hit an error, stop trying to print more frames
 314              if cx.last_error.is_some() { return uw::_URC_FAILURE }
 315  
 316              match print(cx.writer, cx.idx, ip) {
 317                  Ok(()) => {}
 318                  Err(e) => { cx.last_error = Some(e); }
 319              }
 320  
 321              // keep going
 322              return uw::_URC_NO_REASON
 323          }
 324      }
 325  
 326      #[cfg(target_os = "macos")]
 327      fn print(w: &mut Writer, idx: int, addr: *libc::c_void) -> IoResult<(){
 328          use intrinsics;
 329          struct Dl_info {
 330              dli_fname: *libc::c_char,
 331              dli_fbase: *libc::c_void,
 332              dli_sname: *libc::c_char,
 333              dli_saddr: *libc::c_void,
 334          }
 335          extern {
 336              fn dladdr(addr: *libc::c_void,
 337                        info: *mut Dl_info) -> libc::c_int;
 338          }
 339  
 340          let mut info: Dl_info = unsafe { intrinsics::init() };
 341          if unsafe { dladdr(addr, &mut info) == 0 } {
 342              output(w, idx,addr, None)
 343          } else {
 344              output(w, idx, addr, Some(unsafe {
 345                  CString::new(info.dli_sname, false)
 346              }))
 347          }
 348      }
 349  
 350      #[cfg(not(target_os = "macos"))]
 351      fn print(w: &mut Writer, idx: int, addr: *libc::c_void) -> IoResult<()> {
 352          use container::Container;
 353          use iter::Iterator;
 354          use os;
 355          use path::GenericPath;
 356          use ptr::RawPtr;
 357          use ptr;
 358          use slice::{ImmutableVector, MutableVector};
 359  
 360          ////////////////////////////////////////////////////////////////////////
 361          // libbacktrace.h API
 362          ////////////////////////////////////////////////////////////////////////
 363          type backtrace_syminfo_callback =
 364              extern "C" fn(data: *mut libc::c_void,
 365                            pc: libc::uintptr_t,
 366                            symname: *libc::c_char,
 367                            symval: libc::uintptr_t,
 368                            symsize: libc::uintptr_t);
 369          type backtrace_error_callback =
 370              extern "C" fn(data: *mut libc::c_void,
 371                            msg: *libc::c_char,
 372                            errnum: libc::c_int);
 373          enum backtrace_state {}
 374          #[link(name = "backtrace", kind = "static")]
 375          extern {
 376              fn backtrace_create_state(filename*libc::c_char,
 377                                        threadedlibc::c_int,
 378                                        errorbacktrace_error_callback,
 379                                        data*mut libc::c_void)
 380                                              -> *mut backtrace_state;
 381              fn backtrace_syminfo(state*mut backtrace_state,
 382                                   addrlibc::uintptr_t,
 383                                   cbbacktrace_syminfo_callback,
 384                                   errorbacktrace_error_callback,
 385                                   data*mut libc::c_void) -> libc::c_int;
 386          }
 387  
 388          ////////////////////////////////////////////////////////////////////////
 389          // helper callbacks
 390          ////////////////////////////////////////////////////////////////////////
 391  
 392          extern fn error_cb(_data*mut libc::c_void, _msg*libc::c_char,
 393                             _errnumlibc::c_int) {
 394              // do nothing for now
 395          }
 396          extern fn syminfo_cb(data*mut libc::c_void,
 397                               _pclibc::uintptr_t,
 398                               symname*libc::c_char,
 399                               _symvallibc::uintptr_t,
 400                               _symsizelibc::uintptr_t) {
 401              let slot = data as *mut *libc::c_char;
 402              unsafe { *slot = symname; }
 403          }
 404  
 405          // The libbacktrace API supports creating a state, but it does not
 406          // support destroying a state. I personally take this to mean that a
 407          // state is meant to be created and then live forever.
 408          //
 409          // I would love to register an at_exit() handler which cleans up this
 410          // state, but libbacktrace provides no way to do so.
 411          //
 412          // With these constraints, this function has a statically cached state
 413          // that is calculated the first time this is requested. Remember that
 414          // backtracing all happens serially (one global lock).
 415          //
 416          // An additionally oddity in this function is that we initialize the
 417          // filename via self_exe_name() to pass to libbacktrace. It turns out
 418          // that on linux libbacktrace seamlessly gets the filename of the
 419          // current executable, but this fails on freebsd. by always providing
 420          // it, we make sure that libbacktrace never has a reason to not look up
 421          // the symbols. The libbacktrace API also states that the filename must
 422          // be in "permanent memory", so we copy it to a static and then use the
 423          // static as the pointer.
 424          unsafe fn init_state() -> *mut backtrace_state {
 425              static mut STATE: *mut backtrace_state = 0 as *mut backtrace_state;
 426              static mut LAST_FILENAME: [libc::c_char, ..256] = [0, ..256];
 427              if !STATE.is_null() { return STATE }
 428              let selfname = if cfg!(target_os = "freebsd") {
 429                  os::self_exe_name()
 430              } else {
 431                  None
 432              };
 433              let filename = match selfname {
 434                  Some(path) => {
 435                      let bytes = path.as_vec();
 436                      if bytes.len() < LAST_FILENAME.len() {
 437                          let i = bytes.iter();
 438                          for (slot, val) in LAST_FILENAME.mut_iter().zip(i) {
 439                              *slot = *val as libc::c_char;
 440                          }
 441                          LAST_FILENAME.as_ptr()
 442                      } else {
 443                          ptr::null()
 444                      }
 445                  }
 446                  None => ptr::null(),
 447              };
 448              STATE = backtrace_create_state(filename, 0, error_cb,
 449                                             ptr::mut_null());
 450              return STATE
 451          }
 452  
 453          ////////////////////////////////////////////////////////////////////////
 454          // translation
 455          ////////////////////////////////////////////////////////////////////////
 456  
 457          // backtrace errors are currently swept under the rug, only I/O
 458          // errors are reported
 459          let state = unsafe { init_state() };
 460          if state.is_null() {
 461              return output(w, idx, addr, None)
 462          }
 463          let mut data = 0 as *libc::c_char;
 464          let data_addr = &mut data as *mut *libc::c_char;
 465          let ret = unsafe {
 466              backtrace_syminfo(state, addr as libc::uintptr_t,
 467                                syminfo_cb, error_cb,
 468                                data_addr as *mut libc::c_void)
 469          };
 470          if ret == 0 || data.is_null() {
 471              output(w, idx, addr, None)
 472          } else {
 473              output(w, idx, addr, Some(unsafe { CString::new(data, false) }))
 474          }
 475      }
 476  
 477      // Finally, after all that work above, we can emit a symbol.
 478      fn output(w: &mut Writer, idx: int, addr: *libc::c_void,
 479                sOption<CString>) -> IoResult<()> {
 480          try!(write!(w, "  {:2}{:2$} - ", idx, addr, super::HEX_WIDTH));
 481          match s.as_ref().and_then(|c| c.as_str()) {
 482              Some(string) => try!(super::demangle(w, string)),
 483              None => try!(write!(w, "<unknown>")),
 484          }
 485          w.write(['\n' as u8])
 486      }
 487  }
 488  
 489  /// As always, windows has something very different than unix, we mainly want
 490  /// to avoid having to depend too much on libunwind for windows.
 491  ///
 492  /// If you google around, you'll find a fair bit of references to built-in
 493  /// functions to get backtraces on windows. It turns out that most of these are
 494  /// in an external library called dbghelp. I was unable to find this library
 495  /// via `-ldbghelp`, but it is apparently normal to do the `dlopen` equivalent
 496  /// of it.
 497  ///
 498  /// You'll also find that there's a function called CaptureStackBackTrace
 499  /// mentioned frequently (which is also easy to use), but sadly I didn't have a
 500  /// copy of that function in my mingw install (maybe it was broken?). Instead,
 501  /// this takes the route of using StackWalk64 in order to walk the stack.
 502  #[cfg(windows)]
 503  #[allow(dead_code, uppercase_variables)]
 504  mod imp {
 505      use c_str::CString;
 506      use container::Container;
 507      use io::{IoResult, Writer};
 508      use iter::Iterator;
 509      use libc;
 510      use mem;
 511      use ops::Drop;
 512      use option::{Some, None};
 513      use path::Path;
 514      use result::{Ok, Err};
 515      use str::StrSlice;
 516      use unstable::dynamic_lib::DynamicLibrary;
 517      use intrinsics;
 518      use unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
 519      use slice::ImmutableVector;
 520  
 521      extern "system" {
 522          fn GetCurrentProcess() -> libc::HANDLE;
 523          fn GetCurrentThread() -> libc::HANDLE;
 524          fn RtlCaptureContext(ctx: *mut arch::CONTEXT);
 525      }
 526  
 527      type SymFromAddrFn =
 528          extern "system" fn(libc::HANDLE, u64, *mut u64,
 529                             *mut SYMBOL_INFO) -> libc::BOOL;
 530      type SymInitializeFn =
 531          extern "system" fn(libc::HANDLE, *libc::c_void,
 532                             libc::BOOL) -> libc::BOOL;
 533      type SymCleanupFn =
 534          extern "system" fn(libc::HANDLE) -> libc::BOOL;
 535  
 536      type StackWalk64Fn =
 537          extern "system" fn(libc::DWORD, libc::HANDLE, libc::HANDLE,
 538                             *mut STACKFRAME64, *mut arch::CONTEXT,
 539                             *libc::c_void, *libc::c_void,
 540                             *libc::c_void, *libc::c_void) -> libc::BOOL;
 541  
 542      static MAX_SYM_NAME: uint = 2000;
 543      static IMAGE_FILE_MACHINE_I386: libc::DWORD = 0x014c;
 544      static IMAGE_FILE_MACHINE_IA64: libc::DWORD = 0x0200;
 545      static IMAGE_FILE_MACHINE_AMD64: libc::DWORD = 0x8664;
 546  
 547      #[packed]
 548      struct SYMBOL_INFO {
 549          SizeOfStruct: libc::c_ulong,
 550          TypeIndex: libc::c_ulong,
 551          Reserved: [u64, ..2],
 552          Index: libc::c_ulong,
 553          Size: libc::c_ulong,
 554          ModBase: u64,
 555          Flags: libc::c_ulong,
 556          Value: u64,
 557          Address: u64,
 558          Register: libc::c_ulong,
 559          Scope: libc::c_ulong,
 560          Tag: libc::c_ulong,
 561          NameLen: libc::c_ulong,
 562          MaxNameLen: libc::c_ulong,
 563          // note that windows has this as 1, but it basically just means that
 564          // the name is inline at the end of the struct. For us, we just bump
 565          // the struct size up to MAX_SYM_NAME.
 566          Name: [libc::c_char, ..MAX_SYM_NAME],
 567      }
 568  
 569      #[repr(C)]
 570      enum ADDRESS_MODE {
 571          AddrMode1616,
 572          AddrMode1632,
 573          AddrModeReal,
 574          AddrModeFlat,
 575      }
 576  
 577      struct ADDRESS64 {
 578          Offset: u64,
 579          Segment: u16,
 580          Mode: ADDRESS_MODE,
 581      }
 582  
 583      struct STACKFRAME64 {
 584          AddrPC: ADDRESS64,
 585          AddrReturn: ADDRESS64,
 586          AddrFrame: ADDRESS64,
 587          AddrStack: ADDRESS64,
 588          AddrBStore: ADDRESS64,
 589          FuncTableEntry: *libc::c_void,
 590          Params: [u64, ..4],
 591          Far: libc::BOOL,
 592          Virtual: libc::BOOL,
 593          Reserved: [u64, ..3],
 594          KdHelp: KDHELP64,
 595      }
 596  
 597      struct KDHELP64 {
 598          Thread: u64,
 599          ThCallbackStack: libc::DWORD,
 600          ThCallbackBStore: libc::DWORD,
 601          NextCallback: libc::DWORD,
 602          FramePointer: libc::DWORD,
 603          KiCallUserMode: u64,
 604          KeUserCallbackDispatcher: u64,
 605          SystemRangeStart: u64,
 606          KiUserExceptionDispatcher: u64,
 607          StackBase: u64,
 608          StackLimit: u64,
 609          Reserved: [u64, ..5],
 610      }
 611  
 612      #[cfg(target_arch = "x86")]
 613      mod arch {
 614          use libc;
 615  
 616          static MAXIMUM_SUPPORTED_EXTENSION: uint = 512;
 617  
 618          pub struct CONTEXT {
 619              ContextFlags: libc::DWORD,
 620              Dr0: libc::DWORD,
 621              Dr1: libc::DWORD,
 622              Dr2: libc::DWORD,
 623              Dr3: libc::DWORD,
 624              Dr6: libc::DWORD,
 625              Dr7: libc::DWORD,
 626              FloatSave: FLOATING_SAVE_AREA,
 627              SegGs: libc::DWORD,
 628              SegFs: libc::DWORD,
 629              SegEs: libc::DWORD,
 630              SegDs: libc::DWORD,
 631              Edi: libc::DWORD,
 632              Esi: libc::DWORD,
 633              Ebx: libc::DWORD,
 634              Edx: libc::DWORD,
 635              Ecx: libc::DWORD,
 636              Eax: libc::DWORD,
 637              Ebp: libc::DWORD,
 638              Eip: libc::DWORD,
 639              SegCs: libc::DWORD,
 640              EFlags: libc::DWORD,
 641              Esp: libc::DWORD,
 642              SegSs: libc::DWORD,
 643              ExtendedRegisters: [u8, ..MAXIMUM_SUPPORTED_EXTENSION],
 644          }
 645  
 646          pub struct FLOATING_SAVE_AREA {
 647              ControlWord: libc::DWORD,
 648              StatusWord: libc::DWORD,
 649              TagWord: libc::DWORD,
 650              ErrorOffset: libc::DWORD,
 651              ErrorSelector: libc::DWORD,
 652              DataOffset: libc::DWORD,
 653              DataSelector: libc::DWORD,
 654              RegisterArea: [u8, ..80],
 655              Cr0NpxState: libc::DWORD,
 656          }
 657  
 658          pub fn init_frame(frame: &mut super::STACKFRAME64,
 659                            ctx: &CONTEXT) -> libc::DWORD {
 660              frame.AddrPC.Offset = ctx.Eip as u64;
 661              frame.AddrPC.Mode = super::AddrModeFlat;
 662              frame.AddrStack.Offset = ctx.Esp as u64;
 663              frame.AddrStack.Mode = super::AddrModeFlat;
 664              frame.AddrFrame.Offset = ctx.Ebp as u64;
 665              frame.AddrFrame.Mode = super::AddrModeFlat;
 666              super::IMAGE_FILE_MACHINE_I386
 667          }
 668      }
 669  
 670      #[cfg(target_arch = "x86_64")]
 671      mod arch {
 672          use libc::{c_longlong, c_ulonglong};
 673          use libc::types::os::arch::extra::{WORD, DWORD, DWORDLONG};
 674  
 675          pub struct CONTEXT {
 676              P1Home: DWORDLONG,
 677              P2Home: DWORDLONG,
 678              P3Home: DWORDLONG,
 679              P4Home: DWORDLONG,
 680              P5Home: DWORDLONG,
 681              P6Home: DWORDLONG,
 682  
 683              ContextFlags: DWORD,
 684              MxCsr: DWORD,
 685  
 686              SegCs: WORD,
 687              SegDs: WORD,
 688              SegEs: WORD,
 689              SegFs: WORD,
 690              SegGs: WORD,
 691              SegSs: WORD,
 692              EFlags: DWORD,
 693  
 694              Dr0: DWORDLONG,
 695              Dr1: DWORDLONG,
 696              Dr2: DWORDLONG,
 697              Dr3: DWORDLONG,
 698              Dr6: DWORDLONG,
 699              Dr7: DWORDLONG,
 700  
 701              Rax: DWORDLONG,
 702              Rcx: DWORDLONG,
 703              Rdx: DWORDLONG,
 704              Rbx: DWORDLONG,
 705              Rsp: DWORDLONG,
 706              Rbp: DWORDLONG,
 707              Rsi: DWORDLONG,
 708              Rdi: DWORDLONG,
 709              R8:  DWORDLONG,
 710              R9:  DWORDLONG,
 711              R10: DWORDLONG,
 712              R11: DWORDLONG,
 713              R12: DWORDLONG,
 714              R13: DWORDLONG,
 715              R14: DWORDLONG,
 716              R15: DWORDLONG,
 717  
 718              Rip: DWORDLONG,
 719  
 720              FltSave: FLOATING_SAVE_AREA,
 721  
 722              VectorRegister: [M128A, .. 26],
 723              VectorControl: DWORDLONG,
 724  
 725              DebugControl: DWORDLONG,
 726              LastBranchToRip: DWORDLONG,
 727              LastBranchFromRip: DWORDLONG,
 728              LastExceptionToRip: DWORDLONG,
 729              LastExceptionFromRip: DWORDLONG,
 730          }
 731  
 732          pub struct M128A {
 733              Low:  c_ulonglong,
 734              High: c_longlong
 735          }
 736  
 737          pub struct FLOATING_SAVE_AREA {
 738              _Dummy: [u8, ..512] // FIXME: Fill this out
 739          }
 740  
 741          pub fn init_frame(frame: &mut super::STACKFRAME64,
 742                            ctx: &CONTEXT) -> DWORD {
 743              frame.AddrPC.Offset = ctx.Rip as u64;
 744              frame.AddrPC.Mode = super::AddrModeFlat;
 745              frame.AddrStack.Offset = ctx.Rsp as u64;
 746              frame.AddrStack.Mode = super::AddrModeFlat;
 747              frame.AddrFrame.Offset = ctx.Rbp as u64;
 748              frame.AddrFrame.Mode = super::AddrModeFlat;
 749              super::IMAGE_FILE_MACHINE_AMD64
 750          }
 751      }
 752  
 753      struct Cleanup {
 754          handle: libc::HANDLE,
 755          SymCleanup: SymCleanupFn,
 756      }
 757  
 758      impl Drop for Cleanup {
 759          fn drop(&mut self) { (self.SymCleanup)(self.handle); }
 760      }
 761  
 762      pub fn write(w: &mut Writer) -> IoResult<(){
 763          // According to windows documentation, all dbghelp functions are
 764          // single-threaded.
 765          static mut LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
 766          let _g = unsafe { LOCK.lock() };
 767  
 768          // Open up dbghelp.dll, we don't link to it explicitly because it can't
 769          // always be found. Additionally, it's nice having fewer dependencies.
 770          let path = Path::new("dbghelp.dll");
 771          let lib = match DynamicLibrary::open(Some(&path)) {
 772              Ok(lib) => lib,
 773              Err(..) => return Ok(()),
 774          };
 775  
 776          macro_rules! sym( ($e:expr, $t:ident) => (
 777              match unsafe { lib.symbol::<$t>($e) } {
 778                  Ok(f) => f,
 779                  Err(..) => return Ok(())
 780              }
 781          ) )
 782  
 783          // Fetch the symbols necessary from dbghelp.dll
 784          let SymFromAddr = sym!("SymFromAddr", SymFromAddrFn);
 785          let SymInitialize = sym!("SymInitialize", SymInitializeFn);
 786          let SymCleanup = sym!("SymCleanup", SymCleanupFn);
 787          let StackWalk64 = sym!("StackWalk64", StackWalk64Fn);
 788  
 789          // Allocate necessary structures for doing the stack walk
 790          let process = unsafe { GetCurrentProcess() };
 791          let thread = unsafe { GetCurrentThread() };
 792          let mut context: arch::CONTEXT = unsafe { intrinsics::init() };
 793          unsafe { RtlCaptureContext(&mut context); }
 794          let mut frame: STACKFRAME64 = unsafe { intrinsics::init() };
 795          let image = arch::init_frame(&mut frame, &context);
 796  
 797          // Initialize this process's symbols
 798          let ret = SymInitialize(process, 0 as *libc::c_void, libc::TRUE);
 799          if ret != libc::TRUE { return Ok(()) }
 800          let _c = Cleanup { handle: process, SymCleanup: SymCleanup };
 801  
 802          // And now that we're done with all the setup, do the stack walking!
 803          let mut i = 0;
 804          try!(write!(w, "stack backtrace:\n"));
 805          while StackWalk64(image, process, thread, &mut frame, &mut context,
 806                            0 as *libc::c_void, 0 as *libc::c_void,
 807                            0 as *libc::c_void, 0 as *libc::c_void) == libc::TRUE{
 808              let addr = frame.AddrPC.Offset;
 809              if addr == frame.AddrReturn.Offset || addr == 0 ||
 810                 frame.AddrReturn.Offset == 0 { break }
 811  
 812              i += 1;
 813              try!(write!(w, "  {:2}{:#2$x}", i, addr, super::HEX_WIDTH));
 814              let mut info: SYMBOL_INFO = unsafe { intrinsics::init() };
 815              info.MaxNameLen = MAX_SYM_NAME as libc::c_ulong;
 816              info.SizeOfStruct = (mem::size_of::<SYMBOL_INFO>() -
 817                                   info.Name.len() + 1) as libc::c_ulong;
 818  
 819              let mut displacement = 0u64;
 820              let ret = SymFromAddr(process, addr as u64, &mut displacement,
 821                                    &mut info);
 822  
 823              if ret == libc::TRUE {
 824                  try!(write!(w, " - "));
 825                  let cstr = unsafe { CString::new(info.Name.as_ptr(), false) };
 826                  let bytes = cstr.as_bytes();
 827                  match cstr.as_str() {
 828                      Some(s) => try!(super::demangle(w, s)),
 829                      None => try!(w.write(bytes.slice_to(bytes.len() - 1))),
 830                  }
 831              }
 832              try!(w.write(['\n' as u8]));
 833          }
 834  
 835          Ok(())
 836      }
 837  }
 838  
 839  #[cfg(test)]
 840  mod test {
 841      use prelude::*;
 842      use io::MemWriter;
 843      use str;
 844  
 845      macro_rules! t( ($a:expr, $b:expr) => ({
 846          let mut m = MemWriter::new();
 847          super::demangle(&mut m, $a).unwrap();
 848          assert_eq!(str::from_utf8(m.unwrap().as_slice()).unwrap().to_owned(), $b.to_owned());
 849      }) )
 850  
 851      #[test]
 852      fn demangle() {
 853          t!("test", "test");
 854          t!("_ZN4testE", "test");
 855          t!("_ZN4test", "_ZN4test");
 856          t!("_ZN4test1a2bcE", "test::a::bc");
 857      }
 858  
 859      #[test]
 860      fn demangle_dollars() {
 861          t!("_ZN4$UP$E", "Box");
 862          t!("_ZN8$UP$testE", "Boxtest");
 863          t!("_ZN8$UP$test4foobE", "Boxtest::foob");
 864          t!("_ZN8$x20test4foobE", " test::foob");
 865      }
 866  
 867      #[test]
 868      fn demangle_many_dollars() {
 869          t!("_ZN12test$x20test4foobE", "test test::foob");
 870          t!("_ZN12test$UP$test4foobE", "testBoxtest::foob");
 871      }
 872  }


libstd/rt/backtrace.rs:373:8-373:8 -enum- definition:
        enum backtrace_state {}
        #[link(name = "backtrace", kind = "static")]
        extern {
references:- 5
423:         // static as the pointer.
424:         unsafe fn init_state() -> *mut backtrace_state {
425:             static mut STATE: *mut backtrace_state = 0 as *mut backtrace_state;
426:             static mut LAST_FILENAME: [libc::c_char, ..256] = [0, ..256];


libstd/rt/backtrace.rs:369:8-369:8 -NK_AS_STR_TODO- definition:
        type backtrace_error_callback =
            extern "C" fn(data: *mut libc::c_void,
                          msg: *libc::c_char,
references:- 2
377:                                       threaded: libc::c_int,
378:                                       error: backtrace_error_callback,
379:                                       data: *mut libc::c_void)
--
383:                                  cb: backtrace_syminfo_callback,
384:                                  error: backtrace_error_callback,
385:                                  data: *mut libc::c_void) -> libc::c_int;


libstd/rt/backtrace.rs:392:8-392:8 -fn- definition:
        extern fn error_cb(_data: *mut libc::c_void, _msg: *libc::c_char,
                           _errnum: libc::c_int) {
            // do nothing for now
references:- 2
447:             };
448:             STATE = backtrace_create_state(filename, 0, error_cb,
449:                                            ptr::mut_null());
--
466:             backtrace_syminfo(state, addr as libc::uintptr_t,
467:                               syminfo_cb, error_cb,
468:                               data_addr as *mut libc::c_void)


libstd/rt/backtrace.rs:29:81-29:81 -fn- definition:
// whether the magical environment variable is present to see if it's turned on.
pub fn log_enabled() -> bool {
    static mut ENABLED: atomics::AtomicInt = atomics::INIT_ATOMIC_INT;
references:- 4
libstd/rt/unwind.rs:
383:                 rterrln!("failed at '{}', {}:{}", msg_s, file, line);
384:                 if backtrace::log_enabled() {
385:                     let mut err = ::rt::util::Stderr;
--
425:                              file, line);
426:                     if backtrace::log_enabled() {
427:                         let mut err = ::rt::util::Stderr;
--
444:             // printed if logging was enabled).
445:             if !backtrace::log_enabled() {
446:                 let mut err = ::rt::util::Stderr;


libstd/rt/backtrace.rs:478:4-478:4 -fn- definition:
    fn output(w: &mut Writer, idx: int, addr: *libc::c_void,
              s: Option<CString>) -> IoResult<()> {
        try!(write!(w, "  {:2}: {:2$} - ", idx, addr, super::HEX_WIDTH));
references:- 3
472:         } else {
473:             output(w, idx, addr, Some(unsafe { CString::new(data, false) }))
474:         }


libstd/rt/backtrace.rs:248:4-248:4 -struct- definition:
    struct Context<'a> {
        idx: int,
        writer: &'a mut Writer,
references:- 3
267:         let mut cx = Context { writer: w, last_error: None, idx: 0 };
268:         return match unsafe {
--
282:                            arg: *libc::c_void) -> uw::_Unwind_Reason_Code {
283:             let cx: &mut Context = unsafe { cast::transmute(arg) };
284:             let ip = unsafe { uw::_Unwind_GetIP(ctx) as *libc::c_void };


libstd/rt/backtrace.rs:256:4-256:4 -fn- definition:
    pub fn write(w: &mut Writer) -> IoResult<()> {
        // When using libbacktrace, we use some necessary global state, so we
        // need to prevent more than one thread from entering this block. This
references:- 5
libstd/rt/util.rs:
153:         let mut err = Stderr;
154:         let _err = ::rt::backtrace::write(&mut err);
155:     }
libstd/rt/unwind.rs:
446:                 let mut err = ::rt::util::Stderr;
447:                 let _err = backtrace::write(&mut err);
448:             }