2014-02-05 17:19:40 -06:00
|
|
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2014-10-09 14:17:22 -05:00
|
|
|
//! Simple backtrace functionality (to print on panic)
|
2014-04-27 21:05:41 -05:00
|
|
|
|
2014-03-21 20:05:05 -05:00
|
|
|
#![allow(non_camel_case_types)]
|
2014-02-05 17:19:40 -06:00
|
|
|
|
|
|
|
use io::{IoResult, Writer};
|
2014-11-06 11:32:37 -06:00
|
|
|
use iter::{Iterator, IteratorExt};
|
2014-11-28 10:57:41 -06:00
|
|
|
use option::Option::{Some, None};
|
2014-03-13 01:34:31 -05:00
|
|
|
use os;
|
2014-11-28 10:57:41 -06:00
|
|
|
use result::Result::{Ok, Err};
|
2014-11-14 22:52:00 -06:00
|
|
|
use str::{StrPrelude, from_str};
|
2014-08-04 17:42:36 -05:00
|
|
|
use sync::atomic;
|
2014-07-11 16:23:45 -05:00
|
|
|
use unicode::char::UnicodeChar;
|
2014-02-05 17:19:40 -06:00
|
|
|
|
|
|
|
pub use self::imp::write;
|
|
|
|
|
2014-03-13 01:34:31 -05:00
|
|
|
// For now logging is turned off by default, and this function checks to see
|
|
|
|
// whether the magical environment variable is present to see if it's turned on.
|
2014-02-05 17:19:40 -06:00
|
|
|
pub fn log_enabled() -> bool {
|
2014-10-10 23:59:10 -05:00
|
|
|
static ENABLED: atomic::AtomicInt = atomic::INIT_ATOMIC_INT;
|
|
|
|
match ENABLED.load(atomic::SeqCst) {
|
|
|
|
1 => return false,
|
|
|
|
2 => return true,
|
|
|
|
_ => {}
|
2014-03-13 01:34:31 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
let val = match os::getenv("RUST_BACKTRACE") {
|
|
|
|
Some(..) => 2,
|
|
|
|
None => 1,
|
|
|
|
};
|
2014-10-10 23:59:10 -05:00
|
|
|
ENABLED.store(val, atomic::SeqCst);
|
2014-03-13 01:34:31 -05:00
|
|
|
val == 2
|
2014-02-05 17:19:40 -06:00
|
|
|
}
|
|
|
|
|
2014-10-09 13:59:03 -05:00
|
|
|
#[cfg(target_word_size = "64")] const HEX_WIDTH: uint = 18;
|
|
|
|
#[cfg(target_word_size = "32")] const HEX_WIDTH: uint = 10;
|
2014-02-05 17:19:40 -06:00
|
|
|
|
|
|
|
// All rust symbols are in theory lists of "::"-separated identifiers. Some
|
|
|
|
// assemblers, however, can't handle these characters in symbol names. To get
|
|
|
|
// around this, we use C++-style mangling. The mangling method is:
|
|
|
|
//
|
|
|
|
// 1. Prefix the symbol with "_ZN"
|
|
|
|
// 2. For each element of the path, emit the length plus the element
|
|
|
|
// 3. End the path with "E"
|
|
|
|
//
|
|
|
|
// For example, "_ZN4testE" => "test" and "_ZN3foo3bar" => "foo::bar".
|
|
|
|
//
|
|
|
|
// We're the ones printing our backtraces, so we can't rely on anything else to
|
|
|
|
// demangle our symbols. It's *much* nicer to look at demangled symbols, so
|
|
|
|
// this function is implemented to give us nice pretty output.
|
|
|
|
//
|
|
|
|
// Note that this demangler isn't quite as fancy as it could be. We have lots
|
|
|
|
// of other information in our symbols like hashes, version, type information,
|
|
|
|
// etc. Additionally, this doesn't handle glue symbols at all.
|
|
|
|
fn demangle(writer: &mut Writer, s: &str) -> IoResult<()> {
|
|
|
|
// First validate the symbol. If it doesn't look like anything we're
|
|
|
|
// expecting, we just print it literally. Note that we must handle non-rust
|
|
|
|
// symbols because we could have any function in the backtrace.
|
|
|
|
let mut valid = true;
|
|
|
|
if s.len() > 4 && s.starts_with("_ZN") && s.ends_with("E") {
|
|
|
|
let mut chars = s.slice(3, s.len() - 1).chars();
|
|
|
|
while valid {
|
|
|
|
let mut i = 0;
|
|
|
|
for c in chars {
|
2014-10-08 19:15:27 -05:00
|
|
|
if c.is_numeric() {
|
2014-02-05 17:19:40 -06:00
|
|
|
i = i * 10 + c as uint - '0' as uint;
|
|
|
|
} else {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if i == 0 {
|
|
|
|
valid = chars.next().is_none();
|
|
|
|
break
|
2014-06-06 01:18:51 -05:00
|
|
|
} else if chars.by_ref().take(i - 1).count() != i - 1 {
|
2014-02-05 17:19:40 -06:00
|
|
|
valid = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
valid = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Alright, let's do this.
|
|
|
|
if !valid {
|
|
|
|
try!(writer.write_str(s));
|
|
|
|
} else {
|
|
|
|
let mut s = s.slice_from(3);
|
|
|
|
let mut first = true;
|
|
|
|
while s.len() > 1 {
|
|
|
|
if !first {
|
|
|
|
try!(writer.write_str("::"));
|
|
|
|
} else {
|
|
|
|
first = false;
|
|
|
|
}
|
|
|
|
let mut rest = s;
|
2014-10-08 19:15:27 -05:00
|
|
|
while rest.char_at(0).is_numeric() {
|
2014-02-05 17:19:40 -06:00
|
|
|
rest = rest.slice_from(1);
|
|
|
|
}
|
|
|
|
let i: uint = from_str(s.slice_to(s.len() - rest.len())).unwrap();
|
|
|
|
s = rest.slice_from(i);
|
2014-03-13 18:23:10 -05:00
|
|
|
rest = rest.slice_to(i);
|
2014-04-18 19:33:47 -05:00
|
|
|
while rest.len() > 0 {
|
2014-03-13 18:23:10 -05:00
|
|
|
if rest.starts_with("$") {
|
|
|
|
macro_rules! demangle(
|
|
|
|
($($pat:expr => $demangled:expr),*) => ({
|
|
|
|
$(if rest.starts_with($pat) {
|
|
|
|
try!(writer.write_str($demangled));
|
|
|
|
rest = rest.slice_from($pat.len());
|
|
|
|
} else)*
|
|
|
|
{
|
|
|
|
try!(writer.write_str(rest));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
})
|
|
|
|
)
|
|
|
|
// see src/librustc/back/link.rs for these mappings
|
|
|
|
demangle! (
|
|
|
|
"$SP$" => "@",
|
2014-05-05 20:56:44 -05:00
|
|
|
"$UP$" => "Box",
|
2014-03-13 18:23:10 -05:00
|
|
|
"$RP$" => "*",
|
|
|
|
"$BP$" => "&",
|
|
|
|
"$LT$" => "<",
|
|
|
|
"$GT$" => ">",
|
|
|
|
"$LP$" => "(",
|
|
|
|
"$RP$" => ")",
|
|
|
|
"$C$" => ",",
|
|
|
|
|
2014-09-02 00:35:58 -05:00
|
|
|
// in theory we can demangle any Unicode code point, but
|
2014-03-13 18:23:10 -05:00
|
|
|
// for simplicity we just catch the common ones.
|
|
|
|
"$x20" => " ",
|
|
|
|
"$x27" => "'",
|
|
|
|
"$x5b" => "[",
|
|
|
|
"$x5d" => "]"
|
|
|
|
)
|
|
|
|
} else {
|
2014-04-18 19:33:47 -05:00
|
|
|
let idx = match rest.find('$') {
|
|
|
|
None => rest.len(),
|
|
|
|
Some(i) => i,
|
|
|
|
};
|
|
|
|
try!(writer.write_str(rest.slice_to(idx)));
|
|
|
|
rest = rest.slice_from(idx);
|
2014-03-13 18:23:10 -05:00
|
|
|
}
|
|
|
|
}
|
2014-02-05 17:19:40 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Backtrace support built on libgcc with some extra OS-specific support
|
|
|
|
///
|
|
|
|
/// Some methods of getting a backtrace:
|
|
|
|
///
|
|
|
|
/// * The backtrace() functions on unix. It turns out this doesn't work very
|
|
|
|
/// well for green threads on OSX, and the address to symbol portion of it
|
|
|
|
/// suffers problems that are described below.
|
|
|
|
///
|
|
|
|
/// * Using libunwind. This is more difficult than it sounds because libunwind
|
|
|
|
/// isn't installed everywhere by default. It's also a bit of a hefty library,
|
|
|
|
/// so possibly not the best option. When testing, libunwind was excellent at
|
|
|
|
/// getting both accurate backtraces and accurate symbols across platforms.
|
|
|
|
/// This route was not chosen in favor of the next option, however.
|
|
|
|
///
|
|
|
|
/// * We're already using libgcc_s for exceptions in rust (triggering task
|
|
|
|
/// unwinding and running destructors on the stack), and it turns out that it
|
|
|
|
/// conveniently comes with a function that also gives us a backtrace. All of
|
|
|
|
/// these functions look like _Unwind_*, but it's not quite the full
|
|
|
|
/// repertoire of the libunwind API. Due to it already being in use, this was
|
|
|
|
/// the chosen route of getting a backtrace.
|
|
|
|
///
|
|
|
|
/// After choosing libgcc_s for backtraces, the sad part is that it will only
|
|
|
|
/// give us a stack trace of instruction pointers. Thankfully these instruction
|
|
|
|
/// pointers are accurate (they work for green and native threads), but it's
|
|
|
|
/// then up to us again to figure out how to translate these addresses to
|
|
|
|
/// symbols. As with before, we have a few options. Before, that, a little bit
|
|
|
|
/// of an interlude about symbols. This is my very limited knowledge about
|
|
|
|
/// symbol tables, and this information is likely slightly wrong, but the
|
|
|
|
/// general idea should be correct.
|
|
|
|
///
|
|
|
|
/// When talking about symbols, it's helpful to know a few things about where
|
|
|
|
/// symbols are located. Some symbols are located in the dynamic symbol table
|
|
|
|
/// of the executable which in theory means that they're available for dynamic
|
|
|
|
/// linking and lookup. Other symbols end up only in the local symbol table of
|
|
|
|
/// the file. This loosely corresponds to pub and priv functions in Rust.
|
|
|
|
///
|
|
|
|
/// Armed with this knowledge, we know that our solution for address to symbol
|
|
|
|
/// translation will need to consult both the local and dynamic symbol tables.
|
|
|
|
/// With that in mind, here's our options of translating an address to
|
|
|
|
/// a symbol.
|
|
|
|
///
|
|
|
|
/// * Use dladdr(). The original backtrace()-based idea actually uses dladdr()
|
|
|
|
/// behind the scenes to translate, and this is why backtrace() was not used.
|
|
|
|
/// Conveniently, this method works fantastically on OSX. It appears dladdr()
|
|
|
|
/// uses magic to consult the local symbol table, or we're putting everything
|
|
|
|
/// in the dynamic symbol table anyway. Regardless, for OSX, this is the
|
|
|
|
/// method used for translation. It's provided by the system and easy to do.o
|
|
|
|
///
|
|
|
|
/// Sadly, all other systems have a dladdr() implementation that does not
|
|
|
|
/// consult the local symbol table. This means that most functions are blank
|
|
|
|
/// because they don't have symbols. This means that we need another solution.
|
|
|
|
///
|
|
|
|
/// * Use unw_get_proc_name(). This is part of the libunwind api (not the
|
|
|
|
/// libgcc_s version of the libunwind api), but involves taking a dependency
|
|
|
|
/// to libunwind. We may pursue this route in the future if we bundle
|
|
|
|
/// libunwind, but libunwind was unwieldy enough that it was not chosen at
|
|
|
|
/// this time to provide this functionality.
|
|
|
|
///
|
|
|
|
/// * Shell out to a utility like `readelf`. Crazy though it may sound, it's a
|
|
|
|
/// semi-reasonable solution. The stdlib already knows how to spawn processes,
|
|
|
|
/// so in theory it could invoke readelf, parse the output, and consult the
|
|
|
|
/// local/dynamic symbol tables from there. This ended up not getting chosen
|
|
|
|
/// due to the craziness of the idea plus the advent of the next option.
|
|
|
|
///
|
|
|
|
/// * Use `libbacktrace`. It turns out that this is a small library bundled in
|
|
|
|
/// the gcc repository which provides backtrace and symbol translation
|
|
|
|
/// functionality. All we really need from it is the backtrace functionality,
|
|
|
|
/// and we only really need this on everything that's not OSX, so this is the
|
|
|
|
/// chosen route for now.
|
|
|
|
///
|
|
|
|
/// In summary, the current situation uses libgcc_s to get a trace of stack
|
|
|
|
/// pointers, and we use dladdr() or libbacktrace to translate these addresses
|
|
|
|
/// to symbols. This is a bit of a hokey implementation as-is, but it works for
|
|
|
|
/// all unix platforms we support right now, so it at least gets the job done.
|
|
|
|
#[cfg(unix)]
|
|
|
|
mod imp {
|
2014-12-11 11:44:17 -06:00
|
|
|
use prelude::*;
|
|
|
|
|
2014-02-05 17:19:40 -06:00
|
|
|
use c_str::CString;
|
2014-12-11 11:44:17 -06:00
|
|
|
use io::IoResult;
|
2014-02-05 17:19:40 -06:00
|
|
|
use libc;
|
core: Remove the cast module
This commit revisits the `cast` module in libcore and libstd, and scrutinizes
all functions inside of it. The result was to remove the `cast` module entirely,
folding all functionality into the `mem` module. Specifically, this is the fate
of each function in the `cast` module.
* transmute - This function was moved to `mem`, but it is now marked as
#[unstable]. This is due to planned changes to the `transmute`
function and how it can be invoked (see the #[unstable] comment).
For more information, see RFC 5 and #12898
* transmute_copy - This function was moved to `mem`, with clarification that is
is not an error to invoke it with T/U that are different
sizes, but rather that it is strongly discouraged. This
function is now #[stable]
* forget - This function was moved to `mem` and marked #[stable]
* bump_box_refcount - This function was removed due to the deprecation of
managed boxes as well as its questionable utility.
* transmute_mut - This function was previously deprecated, and removed as part
of this commit.
* transmute_mut_unsafe - This function doesn't serve much of a purpose when it
can be achieved with an `as` in safe code, so it was
removed.
* transmute_lifetime - This function was removed because it is likely a strong
indication that code is incorrect in the first place.
* transmute_mut_lifetime - This function was removed for the same reasons as
`transmute_lifetime`
* copy_lifetime - This function was moved to `mem`, but it is marked
`#[unstable]` now due to the likelihood of being removed in
the future if it is found to not be very useful.
* copy_mut_lifetime - This function was also moved to `mem`, but had the same
treatment as `copy_lifetime`.
* copy_lifetime_vec - This function was removed because it is not used today,
and its existence is not necessary with DST
(copy_lifetime will suffice).
In summary, the cast module was stripped down to these functions, and then the
functions were moved to the `mem` module.
transmute - #[unstable]
transmute_copy - #[stable]
forget - #[stable]
copy_lifetime - #[unstable]
copy_mut_lifetime - #[unstable]
[breaking-change]
2014-05-09 12:34:51 -05:00
|
|
|
use mem;
|
2014-11-24 13:16:40 -06:00
|
|
|
use sync::{StaticMutex, MUTEX_INIT};
|
2014-02-05 17:19:40 -06:00
|
|
|
|
2014-05-05 02:07:49 -05:00
|
|
|
/// As always - iOS on arm uses SjLj exceptions and
|
|
|
|
/// _Unwind_Backtrace is even not available there. Still,
|
|
|
|
/// backtraces could be extracted using a backtrace function,
|
|
|
|
/// which thanks god is public
|
2014-06-13 02:18:12 -05:00
|
|
|
///
|
|
|
|
/// As mentioned in a huge comment block above, backtrace doesn't
|
|
|
|
/// play well with green threads, so while it is extremely nice
|
|
|
|
/// and simple to use it should be used only on iOS devices as the
|
|
|
|
/// only viable option.
|
2014-09-29 00:31:50 -05:00
|
|
|
#[cfg(all(target_os = "ios", target_arch = "arm"))]
|
2014-05-05 02:07:49 -05:00
|
|
|
#[inline(never)]
|
|
|
|
pub fn write(w: &mut Writer) -> IoResult<()> {
|
|
|
|
use result;
|
|
|
|
|
|
|
|
extern {
|
2014-06-30 01:51:58 -05:00
|
|
|
fn backtrace(buf: *mut *mut libc::c_void,
|
2014-06-25 14:47:34 -05:00
|
|
|
sz: libc::c_int) -> libc::c_int;
|
2014-05-05 02:07:49 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// while it doesn't requires lock for work as everything is
|
2014-07-02 20:27:07 -05:00
|
|
|
// local, it still displays much nicer backtraces when a
|
2014-10-09 14:17:22 -05:00
|
|
|
// couple of tasks panic simultaneously
|
2014-11-24 13:16:40 -06:00
|
|
|
static LOCK: StaticMutex = MUTEX_INIT;
|
|
|
|
let _g = LOCK.lock();
|
2014-05-05 02:07:49 -05:00
|
|
|
|
|
|
|
try!(writeln!(w, "stack backtrace:"));
|
|
|
|
// 100 lines should be enough
|
2014-10-09 13:59:03 -05:00
|
|
|
const SIZE: uint = 100;
|
2014-06-30 01:51:58 -05:00
|
|
|
let mut buf: [*mut libc::c_void, ..SIZE] = unsafe {mem::zeroed()};
|
2014-08-21 03:09:23 -05:00
|
|
|
let cnt = unsafe { backtrace(buf.as_mut_ptr(), SIZE as libc::c_int) as uint};
|
2014-05-05 02:07:49 -05:00
|
|
|
|
|
|
|
// skipping the first one as it is write itself
|
2014-09-23 09:36:33 -05:00
|
|
|
let iter = range(1, cnt).map(|i| {
|
2014-05-05 02:07:49 -05:00
|
|
|
print(w, i as int, buf[i])
|
2014-09-23 09:36:33 -05:00
|
|
|
});
|
|
|
|
result::fold(iter, (), |_, _| ())
|
2014-02-05 17:19:40 -06:00
|
|
|
}
|
|
|
|
|
2014-09-29 00:31:50 -05:00
|
|
|
#[cfg(not(all(target_os = "ios", target_arch = "arm")))]
|
2014-02-05 17:19:40 -06:00
|
|
|
#[inline(never)] // if we know this is a function call, we can skip it when
|
|
|
|
// tracing
|
|
|
|
pub fn write(w: &mut Writer) -> IoResult<()> {
|
2014-05-05 02:07:49 -05:00
|
|
|
use io::IoError;
|
|
|
|
|
|
|
|
struct Context<'a> {
|
|
|
|
idx: int,
|
2014-11-20 14:08:02 -06:00
|
|
|
writer: &'a mut (Writer+'a),
|
2014-05-05 02:07:49 -05:00
|
|
|
last_error: Option<IoError>,
|
|
|
|
}
|
|
|
|
|
2014-02-05 17:19:40 -06:00
|
|
|
// When using libbacktrace, we use some necessary global state, so we
|
|
|
|
// need to prevent more than one thread from entering this block. This
|
|
|
|
// is semi-reasonable in terms of printing anyway, and we know that all
|
|
|
|
// I/O done here is blocking I/O, not green I/O, so we don't have to
|
|
|
|
// worry about this being a native vs green mutex.
|
2014-11-24 13:16:40 -06:00
|
|
|
static LOCK: StaticMutex = MUTEX_INIT;
|
|
|
|
let _g = LOCK.lock();
|
2014-02-05 17:19:40 -06:00
|
|
|
|
|
|
|
try!(writeln!(w, "stack backtrace:"));
|
|
|
|
|
|
|
|
let mut cx = Context { writer: w, last_error: None, idx: 0 };
|
|
|
|
return match unsafe {
|
|
|
|
uw::_Unwind_Backtrace(trace_fn,
|
2014-06-25 14:47:34 -05:00
|
|
|
&mut cx as *mut Context as *mut libc::c_void)
|
2014-02-05 17:19:40 -06:00
|
|
|
} {
|
|
|
|
uw::_URC_NO_REASON => {
|
|
|
|
match cx.last_error {
|
|
|
|
Some(err) => Err(err),
|
|
|
|
None => Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => Ok(()),
|
|
|
|
};
|
|
|
|
|
2014-06-25 14:47:34 -05:00
|
|
|
extern fn trace_fn(ctx: *mut uw::_Unwind_Context,
|
|
|
|
arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code {
|
core: Remove the cast module
This commit revisits the `cast` module in libcore and libstd, and scrutinizes
all functions inside of it. The result was to remove the `cast` module entirely,
folding all functionality into the `mem` module. Specifically, this is the fate
of each function in the `cast` module.
* transmute - This function was moved to `mem`, but it is now marked as
#[unstable]. This is due to planned changes to the `transmute`
function and how it can be invoked (see the #[unstable] comment).
For more information, see RFC 5 and #12898
* transmute_copy - This function was moved to `mem`, with clarification that is
is not an error to invoke it with T/U that are different
sizes, but rather that it is strongly discouraged. This
function is now #[stable]
* forget - This function was moved to `mem` and marked #[stable]
* bump_box_refcount - This function was removed due to the deprecation of
managed boxes as well as its questionable utility.
* transmute_mut - This function was previously deprecated, and removed as part
of this commit.
* transmute_mut_unsafe - This function doesn't serve much of a purpose when it
can be achieved with an `as` in safe code, so it was
removed.
* transmute_lifetime - This function was removed because it is likely a strong
indication that code is incorrect in the first place.
* transmute_mut_lifetime - This function was removed for the same reasons as
`transmute_lifetime`
* copy_lifetime - This function was moved to `mem`, but it is marked
`#[unstable]` now due to the likelihood of being removed in
the future if it is found to not be very useful.
* copy_mut_lifetime - This function was also moved to `mem`, but had the same
treatment as `copy_lifetime`.
* copy_lifetime_vec - This function was removed because it is not used today,
and its existence is not necessary with DST
(copy_lifetime will suffice).
In summary, the cast module was stripped down to these functions, and then the
functions were moved to the `mem` module.
transmute - #[unstable]
transmute_copy - #[stable]
forget - #[stable]
copy_lifetime - #[unstable]
copy_mut_lifetime - #[unstable]
[breaking-change]
2014-05-09 12:34:51 -05:00
|
|
|
let cx: &mut Context = unsafe { mem::transmute(arg) };
|
2014-06-25 14:47:34 -05:00
|
|
|
let ip = unsafe { uw::_Unwind_GetIP(ctx) as *mut libc::c_void };
|
2014-02-05 17:19:40 -06:00
|
|
|
// dladdr() on osx gets whiny when we use FindEnclosingFunction, and
|
|
|
|
// it appears to work fine without it, so we only use
|
|
|
|
// FindEnclosingFunction on non-osx platforms. In doing so, we get a
|
|
|
|
// slightly more accurate stack trace in the process.
|
|
|
|
//
|
2014-10-09 14:17:22 -05:00
|
|
|
// This is often because panic involves the last instruction of a
|
2014-02-05 17:19:40 -06:00
|
|
|
// function being "call std::rt::begin_unwind", with no ret
|
|
|
|
// instructions after it. This means that the return instruction
|
|
|
|
// pointer points *outside* of the calling function, and by
|
|
|
|
// unwinding it we go back to the original function.
|
2014-05-05 02:07:49 -05:00
|
|
|
let ip = if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
|
2014-02-05 17:19:40 -06:00
|
|
|
ip
|
|
|
|
} else {
|
|
|
|
unsafe { uw::_Unwind_FindEnclosingFunction(ip) }
|
|
|
|
};
|
|
|
|
|
|
|
|
// Don't print out the first few frames (they're not user frames)
|
|
|
|
cx.idx += 1;
|
|
|
|
if cx.idx <= 0 { return uw::_URC_NO_REASON }
|
|
|
|
// Don't print ginormous backtraces
|
|
|
|
if cx.idx > 100 {
|
|
|
|
match write!(cx.writer, " ... <frames omitted>\n") {
|
|
|
|
Ok(()) => {}
|
|
|
|
Err(e) => { cx.last_error = Some(e); }
|
|
|
|
}
|
|
|
|
return uw::_URC_FAILURE
|
|
|
|
}
|
|
|
|
|
|
|
|
// Once we hit an error, stop trying to print more frames
|
|
|
|
if cx.last_error.is_some() { return uw::_URC_FAILURE }
|
|
|
|
|
|
|
|
match print(cx.writer, cx.idx, ip) {
|
|
|
|
Ok(()) => {}
|
|
|
|
Err(e) => { cx.last_error = Some(e); }
|
|
|
|
}
|
|
|
|
|
|
|
|
// keep going
|
|
|
|
return uw::_URC_NO_REASON
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-29 00:31:50 -05:00
|
|
|
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
2014-06-25 14:47:34 -05:00
|
|
|
fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> {
|
2014-02-05 17:19:40 -06:00
|
|
|
use intrinsics;
|
2014-06-06 08:51:42 -05:00
|
|
|
#[repr(C)]
|
2014-02-05 17:19:40 -06:00
|
|
|
struct Dl_info {
|
2014-06-25 14:47:34 -05:00
|
|
|
dli_fname: *const libc::c_char,
|
|
|
|
dli_fbase: *mut libc::c_void,
|
|
|
|
dli_sname: *const libc::c_char,
|
|
|
|
dli_saddr: *mut libc::c_void,
|
2014-02-05 17:19:40 -06:00
|
|
|
}
|
|
|
|
extern {
|
2014-06-25 14:47:34 -05:00
|
|
|
fn dladdr(addr: *const libc::c_void,
|
2014-02-05 17:19:40 -06:00
|
|
|
info: *mut Dl_info) -> libc::c_int;
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut info: Dl_info = unsafe { intrinsics::init() };
|
2014-06-25 14:47:34 -05:00
|
|
|
if unsafe { dladdr(addr as *const libc::c_void, &mut info) == 0 } {
|
2014-02-05 17:19:40 -06:00
|
|
|
output(w, idx,addr, None)
|
|
|
|
} else {
|
|
|
|
output(w, idx, addr, Some(unsafe {
|
|
|
|
CString::new(info.dli_sname, false)
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-29 00:31:50 -05:00
|
|
|
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
|
2014-06-25 14:47:34 -05:00
|
|
|
fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> {
|
2014-02-05 17:19:40 -06:00
|
|
|
use os;
|
|
|
|
use ptr;
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
// libbacktrace.h API
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
type backtrace_syminfo_callback =
|
|
|
|
extern "C" fn(data: *mut libc::c_void,
|
|
|
|
pc: libc::uintptr_t,
|
2014-06-25 14:47:34 -05:00
|
|
|
symname: *const libc::c_char,
|
2014-02-05 17:19:40 -06:00
|
|
|
symval: libc::uintptr_t,
|
|
|
|
symsize: libc::uintptr_t);
|
|
|
|
type backtrace_error_callback =
|
|
|
|
extern "C" fn(data: *mut libc::c_void,
|
2014-06-25 14:47:34 -05:00
|
|
|
msg: *const libc::c_char,
|
2014-02-05 17:19:40 -06:00
|
|
|
errnum: libc::c_int);
|
|
|
|
enum backtrace_state {}
|
|
|
|
#[link(name = "backtrace", kind = "static")]
|
2014-07-30 09:44:20 -05:00
|
|
|
#[cfg(not(test))]
|
|
|
|
extern {}
|
|
|
|
|
2014-02-05 17:19:40 -06:00
|
|
|
extern {
|
2014-06-25 14:47:34 -05:00
|
|
|
fn backtrace_create_state(filename: *const libc::c_char,
|
2014-02-05 17:19:40 -06:00
|
|
|
threaded: libc::c_int,
|
|
|
|
error: backtrace_error_callback,
|
|
|
|
data: *mut libc::c_void)
|
|
|
|
-> *mut backtrace_state;
|
|
|
|
fn backtrace_syminfo(state: *mut backtrace_state,
|
|
|
|
addr: libc::uintptr_t,
|
|
|
|
cb: backtrace_syminfo_callback,
|
|
|
|
error: backtrace_error_callback,
|
|
|
|
data: *mut libc::c_void) -> libc::c_int;
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
// helper callbacks
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2014-06-25 14:47:34 -05:00
|
|
|
extern fn error_cb(_data: *mut libc::c_void, _msg: *const libc::c_char,
|
2014-02-05 17:19:40 -06:00
|
|
|
_errnum: libc::c_int) {
|
|
|
|
// do nothing for now
|
|
|
|
}
|
|
|
|
extern fn syminfo_cb(data: *mut libc::c_void,
|
|
|
|
_pc: libc::uintptr_t,
|
2014-06-25 14:47:34 -05:00
|
|
|
symname: *const libc::c_char,
|
2014-02-05 17:19:40 -06:00
|
|
|
_symval: libc::uintptr_t,
|
|
|
|
_symsize: libc::uintptr_t) {
|
2014-06-25 14:47:34 -05:00
|
|
|
let slot = data as *mut *const libc::c_char;
|
2014-02-05 17:19:40 -06:00
|
|
|
unsafe { *slot = symname; }
|
|
|
|
}
|
|
|
|
|
|
|
|
// The libbacktrace API supports creating a state, but it does not
|
|
|
|
// support destroying a state. I personally take this to mean that a
|
|
|
|
// state is meant to be created and then live forever.
|
|
|
|
//
|
|
|
|
// I would love to register an at_exit() handler which cleans up this
|
|
|
|
// state, but libbacktrace provides no way to do so.
|
|
|
|
//
|
|
|
|
// With these constraints, this function has a statically cached state
|
|
|
|
// that is calculated the first time this is requested. Remember that
|
|
|
|
// backtracing all happens serially (one global lock).
|
|
|
|
//
|
|
|
|
// An additionally oddity in this function is that we initialize the
|
|
|
|
// filename via self_exe_name() to pass to libbacktrace. It turns out
|
2014-09-02 00:35:58 -05:00
|
|
|
// that on Linux libbacktrace seamlessly gets the filename of the
|
2014-02-05 17:19:40 -06:00
|
|
|
// current executable, but this fails on freebsd. by always providing
|
|
|
|
// it, we make sure that libbacktrace never has a reason to not look up
|
|
|
|
// the symbols. The libbacktrace API also states that the filename must
|
|
|
|
// be in "permanent memory", so we copy it to a static and then use the
|
|
|
|
// static as the pointer.
|
2014-07-29 09:44:39 -05:00
|
|
|
//
|
2014-07-30 19:01:16 -05:00
|
|
|
// FIXME: We also call self_exe_name() on DragonFly BSD. I haven't
|
2014-07-29 09:44:39 -05:00
|
|
|
// tested if this is required or not.
|
2014-02-05 17:19:40 -06:00
|
|
|
unsafe fn init_state() -> *mut backtrace_state {
|
|
|
|
static mut STATE: *mut backtrace_state = 0 as *mut backtrace_state;
|
|
|
|
static mut LAST_FILENAME: [libc::c_char, ..256] = [0, ..256];
|
|
|
|
if !STATE.is_null() { return STATE }
|
2014-07-30 19:01:16 -05:00
|
|
|
let selfname = if cfg!(target_os = "freebsd") ||
|
2014-07-29 09:44:39 -05:00
|
|
|
cfg!(target_os = "dragonfly") {
|
2014-02-05 17:19:40 -06:00
|
|
|
os::self_exe_name()
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
let filename = match selfname {
|
|
|
|
Some(path) => {
|
|
|
|
let bytes = path.as_vec();
|
|
|
|
if bytes.len() < LAST_FILENAME.len() {
|
|
|
|
let i = bytes.iter();
|
2014-09-14 22:27:36 -05:00
|
|
|
for (slot, val) in LAST_FILENAME.iter_mut().zip(i) {
|
2014-02-05 17:19:40 -06:00
|
|
|
*slot = *val as libc::c_char;
|
|
|
|
}
|
|
|
|
LAST_FILENAME.as_ptr()
|
|
|
|
} else {
|
|
|
|
ptr::null()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None => ptr::null(),
|
|
|
|
};
|
|
|
|
STATE = backtrace_create_state(filename, 0, error_cb,
|
2014-09-14 22:27:36 -05:00
|
|
|
ptr::null_mut());
|
2014-02-05 17:19:40 -06:00
|
|
|
return STATE
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
// translation
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// backtrace errors are currently swept under the rug, only I/O
|
|
|
|
// errors are reported
|
|
|
|
let state = unsafe { init_state() };
|
|
|
|
if state.is_null() {
|
|
|
|
return output(w, idx, addr, None)
|
|
|
|
}
|
2014-06-25 14:47:34 -05:00
|
|
|
let mut data = 0 as *const libc::c_char;
|
|
|
|
let data_addr = &mut data as *mut *const libc::c_char;
|
2014-02-05 17:19:40 -06:00
|
|
|
let ret = unsafe {
|
|
|
|
backtrace_syminfo(state, addr as libc::uintptr_t,
|
|
|
|
syminfo_cb, error_cb,
|
|
|
|
data_addr as *mut libc::c_void)
|
|
|
|
};
|
|
|
|
if ret == 0 || data.is_null() {
|
|
|
|
output(w, idx, addr, None)
|
|
|
|
} else {
|
|
|
|
output(w, idx, addr, Some(unsafe { CString::new(data, false) }))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Finally, after all that work above, we can emit a symbol.
|
2014-06-25 14:47:34 -05:00
|
|
|
fn output(w: &mut Writer, idx: int, addr: *mut libc::c_void,
|
2014-02-05 17:19:40 -06:00
|
|
|
s: Option<CString>) -> IoResult<()> {
|
|
|
|
try!(write!(w, " {:2}: {:2$} - ", idx, addr, super::HEX_WIDTH));
|
|
|
|
match s.as_ref().and_then(|c| c.as_str()) {
|
|
|
|
Some(string) => try!(super::demangle(w, string)),
|
|
|
|
None => try!(write!(w, "<unknown>")),
|
|
|
|
}
|
2014-11-17 02:39:01 -06:00
|
|
|
w.write(&['\n' as u8])
|
2014-02-05 17:19:40 -06:00
|
|
|
}
|
std: Extract librustrt out of libstd
As part of the libstd facade efforts, this commit extracts the runtime interface
out of the standard library into a standalone crate, librustrt. This crate will
provide the following services:
* Definition of the rtio interface
* Definition of the Runtime interface
* Implementation of the Task structure
* Implementation of task-local-data
* Implementation of task failure via unwinding via libunwind
* Implementation of runtime initialization and shutdown
* Implementation of thread-local-storage for the local rust Task
Notably, this crate avoids the following services:
* Thread creation and destruction. The crate does not require the knowledge of
an OS threading system, and as a result it seemed best to leave out the
`rt::thread` module from librustrt. The librustrt module does depend on
mutexes, however.
* Implementation of backtraces. There is no inherent requirement for the runtime
to be able to generate backtraces. As will be discussed later, this
functionality continues to live in libstd rather than librustrt.
As usual, a number of architectural changes were required to make this crate
possible. Users of "stable" functionality will not be impacted by this change,
but users of the `std::rt` module will likely note the changes. A list of
architectural changes made is:
* The stdout/stderr handles no longer live directly inside of the `Task`
structure. This is a consequence of librustrt not knowing about `std::io`.
These two handles are now stored inside of task-local-data.
The handles were originally stored inside of the `Task` for perf reasons, and
TLD is not currently as fast as it could be. For comparison, 100k prints goes
from 59ms to 68ms (a 15% slowdown). This appeared to me to be an acceptable
perf loss for the successful extraction of a librustrt crate.
* The `rtio` module was forced to duplicate more functionality of `std::io`. As
the module no longer depends on `std::io`, `rtio` now defines structures such
as socket addresses, addrinfo fiddly bits, etc. The primary change made was
that `rtio` now defines its own `IoError` type. This type is distinct from
`std::io::IoError` in that it does not have an enum for what error occurred,
but rather a platform-specific error code.
The native and green libraries will be updated in later commits for this
change, and the bulk of this effort was put behind updating the two libraries
for this change (with `rtio`).
* Printing a message on task failure (along with the backtrace) continues to
live in libstd, not in librustrt. This is a consequence of the above decision
to move the stdout/stderr handles to TLD rather than inside the `Task` itself.
The unwinding API now supports registration of global callback functions which
will be invoked when a task fails, allowing for libstd to register a function
to print a message and a backtrace.
The API for registering a callback is experimental and unsafe, as the
ramifications of running code on unwinding is pretty hairy.
* The `std::unstable::mutex` module has moved to `std::rt::mutex`.
* The `std::unstable::sync` module has been moved to `std::rt::exclusive` and
the type has been rewritten to not internally have an Arc and to have an RAII
guard structure when locking. Old code should stop using `Exclusive` in favor
of the primitives in `libsync`, but if necessary, old code should port to
`Arc<Exclusive<T>>`.
* The local heap has been stripped down to have fewer debugging options. None of
these were tested, and none of these have been used in a very long time.
[breaking-change]
2014-06-03 21:11:49 -05:00
|
|
|
|
|
|
|
/// Unwind library interface used for backtraces
|
|
|
|
///
|
2014-05-05 02:07:49 -05:00
|
|
|
/// Note that the native libraries come from librustrt, not this
|
|
|
|
/// module.
|
|
|
|
/// Note that dead code is allowed as here are just bindings
|
|
|
|
/// iOS doesn't use all of them it but adding more
|
|
|
|
/// platform-specific configs pollutes the code too much
|
std: Extract librustrt out of libstd
As part of the libstd facade efforts, this commit extracts the runtime interface
out of the standard library into a standalone crate, librustrt. This crate will
provide the following services:
* Definition of the rtio interface
* Definition of the Runtime interface
* Implementation of the Task structure
* Implementation of task-local-data
* Implementation of task failure via unwinding via libunwind
* Implementation of runtime initialization and shutdown
* Implementation of thread-local-storage for the local rust Task
Notably, this crate avoids the following services:
* Thread creation and destruction. The crate does not require the knowledge of
an OS threading system, and as a result it seemed best to leave out the
`rt::thread` module from librustrt. The librustrt module does depend on
mutexes, however.
* Implementation of backtraces. There is no inherent requirement for the runtime
to be able to generate backtraces. As will be discussed later, this
functionality continues to live in libstd rather than librustrt.
As usual, a number of architectural changes were required to make this crate
possible. Users of "stable" functionality will not be impacted by this change,
but users of the `std::rt` module will likely note the changes. A list of
architectural changes made is:
* The stdout/stderr handles no longer live directly inside of the `Task`
structure. This is a consequence of librustrt not knowing about `std::io`.
These two handles are now stored inside of task-local-data.
The handles were originally stored inside of the `Task` for perf reasons, and
TLD is not currently as fast as it could be. For comparison, 100k prints goes
from 59ms to 68ms (a 15% slowdown). This appeared to me to be an acceptable
perf loss for the successful extraction of a librustrt crate.
* The `rtio` module was forced to duplicate more functionality of `std::io`. As
the module no longer depends on `std::io`, `rtio` now defines structures such
as socket addresses, addrinfo fiddly bits, etc. The primary change made was
that `rtio` now defines its own `IoError` type. This type is distinct from
`std::io::IoError` in that it does not have an enum for what error occurred,
but rather a platform-specific error code.
The native and green libraries will be updated in later commits for this
change, and the bulk of this effort was put behind updating the two libraries
for this change (with `rtio`).
* Printing a message on task failure (along with the backtrace) continues to
live in libstd, not in librustrt. This is a consequence of the above decision
to move the stdout/stderr handles to TLD rather than inside the `Task` itself.
The unwinding API now supports registration of global callback functions which
will be invoked when a task fails, allowing for libstd to register a function
to print a message and a backtrace.
The API for registering a callback is experimental and unsafe, as the
ramifications of running code on unwinding is pretty hairy.
* The `std::unstable::mutex` module has moved to `std::rt::mutex`.
* The `std::unstable::sync` module has been moved to `std::rt::exclusive` and
the type has been rewritten to not internally have an Arc and to have an RAII
guard structure when locking. Old code should stop using `Exclusive` in favor
of the primitives in `libsync`, but if necessary, old code should port to
`Arc<Exclusive<T>>`.
* The local heap has been stripped down to have fewer debugging options. None of
these were tested, and none of these have been used in a very long time.
[breaking-change]
2014-06-03 21:11:49 -05:00
|
|
|
#[allow(non_camel_case_types)]
|
2014-07-18 07:45:17 -05:00
|
|
|
#[allow(non_snake_case)]
|
2014-05-05 02:07:49 -05:00
|
|
|
#[allow(dead_code)]
|
std: Extract librustrt out of libstd
As part of the libstd facade efforts, this commit extracts the runtime interface
out of the standard library into a standalone crate, librustrt. This crate will
provide the following services:
* Definition of the rtio interface
* Definition of the Runtime interface
* Implementation of the Task structure
* Implementation of task-local-data
* Implementation of task failure via unwinding via libunwind
* Implementation of runtime initialization and shutdown
* Implementation of thread-local-storage for the local rust Task
Notably, this crate avoids the following services:
* Thread creation and destruction. The crate does not require the knowledge of
an OS threading system, and as a result it seemed best to leave out the
`rt::thread` module from librustrt. The librustrt module does depend on
mutexes, however.
* Implementation of backtraces. There is no inherent requirement for the runtime
to be able to generate backtraces. As will be discussed later, this
functionality continues to live in libstd rather than librustrt.
As usual, a number of architectural changes were required to make this crate
possible. Users of "stable" functionality will not be impacted by this change,
but users of the `std::rt` module will likely note the changes. A list of
architectural changes made is:
* The stdout/stderr handles no longer live directly inside of the `Task`
structure. This is a consequence of librustrt not knowing about `std::io`.
These two handles are now stored inside of task-local-data.
The handles were originally stored inside of the `Task` for perf reasons, and
TLD is not currently as fast as it could be. For comparison, 100k prints goes
from 59ms to 68ms (a 15% slowdown). This appeared to me to be an acceptable
perf loss for the successful extraction of a librustrt crate.
* The `rtio` module was forced to duplicate more functionality of `std::io`. As
the module no longer depends on `std::io`, `rtio` now defines structures such
as socket addresses, addrinfo fiddly bits, etc. The primary change made was
that `rtio` now defines its own `IoError` type. This type is distinct from
`std::io::IoError` in that it does not have an enum for what error occurred,
but rather a platform-specific error code.
The native and green libraries will be updated in later commits for this
change, and the bulk of this effort was put behind updating the two libraries
for this change (with `rtio`).
* Printing a message on task failure (along with the backtrace) continues to
live in libstd, not in librustrt. This is a consequence of the above decision
to move the stdout/stderr handles to TLD rather than inside the `Task` itself.
The unwinding API now supports registration of global callback functions which
will be invoked when a task fails, allowing for libstd to register a function
to print a message and a backtrace.
The API for registering a callback is experimental and unsafe, as the
ramifications of running code on unwinding is pretty hairy.
* The `std::unstable::mutex` module has moved to `std::rt::mutex`.
* The `std::unstable::sync` module has been moved to `std::rt::exclusive` and
the type has been rewritten to not internally have an Arc and to have an RAII
guard structure when locking. Old code should stop using `Exclusive` in favor
of the primitives in `libsync`, but if necessary, old code should port to
`Arc<Exclusive<T>>`.
* The local heap has been stripped down to have fewer debugging options. None of
these were tested, and none of these have been used in a very long time.
[breaking-change]
2014-06-03 21:11:49 -05:00
|
|
|
mod uw {
|
2014-11-06 02:05:53 -06:00
|
|
|
pub use self::_Unwind_Reason_Code::*;
|
|
|
|
|
std: Extract librustrt out of libstd
As part of the libstd facade efforts, this commit extracts the runtime interface
out of the standard library into a standalone crate, librustrt. This crate will
provide the following services:
* Definition of the rtio interface
* Definition of the Runtime interface
* Implementation of the Task structure
* Implementation of task-local-data
* Implementation of task failure via unwinding via libunwind
* Implementation of runtime initialization and shutdown
* Implementation of thread-local-storage for the local rust Task
Notably, this crate avoids the following services:
* Thread creation and destruction. The crate does not require the knowledge of
an OS threading system, and as a result it seemed best to leave out the
`rt::thread` module from librustrt. The librustrt module does depend on
mutexes, however.
* Implementation of backtraces. There is no inherent requirement for the runtime
to be able to generate backtraces. As will be discussed later, this
functionality continues to live in libstd rather than librustrt.
As usual, a number of architectural changes were required to make this crate
possible. Users of "stable" functionality will not be impacted by this change,
but users of the `std::rt` module will likely note the changes. A list of
architectural changes made is:
* The stdout/stderr handles no longer live directly inside of the `Task`
structure. This is a consequence of librustrt not knowing about `std::io`.
These two handles are now stored inside of task-local-data.
The handles were originally stored inside of the `Task` for perf reasons, and
TLD is not currently as fast as it could be. For comparison, 100k prints goes
from 59ms to 68ms (a 15% slowdown). This appeared to me to be an acceptable
perf loss for the successful extraction of a librustrt crate.
* The `rtio` module was forced to duplicate more functionality of `std::io`. As
the module no longer depends on `std::io`, `rtio` now defines structures such
as socket addresses, addrinfo fiddly bits, etc. The primary change made was
that `rtio` now defines its own `IoError` type. This type is distinct from
`std::io::IoError` in that it does not have an enum for what error occurred,
but rather a platform-specific error code.
The native and green libraries will be updated in later commits for this
change, and the bulk of this effort was put behind updating the two libraries
for this change (with `rtio`).
* Printing a message on task failure (along with the backtrace) continues to
live in libstd, not in librustrt. This is a consequence of the above decision
to move the stdout/stderr handles to TLD rather than inside the `Task` itself.
The unwinding API now supports registration of global callback functions which
will be invoked when a task fails, allowing for libstd to register a function
to print a message and a backtrace.
The API for registering a callback is experimental and unsafe, as the
ramifications of running code on unwinding is pretty hairy.
* The `std::unstable::mutex` module has moved to `std::rt::mutex`.
* The `std::unstable::sync` module has been moved to `std::rt::exclusive` and
the type has been rewritten to not internally have an Arc and to have an RAII
guard structure when locking. Old code should stop using `Exclusive` in favor
of the primitives in `libsync`, but if necessary, old code should port to
`Arc<Exclusive<T>>`.
* The local heap has been stripped down to have fewer debugging options. None of
these were tested, and none of these have been used in a very long time.
[breaking-change]
2014-06-03 21:11:49 -05:00
|
|
|
use libc;
|
|
|
|
|
|
|
|
#[repr(C)]
|
|
|
|
pub enum _Unwind_Reason_Code {
|
|
|
|
_URC_NO_REASON = 0,
|
|
|
|
_URC_FOREIGN_EXCEPTION_CAUGHT = 1,
|
|
|
|
_URC_FATAL_PHASE2_ERROR = 2,
|
|
|
|
_URC_FATAL_PHASE1_ERROR = 3,
|
|
|
|
_URC_NORMAL_STOP = 4,
|
|
|
|
_URC_END_OF_STACK = 5,
|
|
|
|
_URC_HANDLER_FOUND = 6,
|
|
|
|
_URC_INSTALL_CONTEXT = 7,
|
|
|
|
_URC_CONTINUE_UNWIND = 8,
|
|
|
|
_URC_FAILURE = 9, // used only by ARM EABI
|
|
|
|
}
|
|
|
|
|
|
|
|
pub enum _Unwind_Context {}
|
|
|
|
|
|
|
|
pub type _Unwind_Trace_Fn =
|
2014-06-25 14:47:34 -05:00
|
|
|
extern fn(ctx: *mut _Unwind_Context,
|
|
|
|
arg: *mut libc::c_void) -> _Unwind_Reason_Code;
|
std: Extract librustrt out of libstd
As part of the libstd facade efforts, this commit extracts the runtime interface
out of the standard library into a standalone crate, librustrt. This crate will
provide the following services:
* Definition of the rtio interface
* Definition of the Runtime interface
* Implementation of the Task structure
* Implementation of task-local-data
* Implementation of task failure via unwinding via libunwind
* Implementation of runtime initialization and shutdown
* Implementation of thread-local-storage for the local rust Task
Notably, this crate avoids the following services:
* Thread creation and destruction. The crate does not require the knowledge of
an OS threading system, and as a result it seemed best to leave out the
`rt::thread` module from librustrt. The librustrt module does depend on
mutexes, however.
* Implementation of backtraces. There is no inherent requirement for the runtime
to be able to generate backtraces. As will be discussed later, this
functionality continues to live in libstd rather than librustrt.
As usual, a number of architectural changes were required to make this crate
possible. Users of "stable" functionality will not be impacted by this change,
but users of the `std::rt` module will likely note the changes. A list of
architectural changes made is:
* The stdout/stderr handles no longer live directly inside of the `Task`
structure. This is a consequence of librustrt not knowing about `std::io`.
These two handles are now stored inside of task-local-data.
The handles were originally stored inside of the `Task` for perf reasons, and
TLD is not currently as fast as it could be. For comparison, 100k prints goes
from 59ms to 68ms (a 15% slowdown). This appeared to me to be an acceptable
perf loss for the successful extraction of a librustrt crate.
* The `rtio` module was forced to duplicate more functionality of `std::io`. As
the module no longer depends on `std::io`, `rtio` now defines structures such
as socket addresses, addrinfo fiddly bits, etc. The primary change made was
that `rtio` now defines its own `IoError` type. This type is distinct from
`std::io::IoError` in that it does not have an enum for what error occurred,
but rather a platform-specific error code.
The native and green libraries will be updated in later commits for this
change, and the bulk of this effort was put behind updating the two libraries
for this change (with `rtio`).
* Printing a message on task failure (along with the backtrace) continues to
live in libstd, not in librustrt. This is a consequence of the above decision
to move the stdout/stderr handles to TLD rather than inside the `Task` itself.
The unwinding API now supports registration of global callback functions which
will be invoked when a task fails, allowing for libstd to register a function
to print a message and a backtrace.
The API for registering a callback is experimental and unsafe, as the
ramifications of running code on unwinding is pretty hairy.
* The `std::unstable::mutex` module has moved to `std::rt::mutex`.
* The `std::unstable::sync` module has been moved to `std::rt::exclusive` and
the type has been rewritten to not internally have an Arc and to have an RAII
guard structure when locking. Old code should stop using `Exclusive` in favor
of the primitives in `libsync`, but if necessary, old code should port to
`Arc<Exclusive<T>>`.
* The local heap has been stripped down to have fewer debugging options. None of
these were tested, and none of these have been used in a very long time.
[breaking-change]
2014-06-03 21:11:49 -05:00
|
|
|
|
|
|
|
extern {
|
2014-05-05 02:07:49 -05:00
|
|
|
// No native _Unwind_Backtrace on iOS
|
2014-09-29 00:31:50 -05:00
|
|
|
#[cfg(not(all(target_os = "ios", target_arch = "arm")))]
|
std: Extract librustrt out of libstd
As part of the libstd facade efforts, this commit extracts the runtime interface
out of the standard library into a standalone crate, librustrt. This crate will
provide the following services:
* Definition of the rtio interface
* Definition of the Runtime interface
* Implementation of the Task structure
* Implementation of task-local-data
* Implementation of task failure via unwinding via libunwind
* Implementation of runtime initialization and shutdown
* Implementation of thread-local-storage for the local rust Task
Notably, this crate avoids the following services:
* Thread creation and destruction. The crate does not require the knowledge of
an OS threading system, and as a result it seemed best to leave out the
`rt::thread` module from librustrt. The librustrt module does depend on
mutexes, however.
* Implementation of backtraces. There is no inherent requirement for the runtime
to be able to generate backtraces. As will be discussed later, this
functionality continues to live in libstd rather than librustrt.
As usual, a number of architectural changes were required to make this crate
possible. Users of "stable" functionality will not be impacted by this change,
but users of the `std::rt` module will likely note the changes. A list of
architectural changes made is:
* The stdout/stderr handles no longer live directly inside of the `Task`
structure. This is a consequence of librustrt not knowing about `std::io`.
These two handles are now stored inside of task-local-data.
The handles were originally stored inside of the `Task` for perf reasons, and
TLD is not currently as fast as it could be. For comparison, 100k prints goes
from 59ms to 68ms (a 15% slowdown). This appeared to me to be an acceptable
perf loss for the successful extraction of a librustrt crate.
* The `rtio` module was forced to duplicate more functionality of `std::io`. As
the module no longer depends on `std::io`, `rtio` now defines structures such
as socket addresses, addrinfo fiddly bits, etc. The primary change made was
that `rtio` now defines its own `IoError` type. This type is distinct from
`std::io::IoError` in that it does not have an enum for what error occurred,
but rather a platform-specific error code.
The native and green libraries will be updated in later commits for this
change, and the bulk of this effort was put behind updating the two libraries
for this change (with `rtio`).
* Printing a message on task failure (along with the backtrace) continues to
live in libstd, not in librustrt. This is a consequence of the above decision
to move the stdout/stderr handles to TLD rather than inside the `Task` itself.
The unwinding API now supports registration of global callback functions which
will be invoked when a task fails, allowing for libstd to register a function
to print a message and a backtrace.
The API for registering a callback is experimental and unsafe, as the
ramifications of running code on unwinding is pretty hairy.
* The `std::unstable::mutex` module has moved to `std::rt::mutex`.
* The `std::unstable::sync` module has been moved to `std::rt::exclusive` and
the type has been rewritten to not internally have an Arc and to have an RAII
guard structure when locking. Old code should stop using `Exclusive` in favor
of the primitives in `libsync`, but if necessary, old code should port to
`Arc<Exclusive<T>>`.
* The local heap has been stripped down to have fewer debugging options. None of
these were tested, and none of these have been used in a very long time.
[breaking-change]
2014-06-03 21:11:49 -05:00
|
|
|
pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn,
|
2014-06-25 14:47:34 -05:00
|
|
|
trace_argument: *mut libc::c_void)
|
std: Extract librustrt out of libstd
As part of the libstd facade efforts, this commit extracts the runtime interface
out of the standard library into a standalone crate, librustrt. This crate will
provide the following services:
* Definition of the rtio interface
* Definition of the Runtime interface
* Implementation of the Task structure
* Implementation of task-local-data
* Implementation of task failure via unwinding via libunwind
* Implementation of runtime initialization and shutdown
* Implementation of thread-local-storage for the local rust Task
Notably, this crate avoids the following services:
* Thread creation and destruction. The crate does not require the knowledge of
an OS threading system, and as a result it seemed best to leave out the
`rt::thread` module from librustrt. The librustrt module does depend on
mutexes, however.
* Implementation of backtraces. There is no inherent requirement for the runtime
to be able to generate backtraces. As will be discussed later, this
functionality continues to live in libstd rather than librustrt.
As usual, a number of architectural changes were required to make this crate
possible. Users of "stable" functionality will not be impacted by this change,
but users of the `std::rt` module will likely note the changes. A list of
architectural changes made is:
* The stdout/stderr handles no longer live directly inside of the `Task`
structure. This is a consequence of librustrt not knowing about `std::io`.
These two handles are now stored inside of task-local-data.
The handles were originally stored inside of the `Task` for perf reasons, and
TLD is not currently as fast as it could be. For comparison, 100k prints goes
from 59ms to 68ms (a 15% slowdown). This appeared to me to be an acceptable
perf loss for the successful extraction of a librustrt crate.
* The `rtio` module was forced to duplicate more functionality of `std::io`. As
the module no longer depends on `std::io`, `rtio` now defines structures such
as socket addresses, addrinfo fiddly bits, etc. The primary change made was
that `rtio` now defines its own `IoError` type. This type is distinct from
`std::io::IoError` in that it does not have an enum for what error occurred,
but rather a platform-specific error code.
The native and green libraries will be updated in later commits for this
change, and the bulk of this effort was put behind updating the two libraries
for this change (with `rtio`).
* Printing a message on task failure (along with the backtrace) continues to
live in libstd, not in librustrt. This is a consequence of the above decision
to move the stdout/stderr handles to TLD rather than inside the `Task` itself.
The unwinding API now supports registration of global callback functions which
will be invoked when a task fails, allowing for libstd to register a function
to print a message and a backtrace.
The API for registering a callback is experimental and unsafe, as the
ramifications of running code on unwinding is pretty hairy.
* The `std::unstable::mutex` module has moved to `std::rt::mutex`.
* The `std::unstable::sync` module has been moved to `std::rt::exclusive` and
the type has been rewritten to not internally have an Arc and to have an RAII
guard structure when locking. Old code should stop using `Exclusive` in favor
of the primitives in `libsync`, but if necessary, old code should port to
`Arc<Exclusive<T>>`.
* The local heap has been stripped down to have fewer debugging options. None of
these were tested, and none of these have been used in a very long time.
[breaking-change]
2014-06-03 21:11:49 -05:00
|
|
|
-> _Unwind_Reason_Code;
|
|
|
|
|
2014-09-29 00:31:50 -05:00
|
|
|
#[cfg(all(not(target_os = "android"),
|
|
|
|
not(all(target_os = "linux", target_arch = "arm"))))]
|
2014-06-25 14:47:34 -05:00
|
|
|
pub fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> libc::uintptr_t;
|
2014-09-29 00:31:50 -05:00
|
|
|
|
|
|
|
#[cfg(all(not(target_os = "android"),
|
|
|
|
not(all(target_os = "linux", target_arch = "arm"))))]
|
2014-06-25 14:47:34 -05:00
|
|
|
pub fn _Unwind_FindEnclosingFunction(pc: *mut libc::c_void)
|
|
|
|
-> *mut libc::c_void;
|
std: Extract librustrt out of libstd
As part of the libstd facade efforts, this commit extracts the runtime interface
out of the standard library into a standalone crate, librustrt. This crate will
provide the following services:
* Definition of the rtio interface
* Definition of the Runtime interface
* Implementation of the Task structure
* Implementation of task-local-data
* Implementation of task failure via unwinding via libunwind
* Implementation of runtime initialization and shutdown
* Implementation of thread-local-storage for the local rust Task
Notably, this crate avoids the following services:
* Thread creation and destruction. The crate does not require the knowledge of
an OS threading system, and as a result it seemed best to leave out the
`rt::thread` module from librustrt. The librustrt module does depend on
mutexes, however.
* Implementation of backtraces. There is no inherent requirement for the runtime
to be able to generate backtraces. As will be discussed later, this
functionality continues to live in libstd rather than librustrt.
As usual, a number of architectural changes were required to make this crate
possible. Users of "stable" functionality will not be impacted by this change,
but users of the `std::rt` module will likely note the changes. A list of
architectural changes made is:
* The stdout/stderr handles no longer live directly inside of the `Task`
structure. This is a consequence of librustrt not knowing about `std::io`.
These two handles are now stored inside of task-local-data.
The handles were originally stored inside of the `Task` for perf reasons, and
TLD is not currently as fast as it could be. For comparison, 100k prints goes
from 59ms to 68ms (a 15% slowdown). This appeared to me to be an acceptable
perf loss for the successful extraction of a librustrt crate.
* The `rtio` module was forced to duplicate more functionality of `std::io`. As
the module no longer depends on `std::io`, `rtio` now defines structures such
as socket addresses, addrinfo fiddly bits, etc. The primary change made was
that `rtio` now defines its own `IoError` type. This type is distinct from
`std::io::IoError` in that it does not have an enum for what error occurred,
but rather a platform-specific error code.
The native and green libraries will be updated in later commits for this
change, and the bulk of this effort was put behind updating the two libraries
for this change (with `rtio`).
* Printing a message on task failure (along with the backtrace) continues to
live in libstd, not in librustrt. This is a consequence of the above decision
to move the stdout/stderr handles to TLD rather than inside the `Task` itself.
The unwinding API now supports registration of global callback functions which
will be invoked when a task fails, allowing for libstd to register a function
to print a message and a backtrace.
The API for registering a callback is experimental and unsafe, as the
ramifications of running code on unwinding is pretty hairy.
* The `std::unstable::mutex` module has moved to `std::rt::mutex`.
* The `std::unstable::sync` module has been moved to `std::rt::exclusive` and
the type has been rewritten to not internally have an Arc and to have an RAII
guard structure when locking. Old code should stop using `Exclusive` in favor
of the primitives in `libsync`, but if necessary, old code should port to
`Arc<Exclusive<T>>`.
* The local heap has been stripped down to have fewer debugging options. None of
these were tested, and none of these have been used in a very long time.
[breaking-change]
2014-06-03 21:11:49 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// On android, the function _Unwind_GetIP is a macro, and this is the
|
|
|
|
// expansion of the macro. This is all copy/pasted directly from the
|
|
|
|
// header file with the definition of _Unwind_GetIP.
|
2014-09-29 00:31:50 -05:00
|
|
|
#[cfg(any(target_os = "android",
|
|
|
|
all(target_os = "linux", target_arch = "arm")))]
|
2014-06-25 14:47:34 -05:00
|
|
|
pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> libc::uintptr_t {
|
std: Extract librustrt out of libstd
As part of the libstd facade efforts, this commit extracts the runtime interface
out of the standard library into a standalone crate, librustrt. This crate will
provide the following services:
* Definition of the rtio interface
* Definition of the Runtime interface
* Implementation of the Task structure
* Implementation of task-local-data
* Implementation of task failure via unwinding via libunwind
* Implementation of runtime initialization and shutdown
* Implementation of thread-local-storage for the local rust Task
Notably, this crate avoids the following services:
* Thread creation and destruction. The crate does not require the knowledge of
an OS threading system, and as a result it seemed best to leave out the
`rt::thread` module from librustrt. The librustrt module does depend on
mutexes, however.
* Implementation of backtraces. There is no inherent requirement for the runtime
to be able to generate backtraces. As will be discussed later, this
functionality continues to live in libstd rather than librustrt.
As usual, a number of architectural changes were required to make this crate
possible. Users of "stable" functionality will not be impacted by this change,
but users of the `std::rt` module will likely note the changes. A list of
architectural changes made is:
* The stdout/stderr handles no longer live directly inside of the `Task`
structure. This is a consequence of librustrt not knowing about `std::io`.
These two handles are now stored inside of task-local-data.
The handles were originally stored inside of the `Task` for perf reasons, and
TLD is not currently as fast as it could be. For comparison, 100k prints goes
from 59ms to 68ms (a 15% slowdown). This appeared to me to be an acceptable
perf loss for the successful extraction of a librustrt crate.
* The `rtio` module was forced to duplicate more functionality of `std::io`. As
the module no longer depends on `std::io`, `rtio` now defines structures such
as socket addresses, addrinfo fiddly bits, etc. The primary change made was
that `rtio` now defines its own `IoError` type. This type is distinct from
`std::io::IoError` in that it does not have an enum for what error occurred,
but rather a platform-specific error code.
The native and green libraries will be updated in later commits for this
change, and the bulk of this effort was put behind updating the two libraries
for this change (with `rtio`).
* Printing a message on task failure (along with the backtrace) continues to
live in libstd, not in librustrt. This is a consequence of the above decision
to move the stdout/stderr handles to TLD rather than inside the `Task` itself.
The unwinding API now supports registration of global callback functions which
will be invoked when a task fails, allowing for libstd to register a function
to print a message and a backtrace.
The API for registering a callback is experimental and unsafe, as the
ramifications of running code on unwinding is pretty hairy.
* The `std::unstable::mutex` module has moved to `std::rt::mutex`.
* The `std::unstable::sync` module has been moved to `std::rt::exclusive` and
the type has been rewritten to not internally have an Arc and to have an RAII
guard structure when locking. Old code should stop using `Exclusive` in favor
of the primitives in `libsync`, but if necessary, old code should port to
`Arc<Exclusive<T>>`.
* The local heap has been stripped down to have fewer debugging options. None of
these were tested, and none of these have been used in a very long time.
[breaking-change]
2014-06-03 21:11:49 -05:00
|
|
|
#[repr(C)]
|
|
|
|
enum _Unwind_VRS_Result {
|
|
|
|
_UVRSR_OK = 0,
|
|
|
|
_UVRSR_NOT_IMPLEMENTED = 1,
|
|
|
|
_UVRSR_FAILED = 2,
|
|
|
|
}
|
|
|
|
#[repr(C)]
|
|
|
|
enum _Unwind_VRS_RegClass {
|
|
|
|
_UVRSC_CORE = 0,
|
|
|
|
_UVRSC_VFP = 1,
|
|
|
|
_UVRSC_FPA = 2,
|
|
|
|
_UVRSC_WMMXD = 3,
|
|
|
|
_UVRSC_WMMXC = 4,
|
|
|
|
}
|
|
|
|
#[repr(C)]
|
|
|
|
enum _Unwind_VRS_DataRepresentation {
|
|
|
|
_UVRSD_UINT32 = 0,
|
|
|
|
_UVRSD_VFPX = 1,
|
|
|
|
_UVRSD_FPAX = 2,
|
|
|
|
_UVRSD_UINT64 = 3,
|
|
|
|
_UVRSD_FLOAT = 4,
|
|
|
|
_UVRSD_DOUBLE = 5,
|
|
|
|
}
|
|
|
|
|
|
|
|
type _Unwind_Word = libc::c_uint;
|
|
|
|
extern {
|
2014-06-25 14:47:34 -05:00
|
|
|
fn _Unwind_VRS_Get(ctx: *mut _Unwind_Context,
|
std: Extract librustrt out of libstd
As part of the libstd facade efforts, this commit extracts the runtime interface
out of the standard library into a standalone crate, librustrt. This crate will
provide the following services:
* Definition of the rtio interface
* Definition of the Runtime interface
* Implementation of the Task structure
* Implementation of task-local-data
* Implementation of task failure via unwinding via libunwind
* Implementation of runtime initialization and shutdown
* Implementation of thread-local-storage for the local rust Task
Notably, this crate avoids the following services:
* Thread creation and destruction. The crate does not require the knowledge of
an OS threading system, and as a result it seemed best to leave out the
`rt::thread` module from librustrt. The librustrt module does depend on
mutexes, however.
* Implementation of backtraces. There is no inherent requirement for the runtime
to be able to generate backtraces. As will be discussed later, this
functionality continues to live in libstd rather than librustrt.
As usual, a number of architectural changes were required to make this crate
possible. Users of "stable" functionality will not be impacted by this change,
but users of the `std::rt` module will likely note the changes. A list of
architectural changes made is:
* The stdout/stderr handles no longer live directly inside of the `Task`
structure. This is a consequence of librustrt not knowing about `std::io`.
These two handles are now stored inside of task-local-data.
The handles were originally stored inside of the `Task` for perf reasons, and
TLD is not currently as fast as it could be. For comparison, 100k prints goes
from 59ms to 68ms (a 15% slowdown). This appeared to me to be an acceptable
perf loss for the successful extraction of a librustrt crate.
* The `rtio` module was forced to duplicate more functionality of `std::io`. As
the module no longer depends on `std::io`, `rtio` now defines structures such
as socket addresses, addrinfo fiddly bits, etc. The primary change made was
that `rtio` now defines its own `IoError` type. This type is distinct from
`std::io::IoError` in that it does not have an enum for what error occurred,
but rather a platform-specific error code.
The native and green libraries will be updated in later commits for this
change, and the bulk of this effort was put behind updating the two libraries
for this change (with `rtio`).
* Printing a message on task failure (along with the backtrace) continues to
live in libstd, not in librustrt. This is a consequence of the above decision
to move the stdout/stderr handles to TLD rather than inside the `Task` itself.
The unwinding API now supports registration of global callback functions which
will be invoked when a task fails, allowing for libstd to register a function
to print a message and a backtrace.
The API for registering a callback is experimental and unsafe, as the
ramifications of running code on unwinding is pretty hairy.
* The `std::unstable::mutex` module has moved to `std::rt::mutex`.
* The `std::unstable::sync` module has been moved to `std::rt::exclusive` and
the type has been rewritten to not internally have an Arc and to have an RAII
guard structure when locking. Old code should stop using `Exclusive` in favor
of the primitives in `libsync`, but if necessary, old code should port to
`Arc<Exclusive<T>>`.
* The local heap has been stripped down to have fewer debugging options. None of
these were tested, and none of these have been used in a very long time.
[breaking-change]
2014-06-03 21:11:49 -05:00
|
|
|
klass: _Unwind_VRS_RegClass,
|
|
|
|
word: _Unwind_Word,
|
|
|
|
repr: _Unwind_VRS_DataRepresentation,
|
|
|
|
data: *mut libc::c_void)
|
|
|
|
-> _Unwind_VRS_Result;
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut val: _Unwind_Word = 0;
|
|
|
|
let ptr = &mut val as *mut _Unwind_Word;
|
2014-11-06 02:05:53 -06:00
|
|
|
let _ = _Unwind_VRS_Get(ctx, _Unwind_VRS_RegClass::_UVRSC_CORE, 15,
|
|
|
|
_Unwind_VRS_DataRepresentation::_UVRSD_UINT32,
|
std: Extract librustrt out of libstd
As part of the libstd facade efforts, this commit extracts the runtime interface
out of the standard library into a standalone crate, librustrt. This crate will
provide the following services:
* Definition of the rtio interface
* Definition of the Runtime interface
* Implementation of the Task structure
* Implementation of task-local-data
* Implementation of task failure via unwinding via libunwind
* Implementation of runtime initialization and shutdown
* Implementation of thread-local-storage for the local rust Task
Notably, this crate avoids the following services:
* Thread creation and destruction. The crate does not require the knowledge of
an OS threading system, and as a result it seemed best to leave out the
`rt::thread` module from librustrt. The librustrt module does depend on
mutexes, however.
* Implementation of backtraces. There is no inherent requirement for the runtime
to be able to generate backtraces. As will be discussed later, this
functionality continues to live in libstd rather than librustrt.
As usual, a number of architectural changes were required to make this crate
possible. Users of "stable" functionality will not be impacted by this change,
but users of the `std::rt` module will likely note the changes. A list of
architectural changes made is:
* The stdout/stderr handles no longer live directly inside of the `Task`
structure. This is a consequence of librustrt not knowing about `std::io`.
These two handles are now stored inside of task-local-data.
The handles were originally stored inside of the `Task` for perf reasons, and
TLD is not currently as fast as it could be. For comparison, 100k prints goes
from 59ms to 68ms (a 15% slowdown). This appeared to me to be an acceptable
perf loss for the successful extraction of a librustrt crate.
* The `rtio` module was forced to duplicate more functionality of `std::io`. As
the module no longer depends on `std::io`, `rtio` now defines structures such
as socket addresses, addrinfo fiddly bits, etc. The primary change made was
that `rtio` now defines its own `IoError` type. This type is distinct from
`std::io::IoError` in that it does not have an enum for what error occurred,
but rather a platform-specific error code.
The native and green libraries will be updated in later commits for this
change, and the bulk of this effort was put behind updating the two libraries
for this change (with `rtio`).
* Printing a message on task failure (along with the backtrace) continues to
live in libstd, not in librustrt. This is a consequence of the above decision
to move the stdout/stderr handles to TLD rather than inside the `Task` itself.
The unwinding API now supports registration of global callback functions which
will be invoked when a task fails, allowing for libstd to register a function
to print a message and a backtrace.
The API for registering a callback is experimental and unsafe, as the
ramifications of running code on unwinding is pretty hairy.
* The `std::unstable::mutex` module has moved to `std::rt::mutex`.
* The `std::unstable::sync` module has been moved to `std::rt::exclusive` and
the type has been rewritten to not internally have an Arc and to have an RAII
guard structure when locking. Old code should stop using `Exclusive` in favor
of the primitives in `libsync`, but if necessary, old code should port to
`Arc<Exclusive<T>>`.
* The local heap has been stripped down to have fewer debugging options. None of
these were tested, and none of these have been used in a very long time.
[breaking-change]
2014-06-03 21:11:49 -05:00
|
|
|
ptr as *mut libc::c_void);
|
|
|
|
(val & !1) as libc::uintptr_t
|
|
|
|
}
|
|
|
|
|
2014-09-02 00:35:58 -05:00
|
|
|
// This function also doesn't exist on Android or ARM/Linux, so make it
|
std: Extract librustrt out of libstd
As part of the libstd facade efforts, this commit extracts the runtime interface
out of the standard library into a standalone crate, librustrt. This crate will
provide the following services:
* Definition of the rtio interface
* Definition of the Runtime interface
* Implementation of the Task structure
* Implementation of task-local-data
* Implementation of task failure via unwinding via libunwind
* Implementation of runtime initialization and shutdown
* Implementation of thread-local-storage for the local rust Task
Notably, this crate avoids the following services:
* Thread creation and destruction. The crate does not require the knowledge of
an OS threading system, and as a result it seemed best to leave out the
`rt::thread` module from librustrt. The librustrt module does depend on
mutexes, however.
* Implementation of backtraces. There is no inherent requirement for the runtime
to be able to generate backtraces. As will be discussed later, this
functionality continues to live in libstd rather than librustrt.
As usual, a number of architectural changes were required to make this crate
possible. Users of "stable" functionality will not be impacted by this change,
but users of the `std::rt` module will likely note the changes. A list of
architectural changes made is:
* The stdout/stderr handles no longer live directly inside of the `Task`
structure. This is a consequence of librustrt not knowing about `std::io`.
These two handles are now stored inside of task-local-data.
The handles were originally stored inside of the `Task` for perf reasons, and
TLD is not currently as fast as it could be. For comparison, 100k prints goes
from 59ms to 68ms (a 15% slowdown). This appeared to me to be an acceptable
perf loss for the successful extraction of a librustrt crate.
* The `rtio` module was forced to duplicate more functionality of `std::io`. As
the module no longer depends on `std::io`, `rtio` now defines structures such
as socket addresses, addrinfo fiddly bits, etc. The primary change made was
that `rtio` now defines its own `IoError` type. This type is distinct from
`std::io::IoError` in that it does not have an enum for what error occurred,
but rather a platform-specific error code.
The native and green libraries will be updated in later commits for this
change, and the bulk of this effort was put behind updating the two libraries
for this change (with `rtio`).
* Printing a message on task failure (along with the backtrace) continues to
live in libstd, not in librustrt. This is a consequence of the above decision
to move the stdout/stderr handles to TLD rather than inside the `Task` itself.
The unwinding API now supports registration of global callback functions which
will be invoked when a task fails, allowing for libstd to register a function
to print a message and a backtrace.
The API for registering a callback is experimental and unsafe, as the
ramifications of running code on unwinding is pretty hairy.
* The `std::unstable::mutex` module has moved to `std::rt::mutex`.
* The `std::unstable::sync` module has been moved to `std::rt::exclusive` and
the type has been rewritten to not internally have an Arc and to have an RAII
guard structure when locking. Old code should stop using `Exclusive` in favor
of the primitives in `libsync`, but if necessary, old code should port to
`Arc<Exclusive<T>>`.
* The local heap has been stripped down to have fewer debugging options. None of
these were tested, and none of these have been used in a very long time.
[breaking-change]
2014-06-03 21:11:49 -05:00
|
|
|
// a no-op
|
2014-09-29 00:31:50 -05:00
|
|
|
#[cfg(any(target_os = "android",
|
|
|
|
all(target_os = "linux", target_arch = "arm")))]
|
2014-06-25 14:47:34 -05:00
|
|
|
pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut libc::c_void)
|
|
|
|
-> *mut libc::c_void
|
std: Extract librustrt out of libstd
As part of the libstd facade efforts, this commit extracts the runtime interface
out of the standard library into a standalone crate, librustrt. This crate will
provide the following services:
* Definition of the rtio interface
* Definition of the Runtime interface
* Implementation of the Task structure
* Implementation of task-local-data
* Implementation of task failure via unwinding via libunwind
* Implementation of runtime initialization and shutdown
* Implementation of thread-local-storage for the local rust Task
Notably, this crate avoids the following services:
* Thread creation and destruction. The crate does not require the knowledge of
an OS threading system, and as a result it seemed best to leave out the
`rt::thread` module from librustrt. The librustrt module does depend on
mutexes, however.
* Implementation of backtraces. There is no inherent requirement for the runtime
to be able to generate backtraces. As will be discussed later, this
functionality continues to live in libstd rather than librustrt.
As usual, a number of architectural changes were required to make this crate
possible. Users of "stable" functionality will not be impacted by this change,
but users of the `std::rt` module will likely note the changes. A list of
architectural changes made is:
* The stdout/stderr handles no longer live directly inside of the `Task`
structure. This is a consequence of librustrt not knowing about `std::io`.
These two handles are now stored inside of task-local-data.
The handles were originally stored inside of the `Task` for perf reasons, and
TLD is not currently as fast as it could be. For comparison, 100k prints goes
from 59ms to 68ms (a 15% slowdown). This appeared to me to be an acceptable
perf loss for the successful extraction of a librustrt crate.
* The `rtio` module was forced to duplicate more functionality of `std::io`. As
the module no longer depends on `std::io`, `rtio` now defines structures such
as socket addresses, addrinfo fiddly bits, etc. The primary change made was
that `rtio` now defines its own `IoError` type. This type is distinct from
`std::io::IoError` in that it does not have an enum for what error occurred,
but rather a platform-specific error code.
The native and green libraries will be updated in later commits for this
change, and the bulk of this effort was put behind updating the two libraries
for this change (with `rtio`).
* Printing a message on task failure (along with the backtrace) continues to
live in libstd, not in librustrt. This is a consequence of the above decision
to move the stdout/stderr handles to TLD rather than inside the `Task` itself.
The unwinding API now supports registration of global callback functions which
will be invoked when a task fails, allowing for libstd to register a function
to print a message and a backtrace.
The API for registering a callback is experimental and unsafe, as the
ramifications of running code on unwinding is pretty hairy.
* The `std::unstable::mutex` module has moved to `std::rt::mutex`.
* The `std::unstable::sync` module has been moved to `std::rt::exclusive` and
the type has been rewritten to not internally have an Arc and to have an RAII
guard structure when locking. Old code should stop using `Exclusive` in favor
of the primitives in `libsync`, but if necessary, old code should port to
`Arc<Exclusive<T>>`.
* The local heap has been stripped down to have fewer debugging options. None of
these were tested, and none of these have been used in a very long time.
[breaking-change]
2014-06-03 21:11:49 -05:00
|
|
|
{
|
|
|
|
pc
|
|
|
|
}
|
|
|
|
}
|
2014-02-05 17:19:40 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/// As always, windows has something very different than unix, we mainly want
|
|
|
|
/// to avoid having to depend too much on libunwind for windows.
|
|
|
|
///
|
|
|
|
/// If you google around, you'll find a fair bit of references to built-in
|
|
|
|
/// functions to get backtraces on windows. It turns out that most of these are
|
|
|
|
/// in an external library called dbghelp. I was unable to find this library
|
|
|
|
/// via `-ldbghelp`, but it is apparently normal to do the `dlopen` equivalent
|
|
|
|
/// of it.
|
|
|
|
///
|
|
|
|
/// You'll also find that there's a function called CaptureStackBackTrace
|
|
|
|
/// mentioned frequently (which is also easy to use), but sadly I didn't have a
|
|
|
|
/// copy of that function in my mingw install (maybe it was broken?). Instead,
|
|
|
|
/// this takes the route of using StackWalk64 in order to walk the stack.
|
|
|
|
#[cfg(windows)]
|
2014-07-18 07:45:17 -05:00
|
|
|
#[allow(dead_code, non_snake_case)]
|
2014-02-05 17:19:40 -06:00
|
|
|
mod imp {
|
|
|
|
use c_str::CString;
|
2014-06-04 02:01:40 -05:00
|
|
|
use intrinsics;
|
2014-02-05 17:19:40 -06:00
|
|
|
use io::{IoResult, Writer};
|
|
|
|
use libc;
|
|
|
|
use mem;
|
|
|
|
use ops::Drop;
|
2014-11-28 10:57:41 -06:00
|
|
|
use option::Option::{Some, None};
|
2014-02-05 17:19:40 -06:00
|
|
|
use path::Path;
|
2014-11-28 10:57:41 -06:00
|
|
|
use result::Result::{Ok, Err};
|
2014-11-24 13:16:40 -06:00
|
|
|
use sync::{StaticMutex, MUTEX_INIT};
|
2014-12-11 11:44:17 -06:00
|
|
|
use slice::SliceExt;
|
2014-11-02 19:04:32 -06:00
|
|
|
use str::StrPrelude;
|
2014-06-08 22:12:10 -05:00
|
|
|
use dynamic_lib::DynamicLibrary;
|
2014-02-05 17:19:40 -06:00
|
|
|
|
2014-07-18 07:45:17 -05:00
|
|
|
#[allow(non_snake_case)]
|
2014-02-05 17:19:40 -06:00
|
|
|
extern "system" {
|
|
|
|
fn GetCurrentProcess() -> libc::HANDLE;
|
|
|
|
fn GetCurrentThread() -> libc::HANDLE;
|
|
|
|
fn RtlCaptureContext(ctx: *mut arch::CONTEXT);
|
|
|
|
}
|
|
|
|
|
|
|
|
type SymFromAddrFn =
|
|
|
|
extern "system" fn(libc::HANDLE, u64, *mut u64,
|
|
|
|
*mut SYMBOL_INFO) -> libc::BOOL;
|
|
|
|
type SymInitializeFn =
|
2014-06-25 14:47:34 -05:00
|
|
|
extern "system" fn(libc::HANDLE, *mut libc::c_void,
|
2014-02-05 17:19:40 -06:00
|
|
|
libc::BOOL) -> libc::BOOL;
|
|
|
|
type SymCleanupFn =
|
|
|
|
extern "system" fn(libc::HANDLE) -> libc::BOOL;
|
|
|
|
|
|
|
|
type StackWalk64Fn =
|
|
|
|
extern "system" fn(libc::DWORD, libc::HANDLE, libc::HANDLE,
|
|
|
|
*mut STACKFRAME64, *mut arch::CONTEXT,
|
2014-06-25 14:47:34 -05:00
|
|
|
*mut libc::c_void, *mut libc::c_void,
|
|
|
|
*mut libc::c_void, *mut libc::c_void) -> libc::BOOL;
|
2014-02-05 17:19:40 -06:00
|
|
|
|
2014-10-09 13:59:03 -05:00
|
|
|
const MAX_SYM_NAME: uint = 2000;
|
|
|
|
const IMAGE_FILE_MACHINE_I386: libc::DWORD = 0x014c;
|
|
|
|
const IMAGE_FILE_MACHINE_IA64: libc::DWORD = 0x0200;
|
|
|
|
const IMAGE_FILE_MACHINE_AMD64: libc::DWORD = 0x8664;
|
2014-02-05 17:19:40 -06:00
|
|
|
|
2014-09-21 11:25:57 -05:00
|
|
|
#[repr(C)]
|
2014-08-15 00:47:28 -05:00
|
|
|
struct SYMBOL_INFO {
|
|
|
|
SizeOfStruct: libc::c_ulong,
|
|
|
|
TypeIndex: libc::c_ulong,
|
|
|
|
Reserved: [u64, ..2],
|
|
|
|
Index: libc::c_ulong,
|
|
|
|
Size: libc::c_ulong,
|
|
|
|
ModBase: u64,
|
|
|
|
Flags: libc::c_ulong,
|
|
|
|
Value: u64,
|
|
|
|
Address: u64,
|
|
|
|
Register: libc::c_ulong,
|
|
|
|
Scope: libc::c_ulong,
|
|
|
|
Tag: libc::c_ulong,
|
|
|
|
NameLen: libc::c_ulong,
|
|
|
|
MaxNameLen: libc::c_ulong,
|
|
|
|
// note that windows has this as 1, but it basically just means that
|
|
|
|
// the name is inline at the end of the struct. For us, we just bump
|
|
|
|
// the struct size up to MAX_SYM_NAME.
|
|
|
|
Name: [libc::c_char, ..MAX_SYM_NAME],
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-02-05 17:19:40 -06:00
|
|
|
#[repr(C)]
|
|
|
|
enum ADDRESS_MODE {
|
|
|
|
AddrMode1616,
|
|
|
|
AddrMode1632,
|
|
|
|
AddrModeReal,
|
|
|
|
AddrModeFlat,
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ADDRESS64 {
|
|
|
|
Offset: u64,
|
|
|
|
Segment: u16,
|
|
|
|
Mode: ADDRESS_MODE,
|
|
|
|
}
|
|
|
|
|
|
|
|
struct STACKFRAME64 {
|
|
|
|
AddrPC: ADDRESS64,
|
|
|
|
AddrReturn: ADDRESS64,
|
|
|
|
AddrFrame: ADDRESS64,
|
|
|
|
AddrStack: ADDRESS64,
|
|
|
|
AddrBStore: ADDRESS64,
|
2014-06-25 14:47:34 -05:00
|
|
|
FuncTableEntry: *mut libc::c_void,
|
2014-02-05 17:19:40 -06:00
|
|
|
Params: [u64, ..4],
|
|
|
|
Far: libc::BOOL,
|
|
|
|
Virtual: libc::BOOL,
|
|
|
|
Reserved: [u64, ..3],
|
|
|
|
KdHelp: KDHELP64,
|
|
|
|
}
|
|
|
|
|
|
|
|
struct KDHELP64 {
|
|
|
|
Thread: u64,
|
|
|
|
ThCallbackStack: libc::DWORD,
|
|
|
|
ThCallbackBStore: libc::DWORD,
|
|
|
|
NextCallback: libc::DWORD,
|
|
|
|
FramePointer: libc::DWORD,
|
|
|
|
KiCallUserMode: u64,
|
|
|
|
KeUserCallbackDispatcher: u64,
|
|
|
|
SystemRangeStart: u64,
|
|
|
|
KiUserExceptionDispatcher: u64,
|
|
|
|
StackBase: u64,
|
|
|
|
StackLimit: u64,
|
|
|
|
Reserved: [u64, ..5],
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(target_arch = "x86")]
|
|
|
|
mod arch {
|
|
|
|
use libc;
|
|
|
|
|
2014-10-09 13:59:03 -05:00
|
|
|
const MAXIMUM_SUPPORTED_EXTENSION: uint = 512;
|
2014-02-05 17:19:40 -06:00
|
|
|
|
2014-08-15 00:47:28 -05:00
|
|
|
#[repr(C)]
|
2014-02-05 17:19:40 -06:00
|
|
|
pub struct CONTEXT {
|
|
|
|
ContextFlags: libc::DWORD,
|
|
|
|
Dr0: libc::DWORD,
|
|
|
|
Dr1: libc::DWORD,
|
|
|
|
Dr2: libc::DWORD,
|
|
|
|
Dr3: libc::DWORD,
|
|
|
|
Dr6: libc::DWORD,
|
|
|
|
Dr7: libc::DWORD,
|
|
|
|
FloatSave: FLOATING_SAVE_AREA,
|
|
|
|
SegGs: libc::DWORD,
|
|
|
|
SegFs: libc::DWORD,
|
|
|
|
SegEs: libc::DWORD,
|
|
|
|
SegDs: libc::DWORD,
|
|
|
|
Edi: libc::DWORD,
|
|
|
|
Esi: libc::DWORD,
|
|
|
|
Ebx: libc::DWORD,
|
|
|
|
Edx: libc::DWORD,
|
|
|
|
Ecx: libc::DWORD,
|
|
|
|
Eax: libc::DWORD,
|
|
|
|
Ebp: libc::DWORD,
|
|
|
|
Eip: libc::DWORD,
|
|
|
|
SegCs: libc::DWORD,
|
|
|
|
EFlags: libc::DWORD,
|
|
|
|
Esp: libc::DWORD,
|
|
|
|
SegSs: libc::DWORD,
|
|
|
|
ExtendedRegisters: [u8, ..MAXIMUM_SUPPORTED_EXTENSION],
|
|
|
|
}
|
|
|
|
|
2014-08-15 00:47:28 -05:00
|
|
|
#[repr(C)]
|
2014-02-05 17:19:40 -06:00
|
|
|
pub struct FLOATING_SAVE_AREA {
|
|
|
|
ControlWord: libc::DWORD,
|
|
|
|
StatusWord: libc::DWORD,
|
|
|
|
TagWord: libc::DWORD,
|
|
|
|
ErrorOffset: libc::DWORD,
|
|
|
|
ErrorSelector: libc::DWORD,
|
|
|
|
DataOffset: libc::DWORD,
|
|
|
|
DataSelector: libc::DWORD,
|
|
|
|
RegisterArea: [u8, ..80],
|
|
|
|
Cr0NpxState: libc::DWORD,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn init_frame(frame: &mut super::STACKFRAME64,
|
|
|
|
ctx: &CONTEXT) -> libc::DWORD {
|
|
|
|
frame.AddrPC.Offset = ctx.Eip as u64;
|
2014-11-06 02:05:53 -06:00
|
|
|
frame.AddrPC.Mode = super::ADDRESS_MODE::AddrModeFlat;
|
2014-02-05 17:19:40 -06:00
|
|
|
frame.AddrStack.Offset = ctx.Esp as u64;
|
2014-11-06 02:05:53 -06:00
|
|
|
frame.AddrStack.Mode = super::ADDRESS_MODE::AddrModeFlat;
|
2014-02-05 17:19:40 -06:00
|
|
|
frame.AddrFrame.Offset = ctx.Ebp as u64;
|
2014-11-06 02:05:53 -06:00
|
|
|
frame.AddrFrame.Mode = super::ADDRESS_MODE::AddrModeFlat;
|
2014-02-05 17:19:40 -06:00
|
|
|
super::IMAGE_FILE_MACHINE_I386
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-19 02:42:02 -05:00
|
|
|
#[cfg(target_arch = "x86_64")]
|
|
|
|
mod arch {
|
|
|
|
use libc::{c_longlong, c_ulonglong};
|
|
|
|
use libc::types::os::arch::extra::{WORD, DWORD, DWORDLONG};
|
2014-09-18 08:37:46 -05:00
|
|
|
use simd;
|
2014-03-19 02:42:02 -05:00
|
|
|
|
2014-08-15 00:47:28 -05:00
|
|
|
#[repr(C)]
|
2014-03-19 02:42:02 -05:00
|
|
|
pub struct CONTEXT {
|
2014-09-18 08:37:46 -05:00
|
|
|
_align_hack: [simd::u64x2, ..0], // FIXME align on 16-byte
|
2014-03-19 02:42:02 -05:00
|
|
|
P1Home: DWORDLONG,
|
|
|
|
P2Home: DWORDLONG,
|
|
|
|
P3Home: DWORDLONG,
|
|
|
|
P4Home: DWORDLONG,
|
|
|
|
P5Home: DWORDLONG,
|
|
|
|
P6Home: DWORDLONG,
|
|
|
|
|
|
|
|
ContextFlags: DWORD,
|
|
|
|
MxCsr: DWORD,
|
|
|
|
|
|
|
|
SegCs: WORD,
|
|
|
|
SegDs: WORD,
|
|
|
|
SegEs: WORD,
|
|
|
|
SegFs: WORD,
|
|
|
|
SegGs: WORD,
|
|
|
|
SegSs: WORD,
|
|
|
|
EFlags: DWORD,
|
|
|
|
|
|
|
|
Dr0: DWORDLONG,
|
|
|
|
Dr1: DWORDLONG,
|
|
|
|
Dr2: DWORDLONG,
|
|
|
|
Dr3: DWORDLONG,
|
|
|
|
Dr6: DWORDLONG,
|
|
|
|
Dr7: DWORDLONG,
|
|
|
|
|
|
|
|
Rax: DWORDLONG,
|
|
|
|
Rcx: DWORDLONG,
|
|
|
|
Rdx: DWORDLONG,
|
|
|
|
Rbx: DWORDLONG,
|
|
|
|
Rsp: DWORDLONG,
|
|
|
|
Rbp: DWORDLONG,
|
|
|
|
Rsi: DWORDLONG,
|
|
|
|
Rdi: DWORDLONG,
|
|
|
|
R8: DWORDLONG,
|
|
|
|
R9: DWORDLONG,
|
|
|
|
R10: DWORDLONG,
|
|
|
|
R11: DWORDLONG,
|
|
|
|
R12: DWORDLONG,
|
|
|
|
R13: DWORDLONG,
|
|
|
|
R14: DWORDLONG,
|
|
|
|
R15: DWORDLONG,
|
|
|
|
|
|
|
|
Rip: DWORDLONG,
|
|
|
|
|
|
|
|
FltSave: FLOATING_SAVE_AREA,
|
|
|
|
|
|
|
|
VectorRegister: [M128A, .. 26],
|
|
|
|
VectorControl: DWORDLONG,
|
|
|
|
|
|
|
|
DebugControl: DWORDLONG,
|
|
|
|
LastBranchToRip: DWORDLONG,
|
|
|
|
LastBranchFromRip: DWORDLONG,
|
|
|
|
LastExceptionToRip: DWORDLONG,
|
|
|
|
LastExceptionFromRip: DWORDLONG,
|
|
|
|
}
|
|
|
|
|
2014-08-15 00:47:28 -05:00
|
|
|
#[repr(C)]
|
2014-03-19 02:42:02 -05:00
|
|
|
pub struct M128A {
|
2014-09-18 08:37:46 -05:00
|
|
|
_align_hack: [simd::u64x2, ..0], // FIXME align on 16-byte
|
2014-03-19 02:42:02 -05:00
|
|
|
Low: c_ulonglong,
|
|
|
|
High: c_longlong
|
|
|
|
}
|
|
|
|
|
2014-08-15 00:47:28 -05:00
|
|
|
#[repr(C)]
|
2014-03-19 02:42:02 -05:00
|
|
|
pub struct FLOATING_SAVE_AREA {
|
2014-09-18 08:37:46 -05:00
|
|
|
_align_hack: [simd::u64x2, ..0], // FIXME align on 16-byte
|
2014-03-19 02:42:02 -05:00
|
|
|
_Dummy: [u8, ..512] // FIXME: Fill this out
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn init_frame(frame: &mut super::STACKFRAME64,
|
|
|
|
ctx: &CONTEXT) -> DWORD {
|
|
|
|
frame.AddrPC.Offset = ctx.Rip as u64;
|
2014-11-06 02:05:53 -06:00
|
|
|
frame.AddrPC.Mode = super::ADDRESS_MODE::AddrModeFlat;
|
2014-03-19 02:42:02 -05:00
|
|
|
frame.AddrStack.Offset = ctx.Rsp as u64;
|
2014-11-06 02:05:53 -06:00
|
|
|
frame.AddrStack.Mode = super::ADDRESS_MODE::AddrModeFlat;
|
2014-03-19 02:42:02 -05:00
|
|
|
frame.AddrFrame.Offset = ctx.Rbp as u64;
|
2014-11-06 02:05:53 -06:00
|
|
|
frame.AddrFrame.Mode = super::ADDRESS_MODE::AddrModeFlat;
|
2014-03-19 02:42:02 -05:00
|
|
|
super::IMAGE_FILE_MACHINE_AMD64
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-15 00:47:28 -05:00
|
|
|
#[repr(C)]
|
2014-02-05 17:19:40 -06:00
|
|
|
struct Cleanup {
|
|
|
|
handle: libc::HANDLE,
|
|
|
|
SymCleanup: SymCleanupFn,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for Cleanup {
|
|
|
|
fn drop(&mut self) { (self.SymCleanup)(self.handle); }
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn write(w: &mut Writer) -> IoResult<()> {
|
|
|
|
// According to windows documentation, all dbghelp functions are
|
|
|
|
// single-threaded.
|
2014-11-24 13:16:40 -06:00
|
|
|
static LOCK: StaticMutex = MUTEX_INIT;
|
|
|
|
let _g = LOCK.lock();
|
2014-02-05 17:19:40 -06:00
|
|
|
|
|
|
|
// Open up dbghelp.dll, we don't link to it explicitly because it can't
|
|
|
|
// always be found. Additionally, it's nice having fewer dependencies.
|
|
|
|
let path = Path::new("dbghelp.dll");
|
|
|
|
let lib = match DynamicLibrary::open(Some(&path)) {
|
|
|
|
Ok(lib) => lib,
|
|
|
|
Err(..) => return Ok(()),
|
|
|
|
};
|
|
|
|
|
2014-06-12 23:34:32 -05:00
|
|
|
macro_rules! sym( ($e:expr, $t:ident) => (unsafe {
|
|
|
|
match lib.symbol($e) {
|
2014-06-25 14:47:34 -05:00
|
|
|
Ok(f) => mem::transmute::<*mut u8, $t>(f),
|
2014-02-05 17:19:40 -06:00
|
|
|
Err(..) => return Ok(())
|
|
|
|
}
|
2014-06-12 23:34:32 -05:00
|
|
|
}) )
|
2014-02-05 17:19:40 -06:00
|
|
|
|
|
|
|
// Fetch the symbols necessary from dbghelp.dll
|
|
|
|
let SymFromAddr = sym!("SymFromAddr", SymFromAddrFn);
|
|
|
|
let SymInitialize = sym!("SymInitialize", SymInitializeFn);
|
|
|
|
let SymCleanup = sym!("SymCleanup", SymCleanupFn);
|
|
|
|
let StackWalk64 = sym!("StackWalk64", StackWalk64Fn);
|
|
|
|
|
|
|
|
// Allocate necessary structures for doing the stack walk
|
|
|
|
let process = unsafe { GetCurrentProcess() };
|
|
|
|
let thread = unsafe { GetCurrentThread() };
|
|
|
|
let mut context: arch::CONTEXT = unsafe { intrinsics::init() };
|
|
|
|
unsafe { RtlCaptureContext(&mut context); }
|
|
|
|
let mut frame: STACKFRAME64 = unsafe { intrinsics::init() };
|
|
|
|
let image = arch::init_frame(&mut frame, &context);
|
|
|
|
|
|
|
|
// Initialize this process's symbols
|
2014-06-25 14:47:34 -05:00
|
|
|
let ret = SymInitialize(process, 0 as *mut libc::c_void, libc::TRUE);
|
2014-02-05 17:19:40 -06:00
|
|
|
if ret != libc::TRUE { return Ok(()) }
|
|
|
|
let _c = Cleanup { handle: process, SymCleanup: SymCleanup };
|
|
|
|
|
|
|
|
// And now that we're done with all the setup, do the stack walking!
|
2014-04-21 16:58:52 -05:00
|
|
|
let mut i = 0i;
|
2014-02-05 17:19:40 -06:00
|
|
|
try!(write!(w, "stack backtrace:\n"));
|
|
|
|
while StackWalk64(image, process, thread, &mut frame, &mut context,
|
2014-06-25 14:47:34 -05:00
|
|
|
0 as *mut libc::c_void,
|
|
|
|
0 as *mut libc::c_void,
|
|
|
|
0 as *mut libc::c_void,
|
|
|
|
0 as *mut libc::c_void) == libc::TRUE{
|
2014-02-05 17:19:40 -06:00
|
|
|
let addr = frame.AddrPC.Offset;
|
|
|
|
if addr == frame.AddrReturn.Offset || addr == 0 ||
|
|
|
|
frame.AddrReturn.Offset == 0 { break }
|
|
|
|
|
|
|
|
i += 1;
|
|
|
|
try!(write!(w, " {:2}: {:#2$x}", i, addr, super::HEX_WIDTH));
|
|
|
|
let mut info: SYMBOL_INFO = unsafe { intrinsics::init() };
|
|
|
|
info.MaxNameLen = MAX_SYM_NAME as libc::c_ulong;
|
2014-09-21 11:25:57 -05:00
|
|
|
// the struct size in C. the value is different to
|
|
|
|
// `size_of::<SYMBOL_INFO>() - MAX_SYM_NAME + 1` (== 81)
|
|
|
|
// due to struct alignment.
|
|
|
|
info.SizeOfStruct = 88;
|
2014-02-05 17:19:40 -06:00
|
|
|
|
|
|
|
let mut displacement = 0u64;
|
|
|
|
let ret = SymFromAddr(process, addr as u64, &mut displacement,
|
|
|
|
&mut info);
|
|
|
|
|
|
|
|
if ret == libc::TRUE {
|
|
|
|
try!(write!(w, " - "));
|
|
|
|
let cstr = unsafe { CString::new(info.Name.as_ptr(), false) };
|
|
|
|
let bytes = cstr.as_bytes();
|
|
|
|
match cstr.as_str() {
|
|
|
|
Some(s) => try!(super::demangle(w, s)),
|
2014-09-24 06:41:09 -05:00
|
|
|
None => try!(w.write(bytes[..bytes.len()-1])),
|
2014-02-05 17:19:40 -06:00
|
|
|
}
|
|
|
|
}
|
2014-11-17 18:49:09 -06:00
|
|
|
try!(w.write(&['\n' as u8]));
|
2014-02-05 17:19:40 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
use prelude::*;
|
2014-03-13 18:23:10 -05:00
|
|
|
macro_rules! t( ($a:expr, $b:expr) => ({
|
2014-11-11 15:01:29 -06:00
|
|
|
let mut m = Vec::new();
|
2014-03-13 18:23:10 -05:00
|
|
|
super::demangle(&mut m, $a).unwrap();
|
2014-11-27 18:45:47 -06:00
|
|
|
assert_eq!(String::from_utf8(m).unwrap(), $b);
|
2014-03-13 18:23:10 -05:00
|
|
|
}) )
|
|
|
|
|
2014-02-05 17:19:40 -06:00
|
|
|
#[test]
|
|
|
|
fn demangle() {
|
|
|
|
t!("test", "test");
|
|
|
|
t!("_ZN4testE", "test");
|
|
|
|
t!("_ZN4test", "_ZN4test");
|
|
|
|
t!("_ZN4test1a2bcE", "test::a::bc");
|
|
|
|
}
|
2014-03-13 18:23:10 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn demangle_dollars() {
|
2014-05-05 20:56:44 -05:00
|
|
|
t!("_ZN4$UP$E", "Box");
|
|
|
|
t!("_ZN8$UP$testE", "Boxtest");
|
|
|
|
t!("_ZN8$UP$test4foobE", "Boxtest::foob");
|
2014-03-13 18:23:10 -05:00
|
|
|
t!("_ZN8$x20test4foobE", " test::foob");
|
|
|
|
}
|
2014-04-18 19:33:47 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn demangle_many_dollars() {
|
|
|
|
t!("_ZN12test$x20test4foobE", "test test::foob");
|
2014-05-05 20:56:44 -05:00
|
|
|
t!("_ZN12test$UP$test4foobE", "testBoxtest::foob");
|
2014-04-18 19:33:47 -05:00
|
|
|
}
|
2014-02-05 17:19:40 -06:00
|
|
|
}
|