Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
est31 committed Jun 10, 2018
1 parent dad833e commit 2c8a5be
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 7 deletions.
2 changes: 2 additions & 0 deletions src/Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2726,7 +2726,9 @@ dependencies = [
"alloc_system 0.0.0",
"build_helper 0.1.0",
"cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"gimli 0.16.0 (git+https://github.com/est31/gimli?rev=304caacf8b73f117813b1a0d436ce24403459bf2)",
"libc 0.0.0",
"object 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"panic_abort 0.0.0",
"panic_unwind 0.0.0",
"profiler_builtins 0.0.0",
Expand Down
3 changes: 2 additions & 1 deletion src/bootstrap/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -841,7 +841,8 @@ impl<'a> Builder<'a> {
let suffix = match mode {
Mode::Std => "rustc-std",
Mode::Test => "rustc-test",
Mode::Codegen | Mode::Rustc => "rustc-rustc",
Mode::Codegen => "rustc-codegen",
Mode::Rustc => "rustc-rustc",
Mode::ToolStd | Mode::ToolTest | Mode::ToolRustc => "rustc-tools",
};
cargo.env("RUSTC_METADATA_SUFFIX", suffix);
Expand Down
11 changes: 10 additions & 1 deletion src/libstd/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ panic_abort = { path = "../libpanic_abort" }
libc = { path = "../rustc/libc_shim" }
profiler_builtins = { path = "../libprofiler_builtins", optional = true }
unwind = { path = "../libunwind" }
object = { version = "0.9", default-features = false, optional = true }

[dependencies.gimli]
version = "0.16"
default-features = false
features = ["alloc"]
git = "https://github.com/est31/gimli"
rev = "304caacf8b73f117813b1a0d436ce24403459bf2"
optional = true

[dependencies.addr2line]
git = "https://github.com/est31/addr2line"
Expand All @@ -46,7 +55,7 @@ cc = "1.0"
build_helper = { path = "../build_helper" }

[features]
backtrace = ["addr2line"]
backtrace = ["addr2line", "object", "gimli"]
debug-jemalloc = ["alloc_jemalloc/debug"]
jemalloc = ["alloc_jemalloc"]
force_alloc_system = []
Expand Down
21 changes: 19 additions & 2 deletions src/libstd/sys/unix/backtrace/printing/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ where
Ok(false)
}

#[cfg(not(target_os = "emscripten"))]
#[cfg(target_os = "fuchsia")]
pub use sys_common::gnu::libbacktrace::foreach_symbol_fileline;

#[cfg(not(target_os = "emscripten"))]
#[cfg(target_os = "fuchsia")]
pub fn resolve_symname<F>(frame: Frame, callback: F, bc: &BacktraceContext) -> io::Result<()>
where
F: FnOnce(Option<&str>) -> io::Result<()>
Expand All @@ -41,3 +41,20 @@ where
}
}, bc)
}

#[cfg(not(any(target_os = "fuchsia", target_os = "emscripten")))]
pub use sys_common::addr2line::foreach_symbol_fileline;

#[cfg(not(any(target_os = "fuchsia", target_os = "emscripten")))]
pub fn resolve_symname<F>(frame: Frame, callback: F, bc: &BacktraceContext) -> io::Result<()>
where
F: FnOnce(Option<&str>) -> io::Result<()>
{
::sys_common::addr2line::resolve_symname(frame, |symname| {
if symname.is_some() {
callback(symname)
} else {
dladdr::resolve_symname(frame, callback, bc)
}
}, bc)
}
141 changes: 141 additions & 0 deletions src/libstd/sys_common/addr2line.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
// Copyright 2018 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.

extern crate addr2line;
extern crate gimli;
extern crate object;

use libc::{mmap, size_t, PROT_READ, MAP_SHARED, MAP_FAILED};

use io;
use ptr;

use cell::UnsafeCell;
use marker::Sync;
use sys::backtrace::BacktraceContext;
use sys_common::backtrace::Frame;
use os::unix::io::AsRawFd;
use fs::File;
use slice::from_raw_parts;
use self::addr2line::Context;
use self::gimli::{EndianRcSlice, RunTimeEndian};

struct ThreadSafe<T>(UnsafeCell<T>);

unsafe impl<T> Sync for ThreadSafe<T> {}

macro_rules! err {
($e:expr) => {
return Err(io::Error::new(
io::ErrorKind::Other,
$e)
);
}
}

struct Ctx {
ctx: Context<EndianRcSlice<RunTimeEndian>>,
_file: File,
}

impl Ctx {
fn init() -> io::Result<Ctx> {
let (_filename, file) = ::sys::backtrace::gnu::get_executable_filename()?;
let file_len = file.metadata()?.len();

let map_ptr = unsafe {
mmap(ptr::null_mut(),
file_len as size_t,
PROT_READ,
MAP_SHARED,
file.as_raw_fd(),
0)
};
if map_ptr == MAP_FAILED {
err!("mapping the executable into memory failed");
}

let map = unsafe { from_raw_parts(map_ptr as * mut u8, file_len as usize) };
let object_file = match object::File::parse(&*map) {
Ok(v) => v,
Err(_) => err!("could not parse the object file for backtrace creation"),
};
let ctx = match Context::new(&object_file) {
Ok(v) => v,
Err(_) => err!("could not create backtrace parsing context"),
};

Ok(Ctx {
ctx,
_file: file,
})
}
fn with_static<T, F: FnOnce(&Ctx) -> io::Result<T>>(f: F) -> io::Result<T> {
static CTX_CELL: ThreadSafe<Option<Ctx>> = ThreadSafe(UnsafeCell::new(None));
let cell_ref: &mut Option<_> = unsafe { &mut *CTX_CELL.0.get() };
if cell_ref.is_none() {
*cell_ref = Some(Ctx::init()?);
}
let ctx = if let Some(c) = cell_ref {
c
} else {
unreachable!()
};
f(ctx)
}
}

pub fn foreach_symbol_fileline<F>(frame: Frame,
mut f: F,
_: &BacktraceContext) -> io::Result<bool>
where F: FnMut(&[u8], u32) -> io::Result<()>
{
Ctx::with_static(|ctx|{
let mut frames_iter = match ctx.ctx.find_frames(frame.exact_position as u64) {
Ok(v) => v,
Err(_) => err!("error during binary parsing"),
};
for frame_opt in frames_iter.next() {
let loc_opt = frame_opt.and_then(|v| v.location);
let file_line_opt = loc_opt.map(|v| (v.file, v.line));
if let Some((Some(file), Some(line))) = file_line_opt {
f(file.as_bytes(), line as u32)?;
}
}
// FIXME: when should we return true here?
Ok(false)
})
}

/// Converts a pointer to symbol to its string value.
pub fn resolve_symname<F>(frame: Frame,
callback: F,
_: &BacktraceContext) -> io::Result<()>
where F: FnOnce(Option<&str>) -> io::Result<()>
{
Ctx::with_static(|ctx|{
let mut frames_iter = match ctx.ctx.find_frames(frame.symbol_addr as u64) {
Ok(v) => v,
Err(_) => err!("error during binary parsing"),
};
let frame_opt = match frames_iter.next() {
Ok(v) => v,
Err(_) => err!("error during symbolification"),
};
match frame_opt.and_then(|v| v.function) {
Some(n) => match n.raw_name() {
Ok(v) => callback(Some(&*v))?,
Err(_) => err!("error during name resolval"),
},
None => callback(None)?,
}
Ok(())
})
}
8 changes: 5 additions & 3 deletions src/libstd/sys_common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,13 @@ cfg_if! {
}

#[cfg(feature = "backtrace")]
#[cfg(any(all(unix, not(target_os = "emscripten")),
all(windows, target_env = "gnu"),
target_os = "redox"))]
#[cfg(target_os = "fuchsia")]
pub mod gnu;

#[cfg(feature = "backtrace")]
#[cfg(not(target_os = "fuchsia"))]
pub mod addr2line;

// common error constructors

/// A trait for viewing representations from std types
Expand Down

0 comments on commit 2c8a5be

Please sign in to comment.