Skip to content

Commit eb1ebb4

Browse files
author
Aaron Power
committed
no_std support
1 parent a73a623 commit eb1ebb4

17 files changed

+428
-212
lines changed

Cargo.toml

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ documentation = "https://docs.rs/backtrace"
1111
description = """
1212
A library to acquire a stack trace (backtrace) at runtime in a Rust program.
1313
"""
14+
autoexamples = true
15+
autotests = true
16+
1417
[dependencies]
1518
cfg-if = "0.1"
1619
rustc-demangle = "0.1.4"
@@ -47,7 +50,10 @@ backtrace-sys = { path = "backtrace-sys", version = "0.1.17", optional = true }
4750
# Note that not all features are available on all platforms, so even though a
4851
# feature is enabled some other feature may be used instead.
4952
[features]
50-
default = ["libunwind", "libbacktrace", "coresymbolication", "dladdr", "dbghelp"]
53+
default = ["std", "libunwind", "libbacktrace", "coresymbolication", "dladdr", "dbghelp"]
54+
55+
# Include std support.
56+
std = []
5157

5258
#=======================================
5359
# Methods of acquiring a backtrace
@@ -86,7 +92,7 @@ kernel32 = []
8692
# the moment, this is only possible when targetting Linux, since macOS
8793
# splits DWARF out into a separate object file. Enabling this feature
8894
# means one less C dependency.
89-
libbacktrace = ["backtrace-sys"]
95+
libbacktrace = ["backtrace-sys", "std"]
9096
dladdr = []
9197
coresymbolication = []
9298
gimli-symbolize = ["addr2line", "findshlibs", "gimli", "memmap", "object" ]
@@ -97,3 +103,23 @@ gimli-symbolize = ["addr2line", "findshlibs", "gimli", "memmap", "object" ]
97103
# Various features used for enabling rustc-serialize or syntex codegen.
98104
serialize-rustc = ["rustc-serialize"]
99105
serialize-serde = ["serde", "serde_derive"]
106+
107+
[[example]]
108+
name = "backtrace"
109+
required-features = ["std"]
110+
111+
[[example]]
112+
name = "raw"
113+
required-features = ["std"]
114+
115+
[[test]]
116+
name = "skip_inner_frames"
117+
required-features = ["std"]
118+
119+
[[test]]
120+
name = "long_fn_name"
121+
required-features = ["std"]
122+
123+
[[test]]
124+
name = "smoke"
125+
required-features = ["std"]

backtrace-sys/src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22

33
extern crate libc;
44

5-
use libc::uintptr_t;
6-
use std::os::raw::{c_void, c_char, c_int};
5+
use libc::{c_void, c_char, c_int, uintptr_t};
76

87
pub type backtrace_syminfo_callback =
98
extern fn(data: *mut c_void,

src/backtrace/dbghelp.rs

Lines changed: 33 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -33,49 +33,43 @@ impl Frame {
3333
}
3434

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

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

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

57-
// Initialize this process's symbols
58-
let _c = ::dbghelp_init();
55+
// And now that we're done with all the setup, do the stack walking!
56+
while dbghelp::StackWalk64(image as DWORD,
57+
process,
58+
thread,
59+
&mut frame.inner.inner,
60+
&mut *context as *mut _ as *mut _,
61+
None,
62+
Some(dbghelp::SymFunctionTableAccess64),
63+
Some(dbghelp::SymGetModuleBase64),
64+
None) == TRUE {
65+
if frame.inner.inner.AddrPC.Offset == frame.inner.inner.AddrReturn.Offset ||
66+
frame.inner.inner.AddrPC.Offset == 0 ||
67+
frame.inner.inner.AddrReturn.Offset == 0 {
68+
break
69+
}
5970

60-
// And now that we're done with all the setup, do the stack walking!
61-
while dbghelp::StackWalk64(image as DWORD,
62-
process,
63-
thread,
64-
&mut frame.inner.inner,
65-
&mut *context as *mut _ as *mut _,
66-
None,
67-
Some(dbghelp::SymFunctionTableAccess64),
68-
Some(dbghelp::SymGetModuleBase64),
69-
None) == TRUE {
70-
if frame.inner.inner.AddrPC.Offset == frame.inner.inner.AddrReturn.Offset ||
71-
frame.inner.inner.AddrPC.Offset == 0 ||
72-
frame.inner.inner.AddrReturn.Offset == 0 {
73-
break
74-
}
75-
76-
if !cb(&frame) {
77-
break
78-
}
71+
if !cb(&frame) {
72+
break
7973
}
8074
}
8175
}

src/backtrace/libunwind.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use std::os::raw::c_void;
11+
use types::c_void;
1212

1313
pub struct Frame {
1414
ctx: *mut uw::_Unwind_Context,
@@ -48,10 +48,8 @@ impl Frame {
4848
}
4949

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

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

8684
use libc;
87-
use std::os::raw::{c_int, c_void};
85+
use types::{c_int, c_void};
8886

8987
#[repr(C)]
9088
pub enum _Unwind_Reason_Code {

src/backtrace/mod.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use std::fmt;
2-
3-
use std::os::raw::c_void;
2+
use types::c_void;
43

54
/// Inspects the current call-stack, passing all active frames into the closure
65
/// provided to calculate a stack trace.
@@ -37,10 +36,20 @@ use std::os::raw::c_void;
3736
/// }
3837
/// ```
3938
#[inline(never)]
39+
#[cfg(feature = "std")]
4040
pub fn trace<F: FnMut(&Frame) -> bool>(mut cb: F) {
41+
let _guard = ::lock::lock();
42+
unsafe { trace_imp(&mut cb) }
43+
}
44+
45+
/// Without std this function now does not have synchronization guarentees.
46+
/// Please refer to std documentation for examples and explaination.
47+
#[inline(never)]
48+
pub unsafe fn trace_unsynchronized<F: FnMut(&Frame) -> bool>(mut cb: F) {
4149
trace_imp(&mut cb)
4250
}
4351

52+
4453
/// A trait representing one frame of a backtrace, yielded to the `trace`
4554
/// function of this crate.
4655
///

src/backtrace/noop.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::os::raw::c_void;
1+
use types::c_void;
22

33
#[inline(always)]
44
pub fn trace(_cb: &mut FnMut(&super::Frame) -> bool) {}

src/backtrace/unix_backtrace.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
// except according to those terms.
1010

1111
use std::mem;
12-
use std::os::raw::{c_void, c_int};
12+
use types::{c_void, c_int};
1313

1414
pub struct Frame {
1515
addr: *mut c_void,
@@ -25,15 +25,14 @@ extern {
2525
}
2626

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

3131
let mut buf: [*mut c_void; SIZE];
3232
let cnt;
33-
unsafe {
34-
buf = mem::zeroed();
35-
cnt = backtrace(buf.as_mut_ptr(), SIZE as c_int);
36-
}
33+
34+
buf = mem::zeroed();
35+
cnt = backtrace(buf.as_mut_ptr(), SIZE as c_int);
3736

3837
for addr in buf[..cnt as usize].iter() {
3938
let cx = super::Frame {

src/capture.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use std::fmt;
22
use std::mem;
3-
use std::os::raw::c_void;
43
use std::path::{Path, PathBuf};
54

65
use {trace, resolve, SymbolName};
6+
use types::c_void;
77

88
/// Representation of an owned and self-contained backtrace.
99
///
@@ -144,7 +144,7 @@ impl Backtrace {
144144
symbols.push(BacktraceSymbol {
145145
name: symbol.name().map(|m| m.as_bytes().to_vec()),
146146
addr: symbol.addr().map(|a| a as usize),
147-
filename: symbol.filename().map(|m| m.to_path_buf()),
147+
filename: symbol.filename().map(|m| m.to_owned()),
148148
lineno: symbol.lineno(),
149149
});
150150
});

src/lib.rs

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@
4646
//! extern crate backtrace;
4747
//!
4848
//! fn main() {
49+
//! # // Unsafe here so test passes on no_std.
50+
//! # #[cfg(feature = "std")] {
4951
//! backtrace::trace(|frame| {
5052
//! let ip = frame.ip();
5153
//! let symbol_address = frame.symbol_address();
@@ -63,10 +65,15 @@
6365
//! true // keep going to the next frame
6466
//! });
6567
//! }
68+
//! # }
6669
//! ```
6770
6871
#![doc(html_root_url = "https://docs.rs/backtrace")]
6972
#![deny(missing_docs)]
73+
#![cfg_attr(not(feature = "std"), no_std)]
74+
75+
#[cfg(not(feature = "std"))]
76+
extern crate core as std;
7077

7178
#[cfg(unix)]
7279
extern crate libc;
@@ -98,18 +105,27 @@ cfg_if! {
98105
}
99106

100107
#[allow(dead_code)] // not used everywhere
101-
#[cfg(unix)]
108+
#[cfg(all(unix, feature = "std"))]
102109
#[macro_use]
103110
mod dylib;
104111

105-
pub use backtrace::{trace, Frame};
112+
pub use backtrace::{trace_unsynchronized, Frame};
106113
mod backtrace;
107114

108-
pub use symbolize::{resolve, Symbol, SymbolName};
115+
pub use symbolize::{resolve_unsynchronized, Symbol, SymbolName};
109116
mod symbolize;
110117

111-
pub use capture::{Backtrace, BacktraceFrame, BacktraceSymbol};
112-
mod capture;
118+
pub use types::BytesOrWideString;
119+
mod types;
120+
121+
cfg_if! {
122+
if #[cfg(feature = "std")] {
123+
pub use backtrace::trace;
124+
pub use symbolize::resolve;
125+
pub use capture::{Backtrace, BacktraceFrame, BacktraceSymbol};
126+
mod capture;
127+
}
128+
}
113129

114130
#[allow(dead_code)]
115131
struct Bomb {
@@ -126,6 +142,7 @@ impl Drop for Bomb {
126142
}
127143

128144
#[allow(dead_code)]
145+
#[cfg(feature = "std")]
129146
mod lock {
130147
use std::cell::Cell;
131148
use std::sync::{Once, Mutex, MutexGuard, ONCE_INIT};

src/symbolize/coresymbolication.rs

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,8 @@
1010

1111
#![allow(bad_style)]
1212

13-
use std::ffi::{CStr, OsStr};
13+
use std::ffi::CStr;
1414
use std::mem;
15-
use std::os::raw::{c_void, c_char, c_int};
16-
use std::os::unix::prelude::*;
17-
use std::path::Path;
1815
use std::ptr;
1916
use std::sync::atomic::ATOMIC_USIZE_INIT;
2017

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

2725
#[repr(C)]
2826
#[derive(Copy, Clone, PartialEq)]
@@ -69,15 +67,15 @@ impl Symbol {
6967
}
7068
}
7169

72-
pub fn filename(&self) -> Option<&Path> {
70+
pub fn filename_raw(&self) -> Option<BytesOrWideString> {
7371
match *self {
7472
Symbol::Core { path, .. } => {
7573
if path.is_null() {
7674
None
7775
} else {
78-
Some(Path::new(OsStr::from_bytes(unsafe {
76+
Some(BytesOrWideString::Bytes(unsafe {
7977
CStr::from_ptr(path).to_bytes()
80-
})))
78+
}))
8179
}
8280
}
8381
Symbol::Dladdr(_) => None,
@@ -177,16 +175,14 @@ unsafe fn try_resolve(addr: *mut c_void, cb: &mut FnMut(&super::Symbol)) -> bool
177175
rv
178176
}
179177

180-
pub fn resolve(addr: *mut c_void, cb: &mut FnMut(&super::Symbol)) {
181-
unsafe {
182-
if try_resolve(addr, cb) {
183-
return
184-
}
185-
let mut info: Dl_info = mem::zeroed();
186-
if libc::dladdr(addr as *mut _, &mut info) != 0 {
187-
cb(&super::Symbol {
188-
inner: Symbol::Dladdr(info),
189-
});
190-
}
178+
pub unsafe fn resolve(addr: *mut c_void, cb: &mut FnMut(&super::Symbol)) {
179+
if try_resolve(addr, cb) {
180+
return
181+
}
182+
let mut info: Dl_info = mem::zeroed();
183+
if libc::dladdr(addr as *mut _, &mut info) != 0 {
184+
cb(&super::Symbol {
185+
inner: Symbol::Dladdr(info),
186+
});
191187
}
192188
}

0 commit comments

Comments
 (0)