Skip to content

Instantly share code, notes, and snippets.

@klutzy
Last active December 31, 2015 14:19
Show Gist options
  • Save klutzy/7999247 to your computer and use it in GitHub Desktop.
Save klutzy/7999247 to your computer and use it in GitHub Desktop.
#[cfg(unix)]
fn trace(n_frames: uint) -> ~[~str] {
use std::libc::{c_void, c_int, c_char};
use std::libc;
use std::c_str;
use std::ptr;
use std::vec;
extern {
fn backtrace(buffer: *mut *mut c_void, size: c_int) -> c_int;
fn backtrace_symbols(buffer: **mut c_void, size: c_int) -> *mut *mut c_char;
}
let mut trace_buf: ~[*mut c_void] = vec::from_elem(n_frames, ptr::mut_null());
let ret = unsafe { backtrace(trace_buf.as_mut_ptr(), n_frames as i32) };
trace_buf.truncate(ret as uint);
let symbols = unsafe { backtrace_symbols(trace_buf.as_ptr(), ret) };
let mut strings = ~[];
for i in range(0, ret as int) {
unsafe {
let c_ptr = *ptr::offset(symbols as **i8, i);
let c_str = c_str::CString::new(c_ptr, false);
let s = c_str.as_str().unwrap_or("???").to_owned();
strings.push(s);
}
}
unsafe {
libc::free(symbols as *c_void);
}
strings
}
#[cfg(windows)]
fn trace(n_frames: uint) -> ~[~str] {
use std::libc::{c_ulong, c_ushort, c_void, wchar_t};
use std::libc::{BOOL, DWORD};
use std::ptr;
use std::vec;
type HANDLE = *mut c_void;
extern "system" {
fn RtlCaptureStackBackTrace(
FramesToSkip: c_ulong, FramesToCapture: c_ulong,
BackTrace: *mut *mut c_void, BackTraceHash: *mut c_ulong
) -> c_ushort;
fn GetCurrentProcess() -> HANDLE;
fn GetLastError() -> DWORD;
}
struct SYMBOL_INFO {
SizeOfStruct: c_ulong,
TypeIndex: c_ulong,
Reserved: [u64, ..2],
Index: c_ulong,
Size: c_ulong,
ModBase: u64,
Flags: c_ulong,
Value: u64,
Address: u64,
Register: c_ulong,
Scope: c_ulong,
Tag: c_ulong,
NameLen: c_ulong,
MaxNameLen: c_ulong,
Name: [wchar_t, ..256],
}
#[link(name="dbghelp")]
extern "system" {
fn SymFromAddrW(
hProcess: HANDLE, Address: u64, Displacement: *mut u64, Symbol: *mut SYMBOL_INFO
) -> BOOL;
fn SymInitializeW(hProcess: HANDLE, UserSearchPath: *wchar_t, fInvadeProcess: BOOL) -> BOOL;
}
let mut trace_buf: ~[*mut c_void] = vec::from_elem(n_frames, ptr::mut_null());
let ret = trace_buf.as_mut_buf(|buf, size| {
unsafe {
RtlCaptureStackBackTrace(0, size as c_ulong, buf, ptr::mut_null())
}
});
trace_buf.truncate(ret as uint);
let handle = unsafe { GetCurrentProcess() };
let init_res = unsafe {
SymInitializeW(handle, ptr::null(), 1)
};
let mut res = ~[];
for &frame in trace_buf.iter() {
let mut symbol_info = SYMBOL_INFO {
SizeOfStruct: 88,
TypeIndex: 0,
Reserved: [0, 0],
Index: 0,
Size: 0,
ModBase: 0,
Flags: 0,
Value: 0,
Address: 0,
Register: 0,
Scope: 0,
Tag: 0,
NameLen: 0,
MaxNameLen: 255,
Name: [0, ..256],
};
let addr_res = unsafe {
SymFromAddrW(handle, frame as u64, ptr::mut_null(), &mut symbol_info)
};
//if addr_res == 0 {
// let err = unsafe { GetLastError() };
// println!("err: {:?}", err);
//}
let name = std::str::from_utf16(symbol_info.Name);
res.push(name);
}
res
}
fn print_trace(n: uint) {
println!("---- trace: ----");
let trac = trace(n);
for sym in trac.iter() {
println!("* {:s}", sym.as_slice());
}
}
fn main() {
f();
}
fn f() {
g();
}
fn g() {
print_trace(20);
}
@klutzy
Copy link
Author

klutzy commented Feb 28, 2014

(NOTE: windows part requires mingw-w64 since mingw doesn't export some winapi functions we need..)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment