Skip to content

Commit

Permalink
Use RtlCaptureStackBackTrace for trace when kernel32 feature is enabled
Browse files Browse the repository at this point in the history
  • Loading branch information
aloucks committed May 7, 2019
1 parent cc2c4f8 commit 8f929c4
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 20 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ std = []
libunwind = []
unix-backtrace = []
dbghelp = ["std"]
kernel32 = []
kernel32 = ["dbghelp"]

#=======================================
# Methods of resolving symbols
Expand Down
87 changes: 68 additions & 19 deletions src/backtrace/dbghelp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,17 @@ impl Frame {
#[repr(C, align(16))] // required by `CONTEXT`, is a FIXME in winapi right now
struct MyContext(CONTEXT);

struct CleanupOnDrop;

impl Drop for CleanupOnDrop {
fn drop(&mut self) {
::TRACE_CLEANUP.with(|trace_cleanup| {
let mut trace_cleanup = trace_cleanup.borrow_mut();
*trace_cleanup = ::Trace::Outside;
});
}
}

#[inline(always)]
pub unsafe fn trace(cb: &mut FnMut(&super::Frame) -> bool) {
// Allocate necessary structures for doing the stack walk
Expand All @@ -51,28 +62,66 @@ pub unsafe fn trace(cb: &mut FnMut(&super::Frame) -> bool) {
};
let image = init_frame(&mut frame.inner.inner, &context.0);

// 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.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
let cleanup_on_drop = CleanupOnDrop;

::TRACE_CLEANUP.with(|trace_cleanup| {
let mut trace_cleanup = trace_cleanup.borrow_mut();
*trace_cleanup = ::Trace::Inside(None);
});

if cfg!(feature = "kernel32") {
let frames_to_capture = 62;
let mut frames_to_skip = 0;
let mut backtrace = vec![0_usize; frames_to_capture as usize];
let mut backtrace_hash = 0;

loop {
let num_captured_frames = winapi::um::winnt::RtlCaptureStackBackTrace(
frames_to_skip,
frames_to_capture,
backtrace.as_mut_ptr() as _,
&mut backtrace_hash
);

for i in 0..num_captured_frames as u32 {
frame.inner.inner.AddrPC.Offset = backtrace[i as usize] as _;
if !cb(&frame) {
break;
}
}

frames_to_skip += num_captured_frames as u32;

if !cb(&frame) {
break
if num_captured_frames == 0 {
break;
}
}
} else {
// 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.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
}
}

drop(cleanup_on_drop);
}
}

Expand Down
24 changes: 24 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,17 @@ struct Cleanup {
opts: winapi::shared::minwindef::DWORD,
}

#[cfg(all(windows, feature = "dbghelp"))]
enum Trace {
Inside(Option<Cleanup>),
Outside,
}

thread_local! {
#[cfg(all(windows, feature = "dbghelp"))]
static TRACE_CLEANUP: std::cell::RefCell<Trace> = std::cell::RefCell::new(Trace::Outside);
}

#[cfg(all(windows, feature = "dbghelp"))]
unsafe fn dbghelp_init() -> Option<Cleanup> {
use winapi::shared::minwindef;
Expand Down Expand Up @@ -231,6 +242,19 @@ unsafe fn dbghelp_init() -> Option<Cleanup> {
}
}

impl Clone for Cleanup {
fn clone(&self) -> Cleanup {
unsafe {
let mut ref_count_guard = (&*REF_COUNT).lock().unwrap();
*ref_count_guard += 1;
}
Cleanup {
opts: self.opts,
handle: self.handle
}
}
}

let opts = SymGetOptions();
let handle = processthreadsapi::GetCurrentProcess();

Expand Down
12 changes: 12 additions & 0 deletions src/symbolize/dbghelp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,18 @@ pub unsafe fn resolve(addr: *mut c_void, cb: &mut FnMut(&super::Symbol)) {

let _c = ::dbghelp_init();

::TRACE_CLEANUP.with(|trace_cleanup| {
use ::Trace;
let mut trace_cleanup = trace_cleanup.borrow_mut();
match *trace_cleanup {
Trace::Outside => {},
Trace::Inside(Some(_)) => {},
Trace::Inside(None) => {
*trace_cleanup = Trace::Inside(_c.clone());
}
}
});

let mut displacement = 0u64;
let ret = dbghelp::SymFromAddrW(processthreadsapi::GetCurrentProcess(),
addr as DWORD64,
Expand Down

0 comments on commit 8f929c4

Please sign in to comment.