Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add no_std support #126

Merged
merged 14 commits into from
Nov 1, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -27,11 +27,11 @@ matrix:
- cargo test --no-default-features --features 'unix-backtrace'
- cargo test --no-default-features --features 'unix-backtrace dladdr'
- cargo test --no-default-features --features 'unix-backtrace libbacktrace'
- cargo test --no-default-features --features 'serialize-serde'
- cargo test --no-default-features --features 'serialize-rustc'
- cargo test --no-default-features --features 'serialize-rustc serialize-serde'
- cargo test --no-default-features --features 'cpp_demangle'
- cargo test --no-default-features --features 'gimli-symbolize'
- cargo test --no-default-features --features 'serialize-serde std'
- cargo test --no-default-features --features 'serialize-rustc std'
- cargo test --no-default-features --features 'serialize-rustc serialize-serde std'
- cargo test --no-default-features --features 'cpp_demangle std'
- cargo test --no-default-features --features 'gimli-symbolize std'
- cd ./cpp_smoke_test && cargo test && cd ..
- cargo clean && cargo build

36 changes: 31 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -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"
@@ -30,10 +33,10 @@ memmap = { version = "0.7.0", optional = true }
object = { version = "0.9.0", optional = true }

[target.'cfg(unix)'.dependencies]
libc = "0.2"
libc = { version = "0.2", default-features = false }

[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3.3", optional = true, features = ["std", "dbghelp", "processthreadsapi", "winnt", "minwindef"] }
winapi = { version = "0.3.3", features = ["dbghelp", "processthreadsapi", "winnt", "minwindef"] }

[target.'cfg(all(unix, not(target_os = "fuchsia"), not(target_os = "emscripten"), not(target_os = "macos"), not(target_os = "ios")))'.dependencies]
backtrace-sys = { path = "backtrace-sys", version = "0.1.17", optional = true }
@@ -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
@@ -64,7 +70,7 @@ default = ["libunwind", "libbacktrace", "coresymbolication", "dladdr", "dbghelp"
# function to acquire a backtrace
libunwind = []
unix-backtrace = []
dbghelp = ["winapi"]
dbghelp = []
kernel32 = []

#=======================================
@@ -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" ]
@@ -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"]
2 changes: 2 additions & 0 deletions appveyor.yml
Original file line number Diff line number Diff line change
@@ -18,6 +18,8 @@ build: false

test_script:
- cargo test --target %TARGET%
- cargo build --target %TARGET% --no-default-features
- cargo build --target %TARGET% --no-default-features --features dbghelp

branches:
only:
2 changes: 1 addition & 1 deletion backtrace-sys/Cargo.toml
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@ Bindings to the libbacktrace gcc library
"""

[dependencies]
libc = "0.2"
libc = { version = "0.2", default-features = false }

[build-dependencies]
cc = "1.0"
4 changes: 2 additions & 2 deletions backtrace-sys/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#![allow(bad_style)]
#![no_std]

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,
78 changes: 37 additions & 41 deletions src/backtrace/dbghelp.rs
Original file line number Diff line number Diff line change
@@ -10,14 +10,17 @@

#![allow(bad_style)]

use std::mem;
use winapi::ctypes::*;
use core::mem;
use core::prelude::v1::*;

use winapi::shared::minwindef::*;
use winapi::um::processthreadsapi;
use winapi::um::winnt::{self, CONTEXT};
use winapi::um::dbghelp;
use winapi::um::dbghelp::*;

use types::c_void;

pub struct Frame {
inner: STACKFRAME64,
}
@@ -32,50 +35,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();
#[repr(C, align(16))] // required by `CONTEXT`, is a FIXME in winapi right now
struct MyContext(CONTEXT);

unsafe {
// Allocate necessary structures for doing the stack walk
let process = processthreadsapi::GetCurrentProcess();
let thread = processthreadsapi::GetCurrentThread();
#[inline(always)]
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();

// 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);
let mut context = mem::zeroed::<MyContext>();
winnt::RtlCaptureContext(&mut context.0);
let mut frame = super::Frame {
inner: Frame { inner: mem::zeroed() },
};
let image = init_frame(&mut frame.inner.inner, &context.0);

// 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.0 as *mut CONTEXT 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
}
}
}
12 changes: 5 additions & 7 deletions src/backtrace/libunwind.rs
Original file line number Diff line number Diff line change
@@ -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,
@@ -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 {
@@ -83,8 +81,8 @@ pub fn trace(mut cb: &mut FnMut(&super::Frame) -> bool) {
mod uw {
pub use self::_Unwind_Reason_Code::*;

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

#[repr(C)]
pub enum _Unwind_Reason_Code {
25 changes: 21 additions & 4 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 core::fmt;
use types::c_void;

/// Inspects the current call-stack, passing all active frames into the closure
/// provided to calculate a stack trace.
@@ -23,6 +22,11 @@ use std::os::raw::c_void;
/// example, capture a backtrace to be inspected later, then the `Backtrace`
/// type may be more appropriate.
///
/// # Required features
///
/// This function requires the `std` feature of the `backtrace` crate to be
/// enabled, and the `std` feature is enabled by default.
///
/// # Example
///
/// ```
@@ -36,11 +40,24 @@ use std::os::raw::c_void;
/// });
/// }
/// ```
#[inline(always)]
#[cfg(feature = "std")]
pub fn trace<F: FnMut(&Frame) -> bool>(cb: F) {
let _guard = ::lock::lock();
unsafe { trace_unsynchronized(cb) }
}

/// Same as `trace`, only unsafe as it's unsynchronized.
///
/// This function does not have synchronization guarentees but is available
/// when the `std` feature of this crate isn't compiled in. See the `trace`
/// function for more documentation and examples.
#[inline(never)]
pub fn trace<F: FnMut(&Frame) -> bool>(mut cb: F) {
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.
///
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) {}
15 changes: 8 additions & 7 deletions src/backtrace/unix_backtrace.rs
Original file line number Diff line number Diff line change
@@ -8,8 +8,10 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

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

use types::c_void;

pub struct Frame {
addr: *mut c_void,
@@ -25,15 +27,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 {
5 changes: 3 additions & 2 deletions src/capture.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use std::prelude::v1::*;
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.
///
@@ -144,7 +145,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(),
});
});
Loading