]> git.proxmox.com Git - rustc.git/blame - src/libstd/sys/windows/backtrace/printing/msvc.rs
New upstream version 1.36.0+dfsg1
[rustc.git] / src / libstd / sys / windows / backtrace / printing / msvc.rs
CommitLineData
532ac7d7
XL
1use crate::ffi::CStr;
2use crate::io;
3use crate::mem;
4use crate::sys::backtrace::BacktraceContext;
5use crate::sys::backtrace::StackWalkVariant;
6use crate::sys::c;
7use crate::sys::dynamic_lib::DynamicLibrary;
8use crate::sys_common::backtrace::Frame;
9
8faf50e0 10use 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)
15pub struct PrintingFnsEx {
16 resolve_symname: SymFromInlineContextFn,
17 sym_get_line: SymGetLineFromInlineContextFn,
18}
19pub struct PrintingFns64 {
20 resolve_symname: SymFromAddrFn,
21 sym_get_line: SymGetLineFromAddr64Fn,
22}
23
24pub 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}
34pub 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
41type SymFromAddrFn =
42 unsafe extern "system" fn(c::HANDLE, u64, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL;
2c00a5a8 43type SymFromInlineContextFn =
8faf50e0
XL
44 unsafe extern "system" fn(c::HANDLE, u64, c::ULONG, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL;
45
46type SymGetLineFromAddr64Fn =
47 unsafe extern "system" fn(c::HANDLE, u64, *mut u32, *mut c::IMAGEHLP_LINE64) -> c::BOOL;
48type 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
58pub fn resolve_symname<F>(frame: Frame, callback: F, context: &BacktraceContext) -> io::Result<()>
59where
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
96fn resolve_symname_internal<F, R>(
97 mut symbol_resolver: R,
98 frame: Frame,
99 callback: F,
100 context: &BacktraceContext,
101) -> io::Result<()>
102where
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
139pub fn foreach_symbol_fileline<F>(
140 frame: Frame,
141 callback: F,
142 context: &BacktraceContext,
143) -> io::Result<bool>
144where
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
182fn 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>
188where
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}