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