]>
Commit | Line | Data |
---|---|---|
532ac7d7 XL |
1 | use crate::ffi::CStr; |
2 | use crate::io; | |
3 | use crate::mem; | |
4 | use crate::sys::backtrace::BacktraceContext; | |
5 | use crate::sys::backtrace::StackWalkVariant; | |
6 | use crate::sys::c; | |
7 | use crate::sys::dynamic_lib::DynamicLibrary; | |
8 | use crate::sys_common::backtrace::Frame; | |
9 | ||
8faf50e0 | 10 | use libc::{c_char, c_ulong}; |
8bb4bdeb | 11 | |
8faf50e0 XL |
12 | // Structs holding printing functions and loaders for them |
13 | // Two versions depending on whether dbghelp.dll has StackWalkEx or not | |
14 | // (the former being in newer Windows versions, the older being in Win7 and before) | |
15 | pub struct PrintingFnsEx { | |
16 | resolve_symname: SymFromInlineContextFn, | |
17 | sym_get_line: SymGetLineFromInlineContextFn, | |
18 | } | |
19 | pub struct PrintingFns64 { | |
20 | resolve_symname: SymFromAddrFn, | |
21 | sym_get_line: SymGetLineFromAddr64Fn, | |
22 | } | |
23 | ||
24 | pub fn load_printing_fns_ex(dbghelp: &DynamicLibrary) -> io::Result<PrintingFnsEx> { | |
25 | Ok(PrintingFnsEx { | |
26 | resolve_symname: sym!(dbghelp, "SymFromInlineContext", SymFromInlineContextFn)?, | |
27 | sym_get_line: sym!( | |
28 | dbghelp, | |
29 | "SymGetLineFromInlineContext", | |
30 | SymGetLineFromInlineContextFn | |
31 | )?, | |
32 | }) | |
33 | } | |
34 | pub fn load_printing_fns_64(dbghelp: &DynamicLibrary) -> io::Result<PrintingFns64> { | |
35 | Ok(PrintingFns64 { | |
36 | resolve_symname: sym!(dbghelp, "SymFromAddr", SymFromAddrFn)?, | |
37 | sym_get_line: sym!(dbghelp, "SymGetLineFromAddr64", SymGetLineFromAddr64Fn)?, | |
38 | }) | |
39 | } | |
40 | ||
41 | type SymFromAddrFn = | |
42 | unsafe extern "system" fn(c::HANDLE, u64, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL; | |
2c00a5a8 | 43 | type SymFromInlineContextFn = |
8faf50e0 XL |
44 | unsafe extern "system" fn(c::HANDLE, u64, c::ULONG, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL; |
45 | ||
46 | type SymGetLineFromAddr64Fn = | |
47 | unsafe extern "system" fn(c::HANDLE, u64, *mut u32, *mut c::IMAGEHLP_LINE64) -> c::BOOL; | |
48 | type SymGetLineFromInlineContextFn = unsafe extern "system" fn( | |
49 | c::HANDLE, | |
50 | u64, | |
51 | c::ULONG, | |
52 | u64, | |
53 | *mut c::DWORD, | |
54 | *mut c::IMAGEHLP_LINE64, | |
55 | ) -> c::BOOL; | |
8bb4bdeb XL |
56 | |
57 | /// Converts a pointer to symbol to its string value. | |
8faf50e0 XL |
58 | pub fn resolve_symname<F>(frame: Frame, callback: F, context: &BacktraceContext) -> io::Result<()> |
59 | where | |
60 | F: FnOnce(Option<&str>) -> io::Result<()>, | |
8bb4bdeb | 61 | { |
8faf50e0 XL |
62 | match context.StackWalkVariant { |
63 | StackWalkVariant::StackWalkEx(_, ref fns) => resolve_symname_internal( | |
64 | |process: c::HANDLE, | |
65 | symbol_address: u64, | |
66 | inline_context: c::ULONG, | |
67 | info: *mut c::SYMBOL_INFO| unsafe { | |
68 | let mut displacement = 0u64; | |
69 | (fns.resolve_symname)( | |
70 | process, | |
71 | symbol_address, | |
72 | inline_context, | |
73 | &mut displacement, | |
74 | info, | |
75 | ) | |
76 | }, | |
77 | frame, | |
78 | callback, | |
79 | context, | |
80 | ), | |
81 | StackWalkVariant::StackWalk64(_, ref fns) => resolve_symname_internal( | |
82 | |process: c::HANDLE, | |
83 | symbol_address: u64, | |
84 | _inline_context: c::ULONG, | |
85 | info: *mut c::SYMBOL_INFO| unsafe { | |
86 | let mut displacement = 0u64; | |
87 | (fns.resolve_symname)(process, symbol_address, &mut displacement, info) | |
88 | }, | |
89 | frame, | |
90 | callback, | |
91 | context, | |
92 | ), | |
93 | } | |
94 | } | |
8bb4bdeb | 95 | |
8faf50e0 XL |
96 | fn resolve_symname_internal<F, R>( |
97 | mut symbol_resolver: R, | |
98 | frame: Frame, | |
99 | callback: F, | |
100 | context: &BacktraceContext, | |
101 | ) -> io::Result<()> | |
102 | where | |
103 | F: FnOnce(Option<&str>) -> io::Result<()>, | |
104 | R: FnMut(c::HANDLE, u64, c::ULONG, *mut c::SYMBOL_INFO) -> c::BOOL, | |
105 | { | |
8bb4bdeb XL |
106 | unsafe { |
107 | let mut info: c::SYMBOL_INFO = mem::zeroed(); | |
108 | info.MaxNameLen = c::MAX_SYM_NAME as c_ulong; | |
109 | // the struct size in C. the value is different to | |
110 | // `size_of::<SYMBOL_INFO>() - MAX_SYM_NAME + 1` (== 81) | |
111 | // due to struct alignment. | |
112 | info.SizeOfStruct = 88; | |
113 | ||
8faf50e0 XL |
114 | let ret = symbol_resolver( |
115 | context.handle, | |
116 | frame.symbol_addr as u64, | |
117 | frame.inline_context, | |
118 | &mut info, | |
119 | ); | |
120 | let valid_range = if ret == c::TRUE && frame.symbol_addr as usize >= info.Address as usize { | |
2c00a5a8 XL |
121 | if info.Size != 0 { |
122 | (frame.symbol_addr as usize) < info.Address as usize + info.Size as usize | |
123 | } else { | |
124 | true | |
125 | } | |
126 | } else { | |
127 | false | |
128 | }; | |
129 | let symname = if valid_range { | |
8bb4bdeb XL |
130 | let ptr = info.Name.as_ptr() as *const c_char; |
131 | CStr::from_ptr(ptr).to_str().ok() | |
132 | } else { | |
133 | None | |
134 | }; | |
135 | callback(symname) | |
136 | } | |
137 | } | |
138 | ||
8faf50e0 XL |
139 | pub fn foreach_symbol_fileline<F>( |
140 | frame: Frame, | |
141 | callback: F, | |
142 | context: &BacktraceContext, | |
143 | ) -> io::Result<bool> | |
144 | where | |
145 | F: FnMut(&[u8], u32) -> io::Result<()>, | |
8bb4bdeb | 146 | { |
8faf50e0 XL |
147 | match context.StackWalkVariant { |
148 | StackWalkVariant::StackWalkEx(_, ref fns) => foreach_symbol_fileline_iternal( | |
149 | |process: c::HANDLE, | |
150 | frame_address: u64, | |
151 | inline_context: c::ULONG, | |
152 | line: *mut c::IMAGEHLP_LINE64| unsafe { | |
153 | let mut displacement = 0u32; | |
154 | (fns.sym_get_line)( | |
155 | process, | |
156 | frame_address, | |
157 | inline_context, | |
158 | 0, | |
159 | &mut displacement, | |
160 | line, | |
161 | ) | |
162 | }, | |
163 | frame, | |
164 | callback, | |
165 | context, | |
166 | ), | |
167 | StackWalkVariant::StackWalk64(_, ref fns) => foreach_symbol_fileline_iternal( | |
168 | |process: c::HANDLE, | |
169 | frame_address: u64, | |
170 | _inline_context: c::ULONG, | |
171 | line: *mut c::IMAGEHLP_LINE64| unsafe { | |
172 | let mut displacement = 0u32; | |
173 | (fns.sym_get_line)(process, frame_address, &mut displacement, line) | |
174 | }, | |
175 | frame, | |
176 | callback, | |
177 | context, | |
178 | ), | |
179 | } | |
180 | } | |
8bb4bdeb | 181 | |
8faf50e0 XL |
182 | fn foreach_symbol_fileline_iternal<F, G>( |
183 | mut line_getter: G, | |
184 | frame: Frame, | |
185 | mut callback: F, | |
186 | context: &BacktraceContext, | |
187 | ) -> io::Result<bool> | |
188 | where | |
189 | F: FnMut(&[u8], u32) -> io::Result<()>, | |
190 | G: FnMut(c::HANDLE, u64, c::ULONG, *mut c::IMAGEHLP_LINE64) -> c::BOOL, | |
191 | { | |
8bb4bdeb XL |
192 | unsafe { |
193 | let mut line: c::IMAGEHLP_LINE64 = mem::zeroed(); | |
532ac7d7 | 194 | line.SizeOfStruct = mem::size_of::<c::IMAGEHLP_LINE64>() as u32; |
8bb4bdeb | 195 | |
8faf50e0 XL |
196 | let ret = line_getter( |
197 | context.handle, | |
198 | frame.exact_position as u64, | |
199 | frame.inline_context, | |
200 | &mut line, | |
201 | ); | |
8bb4bdeb XL |
202 | if ret == c::TRUE { |
203 | let name = CStr::from_ptr(line.Filename).to_bytes(); | |
8faf50e0 | 204 | callback(name, line.LineNumber as u32)?; |
8bb4bdeb XL |
205 | } |
206 | Ok(false) | |
207 | } | |
208 | } |