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