Skip to content

Commit

Permalink
no_std support
Browse files Browse the repository at this point in the history
  • Loading branch information
Aaron Power committed Oct 15, 2018
1 parent a73a623 commit eb1ebb4
Show file tree
Hide file tree
Showing 17 changed files with 428 additions and 212 deletions.
30 changes: 28 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ documentation = "https://docs.rs/backtrace"
description = """
A library to acquire a stack trace (backtrace) at runtime in a Rust program.
"""
autoexamples = true
autotests = true

[dependencies]
cfg-if = "0.1"
rustc-demangle = "0.1.4"
Expand Down Expand Up @@ -47,7 +50,10 @@ backtrace-sys = { path = "backtrace-sys", version = "0.1.17", optional = true }
# Note that not all features are available on all platforms, so even though a
# feature is enabled some other feature may be used instead.
[features]
default = ["libunwind", "libbacktrace", "coresymbolication", "dladdr", "dbghelp"]
default = ["std", "libunwind", "libbacktrace", "coresymbolication", "dladdr", "dbghelp"]

# Include std support.
std = []

#=======================================
# Methods of acquiring a backtrace
Expand Down Expand Up @@ -86,7 +92,7 @@ kernel32 = []
# the moment, this is only possible when targetting Linux, since macOS
# splits DWARF out into a separate object file. Enabling this feature
# means one less C dependency.
libbacktrace = ["backtrace-sys"]
libbacktrace = ["backtrace-sys", "std"]
dladdr = []
coresymbolication = []
gimli-symbolize = ["addr2line", "findshlibs", "gimli", "memmap", "object" ]
Expand All @@ -97,3 +103,23 @@ gimli-symbolize = ["addr2line", "findshlibs", "gimli", "memmap", "object" ]
# Various features used for enabling rustc-serialize or syntex codegen.
serialize-rustc = ["rustc-serialize"]
serialize-serde = ["serde", "serde_derive"]

[[example]]
name = "backtrace"
required-features = ["std"]

[[example]]
name = "raw"
required-features = ["std"]

[[test]]
name = "skip_inner_frames"
required-features = ["std"]

[[test]]
name = "long_fn_name"
required-features = ["std"]

[[test]]
name = "smoke"
required-features = ["std"]
3 changes: 1 addition & 2 deletions backtrace-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

extern crate libc;

use libc::uintptr_t;
use std::os::raw::{c_void, c_char, c_int};
use libc::{c_void, c_char, c_int, uintptr_t};

pub type backtrace_syminfo_callback =
extern fn(data: *mut c_void,
Expand Down
72 changes: 33 additions & 39 deletions src/backtrace/dbghelp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,49 +33,43 @@ impl Frame {
}

#[inline(always)]
pub fn trace(cb: &mut FnMut(&super::Frame) -> bool) {
// According to windows documentation, all dbghelp functions are
// single-threaded.
let _g = ::lock::lock();
pub unsafe fn trace(cb: &mut FnMut(&super::Frame) -> bool) {
// Allocate necessary structures for doing the stack walk
let process = processthreadsapi::GetCurrentProcess();
let thread = processthreadsapi::GetCurrentThread();

unsafe {
// Allocate necessary structures for doing the stack walk
let process = processthreadsapi::GetCurrentProcess();
let thread = processthreadsapi::GetCurrentThread();
// The CONTEXT structure needs to be aligned on a 16-byte boundary for
// 64-bit Windows, but currently we don't have a way to express that in
// Rust. Allocations are generally aligned to 16-bytes, though, so we
// box this up.
let mut context = Box::new(mem::zeroed::<CONTEXT>());
winnt::RtlCaptureContext(&mut *context);
let mut frame = super::Frame {
inner: Frame { inner: mem::zeroed() },
};
let image = init_frame(&mut frame.inner.inner, &context);

// The CONTEXT structure needs to be aligned on a 16-byte boundary for
// 64-bit Windows, but currently we don't have a way to express that in
// Rust. Allocations are generally aligned to 16-bytes, though, so we
// box this up.
let mut context = Box::new(mem::zeroed::<CONTEXT>());
winnt::RtlCaptureContext(&mut *context);
let mut frame = super::Frame {
inner: Frame { inner: mem::zeroed() },
};
let image = init_frame(&mut frame.inner.inner, &context);
// Initialize this process's symbols
let _c = ::dbghelp_init();

// Initialize this process's symbols
let _c = ::dbghelp_init();
// And now that we're done with all the setup, do the stack walking!
while dbghelp::StackWalk64(image as DWORD,
process,
thread,
&mut frame.inner.inner,
&mut *context as *mut _ as *mut _,
None,
Some(dbghelp::SymFunctionTableAccess64),
Some(dbghelp::SymGetModuleBase64),
None) == TRUE {
if frame.inner.inner.AddrPC.Offset == frame.inner.inner.AddrReturn.Offset ||
frame.inner.inner.AddrPC.Offset == 0 ||
frame.inner.inner.AddrReturn.Offset == 0 {
break
}

// And now that we're done with all the setup, do the stack walking!
while dbghelp::StackWalk64(image as DWORD,
process,
thread,
&mut frame.inner.inner,
&mut *context as *mut _ as *mut _,
None,
Some(dbghelp::SymFunctionTableAccess64),
Some(dbghelp::SymGetModuleBase64),
None) == TRUE {
if frame.inner.inner.AddrPC.Offset == frame.inner.inner.AddrReturn.Offset ||
frame.inner.inner.AddrPC.Offset == 0 ||
frame.inner.inner.AddrReturn.Offset == 0 {
break
}

if !cb(&frame) {
break
}
if !cb(&frame) {
break
}
}
}
Expand Down
10 changes: 4 additions & 6 deletions src/backtrace/libunwind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::os::raw::c_void;
use types::c_void;

pub struct Frame {
ctx: *mut uw::_Unwind_Context,
Expand Down Expand Up @@ -48,10 +48,8 @@ impl Frame {
}

#[inline(always)]
pub fn trace(mut cb: &mut FnMut(&super::Frame) -> bool) {
unsafe {
uw::_Unwind_Backtrace(trace_fn, &mut cb as *mut _ as *mut _);
}
pub unsafe fn trace(mut cb: &mut FnMut(&super::Frame) -> bool) {
uw::_Unwind_Backtrace(trace_fn, &mut cb as *mut _ as *mut _);

extern fn trace_fn(ctx: *mut uw::_Unwind_Context,
arg: *mut c_void) -> uw::_Unwind_Reason_Code {
Expand Down Expand Up @@ -84,7 +82,7 @@ mod uw {
pub use self::_Unwind_Reason_Code::*;

use libc;
use std::os::raw::{c_int, c_void};
use types::{c_int, c_void};

#[repr(C)]
pub enum _Unwind_Reason_Code {
Expand Down
13 changes: 11 additions & 2 deletions src/backtrace/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use std::fmt;

use std::os::raw::c_void;
use types::c_void;

/// Inspects the current call-stack, passing all active frames into the closure
/// provided to calculate a stack trace.
Expand Down Expand Up @@ -37,10 +36,20 @@ use std::os::raw::c_void;
/// }
/// ```
#[inline(never)]
#[cfg(feature = "std")]
pub fn trace<F: FnMut(&Frame) -> bool>(mut cb: F) {
let _guard = ::lock::lock();
unsafe { trace_imp(&mut cb) }
}

/// Without std this function now does not have synchronization guarentees.
/// Please refer to std documentation for examples and explaination.
#[inline(never)]
pub unsafe fn trace_unsynchronized<F: FnMut(&Frame) -> bool>(mut cb: F) {
trace_imp(&mut cb)
}


/// A trait representing one frame of a backtrace, yielded to the `trace`
/// function of this crate.
///
Expand Down
2 changes: 1 addition & 1 deletion src/backtrace/noop.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::os::raw::c_void;
use types::c_void;

#[inline(always)]
pub fn trace(_cb: &mut FnMut(&super::Frame) -> bool) {}
Expand Down
11 changes: 5 additions & 6 deletions src/backtrace/unix_backtrace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
// except according to those terms.

use std::mem;
use std::os::raw::{c_void, c_int};
use types::{c_void, c_int};

pub struct Frame {
addr: *mut c_void,
Expand All @@ -25,15 +25,14 @@ extern {
}

#[inline(always)]
pub fn trace(cb: &mut FnMut(&super::Frame) -> bool) {
pub unsafe fn trace(cb: &mut FnMut(&super::Frame) -> bool) {
const SIZE: usize = 100;

let mut buf: [*mut c_void; SIZE];
let cnt;
unsafe {
buf = mem::zeroed();
cnt = backtrace(buf.as_mut_ptr(), SIZE as c_int);
}

buf = mem::zeroed();
cnt = backtrace(buf.as_mut_ptr(), SIZE as c_int);

for addr in buf[..cnt as usize].iter() {
let cx = super::Frame {
Expand Down
4 changes: 2 additions & 2 deletions src/capture.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use std::fmt;
use std::mem;
use std::os::raw::c_void;
use std::path::{Path, PathBuf};

use {trace, resolve, SymbolName};
use types::c_void;

/// Representation of an owned and self-contained backtrace.
///
Expand Down Expand Up @@ -144,7 +144,7 @@ impl Backtrace {
symbols.push(BacktraceSymbol {
name: symbol.name().map(|m| m.as_bytes().to_vec()),
addr: symbol.addr().map(|a| a as usize),
filename: symbol.filename().map(|m| m.to_path_buf()),
filename: symbol.filename().map(|m| m.to_owned()),
lineno: symbol.lineno(),
});
});
Expand Down
27 changes: 22 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@
//! extern crate backtrace;
//!
//! fn main() {
//! # // Unsafe here so test passes on no_std.
//! # #[cfg(feature = "std")] {
//! backtrace::trace(|frame| {
//! let ip = frame.ip();
//! let symbol_address = frame.symbol_address();
Expand All @@ -63,10 +65,15 @@
//! true // keep going to the next frame
//! });
//! }
//! # }
//! ```
#![doc(html_root_url = "https://docs.rs/backtrace")]
#![deny(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]

#[cfg(not(feature = "std"))]
extern crate core as std;

#[cfg(unix)]
extern crate libc;
Expand Down Expand Up @@ -98,18 +105,27 @@ cfg_if! {
}

#[allow(dead_code)] // not used everywhere
#[cfg(unix)]
#[cfg(all(unix, feature = "std"))]
#[macro_use]
mod dylib;

pub use backtrace::{trace, Frame};
pub use backtrace::{trace_unsynchronized, Frame};
mod backtrace;

pub use symbolize::{resolve, Symbol, SymbolName};
pub use symbolize::{resolve_unsynchronized, Symbol, SymbolName};
mod symbolize;

pub use capture::{Backtrace, BacktraceFrame, BacktraceSymbol};
mod capture;
pub use types::BytesOrWideString;
mod types;

cfg_if! {
if #[cfg(feature = "std")] {
pub use backtrace::trace;
pub use symbolize::resolve;
pub use capture::{Backtrace, BacktraceFrame, BacktraceSymbol};
mod capture;
}
}

#[allow(dead_code)]
struct Bomb {
Expand All @@ -126,6 +142,7 @@ impl Drop for Bomb {
}

#[allow(dead_code)]
#[cfg(feature = "std")]
mod lock {
use std::cell::Cell;
use std::sync::{Once, Mutex, MutexGuard, ONCE_INIT};
Expand Down
32 changes: 14 additions & 18 deletions src/symbolize/coresymbolication.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,8 @@

#![allow(bad_style)]

use std::ffi::{CStr, OsStr};
use std::ffi::CStr;
use std::mem;
use std::os::raw::{c_void, c_char, c_int};
use std::os::unix::prelude::*;
use std::path::Path;
use std::ptr;
use std::sync::atomic::ATOMIC_USIZE_INIT;

Expand All @@ -23,6 +20,7 @@ use libc::{self, Dl_info};
use SymbolName;
use dylib::Dylib;
use dylib::Symbol as DylibSymbol;
use types::{BytesOrWideString, c_void, c_char, c_int};

#[repr(C)]
#[derive(Copy, Clone, PartialEq)]
Expand Down Expand Up @@ -69,15 +67,15 @@ impl Symbol {
}
}

pub fn filename(&self) -> Option<&Path> {
pub fn filename_raw(&self) -> Option<BytesOrWideString> {
match *self {
Symbol::Core { path, .. } => {
if path.is_null() {
None
} else {
Some(Path::new(OsStr::from_bytes(unsafe {
Some(BytesOrWideString::Bytes(unsafe {
CStr::from_ptr(path).to_bytes()
})))
}))
}
}
Symbol::Dladdr(_) => None,
Expand Down Expand Up @@ -177,16 +175,14 @@ unsafe fn try_resolve(addr: *mut c_void, cb: &mut FnMut(&super::Symbol)) -> bool
rv
}

pub fn resolve(addr: *mut c_void, cb: &mut FnMut(&super::Symbol)) {
unsafe {
if try_resolve(addr, cb) {
return
}
let mut info: Dl_info = mem::zeroed();
if libc::dladdr(addr as *mut _, &mut info) != 0 {
cb(&super::Symbol {
inner: Symbol::Dladdr(info),
});
}
pub unsafe fn resolve(addr: *mut c_void, cb: &mut FnMut(&super::Symbol)) {
if try_resolve(addr, cb) {
return
}
let mut info: Dl_info = mem::zeroed();
if libc::dladdr(addr as *mut _, &mut info) != 0 {
cb(&super::Symbol {
inner: Symbol::Dladdr(info),
});
}
}
Loading

0 comments on commit eb1ebb4

Please sign in to comment.