std\backtrace\src\backtrace/
win32.rs1#![deny(unsafe_op_in_unsafe_fn)]
12
13use super::super::{dbghelp, windows_sys::*};
14use core::ffi::c_void;
15use core::mem;
16
17#[derive(Clone, Copy)]
18pub enum StackFrame {
19 New(STACKFRAME_EX),
20 Old(STACKFRAME64),
21}
22
23#[derive(Clone, Copy)]
24pub struct Frame {
25 pub(crate) stack_frame: StackFrame,
26 base_address: *mut c_void,
27}
28
29unsafe impl Send for Frame {}
32unsafe impl Sync for Frame {}
33
34impl Frame {
35 pub fn ip(&self) -> *mut c_void {
36 self.addr_pc().Offset as *mut _
37 }
38
39 pub fn sp(&self) -> *mut c_void {
40 self.addr_stack().Offset as *mut _
41 }
42
43 pub fn symbol_address(&self) -> *mut c_void {
44 self.ip()
45 }
46
47 pub fn module_base_address(&self) -> Option<*mut c_void> {
48 Some(self.base_address)
49 }
50
51 #[cfg(not(target_env = "gnu"))]
52 pub fn inline_context(&self) -> Option<u32> {
53 match self.stack_frame {
54 StackFrame::New(ref new) => Some(new.InlineFrameContext),
55 StackFrame::Old(_) => None,
56 }
57 }
58
59 fn addr_pc(&self) -> &ADDRESS64 {
60 match self.stack_frame {
61 StackFrame::New(ref new) => &new.AddrPC,
62 StackFrame::Old(ref old) => &old.AddrPC,
63 }
64 }
65
66 fn addr_pc_mut(&mut self) -> &mut ADDRESS64 {
67 match self.stack_frame {
68 StackFrame::New(ref mut new) => &mut new.AddrPC,
69 StackFrame::Old(ref mut old) => &mut old.AddrPC,
70 }
71 }
72
73 fn addr_frame_mut(&mut self) -> &mut ADDRESS64 {
74 match self.stack_frame {
75 StackFrame::New(ref mut new) => &mut new.AddrFrame,
76 StackFrame::Old(ref mut old) => &mut old.AddrFrame,
77 }
78 }
79
80 fn addr_stack(&self) -> &ADDRESS64 {
81 match self.stack_frame {
82 StackFrame::New(ref new) => &new.AddrStack,
83 StackFrame::Old(ref old) => &old.AddrStack,
84 }
85 }
86
87 fn addr_stack_mut(&mut self) -> &mut ADDRESS64 {
88 match self.stack_frame {
89 StackFrame::New(ref mut new) => &mut new.AddrStack,
90 StackFrame::Old(ref mut old) => &mut old.AddrStack,
91 }
92 }
93}
94
95#[repr(C, align(16))] struct MyContext(CONTEXT);
97
98#[inline(always)]
99pub unsafe fn trace(cb: &mut dyn FnMut(&super::Frame) -> bool) {
100 let process = unsafe { GetCurrentProcess() };
102 let thread = unsafe { GetCurrentThread() };
103
104 let mut context = unsafe { mem::zeroed::<MyContext>() };
106 unsafe { RtlCaptureContext(&mut context.0) };
107
108 let dbghelp = match dbghelp::init() {
110 Ok(dbghelp) => dbghelp,
111 Err(()) => return, };
113
114 let function_table_access = dbghelp.SymFunctionTableAccess64();
115 let get_module_base = dbghelp.SymGetModuleBase64();
116
117 match unsafe { (*dbghelp.dbghelp()).StackWalkEx() } {
120 #[allow(non_snake_case)]
121 Some(StackWalkEx) => {
122 let mut inner: STACKFRAME_EX = unsafe { mem::zeroed() };
124 inner.StackFrameSize = mem::size_of::<STACKFRAME_EX>() as u32;
125 let mut frame = super::Frame {
126 inner: Frame {
127 stack_frame: StackFrame::New(inner),
128 base_address: 0 as _,
129 },
130 };
131 let image = init_frame(&mut frame.inner, &context.0);
132 let frame_ptr = match &mut frame.inner.stack_frame {
133 StackFrame::New(ptr) => ptr as *mut STACKFRAME_EX,
134 _ => unreachable!(),
135 };
136
137 while unsafe {
138 StackWalkEx(
139 image as u32,
140 process,
141 thread,
142 frame_ptr,
143 &mut context.0 as *mut CONTEXT as *mut _,
144 None,
145 Some(function_table_access),
146 Some(get_module_base),
147 None,
148 0,
149 ) == TRUE
150 } {
151 frame.inner.base_address =
152 unsafe { get_module_base(process, frame.ip() as _) as _ };
153
154 if !cb(&frame) {
155 break;
156 }
157 }
158 }
159 None => {
160 let mut frame = super::Frame {
161 inner: Frame {
162 stack_frame: StackFrame::Old(unsafe { mem::zeroed() }),
164 base_address: 0 as _,
165 },
166 };
167 let image = init_frame(&mut frame.inner, &context.0);
168 let frame_ptr = match &mut frame.inner.stack_frame {
169 StackFrame::Old(ptr) => ptr as *mut STACKFRAME64,
170 _ => unreachable!(),
171 };
172
173 while unsafe {
174 dbghelp.StackWalk64()(
175 image as u32,
176 process,
177 thread,
178 frame_ptr,
179 &mut context.0 as *mut CONTEXT as *mut _,
180 None,
181 Some(function_table_access),
182 Some(get_module_base),
183 None,
184 ) == TRUE
185 } {
186 frame.inner.base_address =
187 unsafe { get_module_base(process, frame.ip() as _) as _ };
188
189 if !cb(&frame) {
190 break;
191 }
192 }
193 }
194 }
195}
196
197#[cfg(target_arch = "x86")]
198fn init_frame(frame: &mut Frame, ctx: &CONTEXT) -> u16 {
199 frame.addr_pc_mut().Offset = ctx.Eip as u64;
200 frame.addr_pc_mut().Mode = AddrModeFlat;
201 frame.addr_stack_mut().Offset = ctx.Esp as u64;
202 frame.addr_stack_mut().Mode = AddrModeFlat;
203 frame.addr_frame_mut().Offset = ctx.Ebp as u64;
204 frame.addr_frame_mut().Mode = AddrModeFlat;
205
206 IMAGE_FILE_MACHINE_I386
207}
208
209#[cfg(target_arch = "arm")]
210fn init_frame(frame: &mut Frame, ctx: &CONTEXT) -> u16 {
211 frame.addr_pc_mut().Offset = ctx.Pc as u64;
212 frame.addr_pc_mut().Mode = AddrModeFlat;
213 frame.addr_stack_mut().Offset = ctx.Sp as u64;
214 frame.addr_stack_mut().Mode = AddrModeFlat;
215 unsafe {
216 frame.addr_frame_mut().Offset = ctx.R11 as u64;
217 }
218 frame.addr_frame_mut().Mode = AddrModeFlat;
219 IMAGE_FILE_MACHINE_ARMNT
220}