std\backtrace\src\symbolize/
dbghelp.rs1#![allow(bad_style)]
19
20use super::super::{dbghelp, windows_sys::*};
21use super::{BytesOrWideString, ResolveWhat, SymbolName};
22use core::ffi::c_void;
23use core::marker;
24use core::mem;
25use core::ptr;
26use core::slice;
27
28#[inline(always)]
30#[must_use]
31const fn ptr_from_ref<T: ?Sized>(r: &T) -> *const T {
32 r
33}
34
35pub struct Symbol<'a> {
37 name: *const [u8],
38 addr: *mut c_void,
39 line: Option<u32>,
40 filename: Option<*const [u16]>,
41 #[cfg(feature = "std")]
42 _filename_cache: Option<::std::ffi::OsString>,
43 #[cfg(not(feature = "std"))]
44 _filename_cache: (),
45 _marker: marker::PhantomData<&'a i32>,
46}
47
48impl Symbol<'_> {
49 pub fn name(&self) -> Option<SymbolName<'_>> {
50 Some(SymbolName::new(unsafe { &*self.name }))
51 }
52
53 pub fn addr(&self) -> Option<*mut c_void> {
54 Some(self.addr)
55 }
56
57 pub fn filename_raw(&self) -> Option<BytesOrWideString<'_>> {
58 self.filename
59 .map(|slice| unsafe { BytesOrWideString::Wide(&*slice) })
60 }
61
62 pub fn colno(&self) -> Option<u32> {
63 None
64 }
65
66 pub fn lineno(&self) -> Option<u32> {
67 self.line
68 }
69
70 #[cfg(feature = "std")]
71 pub fn filename(&self) -> Option<&::std::path::Path> {
72 use std::path::Path;
73
74 self._filename_cache.as_ref().map(Path::new)
75 }
76}
77
78#[repr(C, align(8))]
79struct Aligned8<T>(T);
80
81#[cfg(not(target_vendor = "win7"))]
82pub unsafe fn resolve(what: ResolveWhat<'_>, cb: &mut dyn FnMut(&super::Symbol)) {
83 let dbghelp = match dbghelp::init() {
85 Ok(dbghelp) => dbghelp,
86 Err(()) => return, };
88 unsafe {
89 match what {
90 ResolveWhat::Address(_) => {
91 resolve_with_inline(&dbghelp, what.address_or_ip(), None, cb)
92 }
93 ResolveWhat::Frame(frame) => {
94 resolve_with_inline(&dbghelp, frame.ip(), frame.inner.inline_context(), cb)
95 }
96 };
97 }
98}
99
100#[cfg(target_vendor = "win7")]
101pub unsafe fn resolve(what: ResolveWhat<'_>, cb: &mut dyn FnMut(&super::Symbol)) {
102 let dbghelp = match dbghelp::init() {
104 Ok(dbghelp) => dbghelp,
105 Err(()) => return, };
107
108 unsafe {
109 let resolve_inner = if (*dbghelp.dbghelp()).SymAddrIncludeInlineTrace().is_some() {
110 resolve_with_inline
113 } else {
114 resolve_legacy
117 };
118 match what {
119 ResolveWhat::Address(_) => resolve_inner(&dbghelp, what.address_or_ip(), None, cb),
120 ResolveWhat::Frame(frame) => {
121 resolve_inner(&dbghelp, frame.ip(), frame.inner.inline_context(), cb)
122 }
123 };
124 }
125}
126
127#[cfg(target_vendor = "win7")]
132unsafe fn resolve_legacy(
133 dbghelp: &dbghelp::Init,
134 addr: *mut c_void,
135 _inline_context: Option<u32>,
136 cb: &mut dyn FnMut(&super::Symbol),
137) -> Option<()> {
138 let addr = super::adjust_ip(addr) as u64;
139 unsafe {
140 do_resolve(
141 |info| dbghelp.SymFromAddrW()(GetCurrentProcess(), addr, &mut 0, info),
142 |line| dbghelp.SymGetLineFromAddrW64()(GetCurrentProcess(), addr, &mut 0, line),
143 cb,
144 );
145 }
146 Some(())
147}
148
149unsafe fn resolve_with_inline(
154 dbghelp: &dbghelp::Init,
155 addr: *mut c_void,
156 inline_context: Option<u32>,
157 cb: &mut dyn FnMut(&super::Symbol),
158) -> Option<()> {
159 unsafe {
160 let current_process = GetCurrentProcess();
161 let SymFromInlineContextW = (*dbghelp.dbghelp()).SymFromInlineContextW()?;
163 let SymGetLineFromInlineContextW = (*dbghelp.dbghelp()).SymGetLineFromInlineContextW()?;
164
165 let addr = super::adjust_ip(addr) as u64;
166
167 let (inlined_frame_count, inline_context) = if let Some(ic) = inline_context {
168 (0, ic)
169 } else {
170 let SymAddrIncludeInlineTrace = (*dbghelp.dbghelp()).SymAddrIncludeInlineTrace()?;
171 let SymQueryInlineTrace = (*dbghelp.dbghelp()).SymQueryInlineTrace()?;
172
173 let mut inlined_frame_count = SymAddrIncludeInlineTrace(current_process, addr);
174
175 let mut inline_context = 0;
176
177 if (inlined_frame_count > 0
180 && SymQueryInlineTrace(
181 current_process,
182 addr,
183 0,
184 addr,
185 addr,
186 &mut inline_context,
187 &mut 0,
188 ) != TRUE)
189 || inlined_frame_count == 0
190 {
191 inlined_frame_count = 0;
192 inline_context = 0;
193 }
194
195 (inlined_frame_count, inline_context)
196 };
197
198 let last_inline_context = inline_context + 1 + inlined_frame_count;
199
200 for inline_context in inline_context..last_inline_context {
201 do_resolve(
202 |info| SymFromInlineContextW(current_process, addr, inline_context, &mut 0, info),
203 |line| {
204 SymGetLineFromInlineContextW(
205 current_process,
206 addr,
207 inline_context,
208 0,
209 &mut 0,
210 line,
211 )
212 },
213 cb,
214 );
215 }
216 }
217 Some(())
218}
219
220unsafe fn do_resolve(
221 sym_from_addr: impl FnOnce(*mut SYMBOL_INFOW) -> BOOL,
222 get_line_from_addr: impl FnOnce(&mut IMAGEHLP_LINEW64) -> BOOL,
223 cb: &mut dyn FnMut(&super::Symbol),
224) {
225 const SIZE: usize = 2 * MAX_SYM_NAME as usize + mem::size_of::<SYMBOL_INFOW>();
226 let mut data = Aligned8([0u8; SIZE]);
227 let info = unsafe { &mut *data.0.as_mut_ptr().cast::<SYMBOL_INFOW>() };
228 info.MaxNameLen = MAX_SYM_NAME as u32;
229 info.SizeOfStruct = 88;
233
234 if sym_from_addr(info) != TRUE {
235 return;
236 }
237
238 let name_len = ::core::cmp::min(info.NameLen as usize, info.MaxNameLen as usize - 1);
242 let name_ptr = info.Name.as_ptr().cast::<u16>();
243
244 let mut name_buffer = [0_u8; 256];
247 let mut name_len = unsafe {
248 WideCharToMultiByte(
249 CP_UTF8,
250 0,
251 name_ptr,
252 name_len as i32,
253 name_buffer.as_mut_ptr(),
254 name_buffer.len() as i32,
255 core::ptr::null_mut(),
256 core::ptr::null_mut(),
257 ) as usize
258 };
259 if name_len == 0 {
260 name_len = name_buffer.len();
263 } else if name_len > name_buffer.len() {
264 return;
266 }
267 let name = ptr::addr_of!(name_buffer[..name_len]);
268
269 let mut line = IMAGEHLP_LINEW64 {
270 SizeOfStruct: 0,
271 Key: core::ptr::null_mut(),
272 LineNumber: 0,
273 FileName: core::ptr::null_mut(),
274 Address: 0,
275 };
276 line.SizeOfStruct = mem::size_of::<IMAGEHLP_LINEW64>() as u32;
277
278 let mut filename = None;
279 let mut lineno = None;
280 if get_line_from_addr(&mut line) == TRUE {
281 lineno = Some(line.LineNumber);
282
283 let base = line.FileName;
284 let mut len = 0;
285 while unsafe { *base.offset(len) != 0 } {
286 len += 1;
287 }
288
289 let len = len as usize;
290
291 unsafe {
292 filename = Some(ptr_from_ref(slice::from_raw_parts(base, len)));
293 }
294 }
295
296 cb(&super::Symbol {
297 inner: Symbol {
298 name,
299 addr: info.Address as *mut _,
300 line: lineno,
301 filename,
302 _filename_cache: unsafe { cache(filename) },
303 _marker: marker::PhantomData,
304 },
305 })
306}
307
308#[cfg(feature = "std")]
309unsafe fn cache(filename: Option<*const [u16]>) -> Option<::std::ffi::OsString> {
310 use std::os::windows::ffi::OsStringExt;
311 unsafe { filename.map(|f| ::std::ffi::OsString::from_wide(&*f)) }
312}
313
314#[cfg(not(feature = "std"))]
315unsafe fn cache(_filename: Option<*const [u16]>) {}
316
317pub unsafe fn clear_symbol_cache() {}