1 //! A module to define the FFI definitions we use on Windows for `dbghelp.dll`
2 //!
3 //! This module uses a custom macro, `ffi!`, to wrap all definitions to
4 //! automatically generate tests to assert that our definitions here are the
5 //! same as `winapi`.
6 //!
7 //! This module largely exists to integrate into libstd itself where winapi is
8 //! not currently available.
9 
10 #![allow(bad_style, dead_code)]
11 
12 cfg_if::cfg_if! {
13     if #[cfg(feature = "verify-winapi")] {
14         pub use self::winapi::c_void;
15         pub use self::winapi::HINSTANCE;
16         pub use self::winapi::FARPROC;
17         pub use self::winapi::LPSECURITY_ATTRIBUTES;
18 
19         mod winapi {
20             pub use winapi::ctypes::*;
21             pub use winapi::shared::basetsd::*;
22             pub use winapi::shared::minwindef::*;
23             pub use winapi::um::dbghelp::*;
24             pub use winapi::um::handleapi::*;
25             pub use winapi::um::libloaderapi::*;
26             pub use winapi::um::processthreadsapi::*;
27             pub use winapi::um::winbase::*;
28             pub use winapi::um::winnt::*;
29             pub use winapi::um::fileapi::*;
30             pub use winapi::um::minwinbase::*;
31             pub use winapi::um::synchapi::*;
32         }
33     } else {
34         pub use core::ffi::c_void;
35         pub type HINSTANCE = *mut c_void;
36         pub type FARPROC = *mut c_void;
37         pub type LPSECURITY_ATTRIBUTES = *mut c_void;
38     }
39 }
40 
41 macro_rules! ffi {
42 	() => ();
43 
44     (#[repr($($r:tt)*)] pub struct $name:ident { $(pub $field:ident: $ty:ty,)* } $($rest:tt)*) => (
45         #[repr($($r)*)]
46         #[cfg(not(feature = "verify-winapi"))]
47         #[derive(Copy, Clone)]
48         pub struct $name {
49             $(pub $field: $ty,)*
50         }
51 
52         #[cfg(feature = "verify-winapi")]
53         pub use self::winapi::$name;
54 
55         #[test]
56         #[cfg(feature = "verify-winapi")]
57         fn $name() {
58             use core::mem;
59 
60             #[repr($($r)*)]
61             pub struct $name {
62                 $(pub $field: $ty,)*
63             }
64 
65             assert_eq!(
66                 mem::size_of::<$name>(),
67                 mem::size_of::<winapi::$name>(),
68                 concat!("size of ", stringify!($name), " is wrong"),
69             );
70             assert_eq!(
71                 mem::align_of::<$name>(),
72                 mem::align_of::<winapi::$name>(),
73                 concat!("align of ", stringify!($name), " is wrong"),
74             );
75 
76             type Winapi = winapi::$name;
77 
78             fn assert_same<T>(_: T, _: T) {}
79 
80             unsafe {
81                 let a = &*(mem::align_of::<$name>() as *const $name);
82                 let b = &*(mem::align_of::<Winapi>() as *const Winapi);
83 
84                 $(
85                     ffi!(@test_fields a b $field $ty);
86                 )*
87             }
88         }
89 
90         ffi!($($rest)*);
91     );
92 
93     // Handling verification against unions in winapi requires some special care
94     (@test_fields $a:ident $b:ident FltSave $ty:ty) => (
95         // Skip this field on x86_64 `CONTEXT` since it's a union and a bit funny
96     );
97     (@test_fields $a:ident $b:ident D $ty:ty) => ({
98         let a = &$a.D;
99         let b = $b.D();
100         assert_same(a, b);
101         assert_eq!(a as *const $ty, b as *const $ty, "misplaced field D");
102     });
103     (@test_fields $a:ident $b:ident s $ty:ty) => ({
104         let a = &$a.s;
105         let b = $b.s();
106         assert_same(a, b);
107         assert_eq!(a as *const $ty, b as *const $ty, "misplaced field s");
108     });
109 
110     // Otherwise test all fields normally.
111     (@test_fields $a:ident $b:ident $field:ident $ty:ty) => ({
112         let a = &$a.$field;
113         let b = &$b.$field;
114         assert_same(a, b);
115         assert_eq!(a as *const $ty, b as *const $ty,
116                    concat!("misplaced field ", stringify!($field)));
117     });
118 
119     (pub type $name:ident = $ty:ty; $($rest:tt)*) => (
120         pub type $name = $ty;
121 
122         #[cfg(feature = "verify-winapi")]
123         #[allow(dead_code)]
124         const $name: () = {
125             fn _foo() {
126                 trait SameType {}
127                 impl<T> SameType for (T, T) {}
128                 fn assert_same<T: SameType>() {}
129 
130                 assert_same::<($name, winapi::$name)>();
131             }
132         };
133 
134         ffi!($($rest)*);
135     );
136 
137     (pub const $name:ident: $ty:ty = $val:expr; $($rest:tt)*) => (
138         pub const $name: $ty = $val;
139 
140         #[cfg(feature = "verify-winapi")]
141         #[allow(unused_imports)]
142         mod $name {
143             use super::*;
144             #[test]
145             fn assert_valid() {
146                 let x: $ty = winapi::$name;
147                 assert_eq!(x, $val);
148             }
149         }
150 
151 
152         ffi!($($rest)*);
153     );
154 
155     (extern "system" { $(pub fn $name:ident($($args:tt)*) -> $ret:ty;)* } $($rest:tt)*) => (
156         extern "system" {
157             $(pub fn $name($($args)*) -> $ret;)*
158         }
159 
160         $(
161             #[cfg(feature = "verify-winapi")]
162             mod $name {
163                 #[test]
164                 fn assert_same() {
165                     use super::*;
166 
167                     assert_eq!($name as usize, winapi::$name as usize);
168                     let mut x: unsafe extern "system" fn($($args)*) -> $ret;
169                     x = $name;
170                     drop(x);
171                     x = winapi::$name;
172                     drop(x);
173                 }
174             }
175         )*
176 
177         ffi!($($rest)*);
178     );
179 
180     (impl $name:ident { $($i:tt)* } $($rest:tt)*) => (
181         #[cfg(not(feature = "verify-winapi"))]
182         impl $name {
183             $($i)*
184         }
185 
186         ffi!($($rest)*);
187     );
188 }
189 
190 ffi! {
191     #[repr(C)]
192     pub struct STACKFRAME64 {
193         pub AddrPC: ADDRESS64,
194         pub AddrReturn: ADDRESS64,
195         pub AddrFrame: ADDRESS64,
196         pub AddrStack: ADDRESS64,
197         pub AddrBStore: ADDRESS64,
198         pub FuncTableEntry: PVOID,
199         pub Params: [DWORD64; 4],
200         pub Far: BOOL,
201         pub Virtual: BOOL,
202         pub Reserved: [DWORD64; 3],
203         pub KdHelp: KDHELP64,
204     }
205 
206     pub type LPSTACKFRAME64 = *mut STACKFRAME64;
207 
208     #[repr(C)]
209     pub struct STACKFRAME_EX {
210         pub AddrPC: ADDRESS64,
211         pub AddrReturn: ADDRESS64,
212         pub AddrFrame: ADDRESS64,
213         pub AddrStack: ADDRESS64,
214         pub AddrBStore: ADDRESS64,
215         pub FuncTableEntry: PVOID,
216         pub Params: [DWORD64; 4],
217         pub Far: BOOL,
218         pub Virtual: BOOL,
219         pub Reserved: [DWORD64; 3],
220         pub KdHelp: KDHELP64,
221         pub StackFrameSize: DWORD,
222         pub InlineFrameContext: DWORD,
223     }
224 
225     pub type LPSTACKFRAME_EX = *mut STACKFRAME_EX;
226 
227     #[repr(C)]
228     pub struct IMAGEHLP_LINEW64 {
229         pub SizeOfStruct: DWORD,
230         pub Key: PVOID,
231         pub LineNumber: DWORD,
232         pub FileName: PWSTR,
233         pub Address: DWORD64,
234     }
235 
236     pub type PIMAGEHLP_LINEW64 = *mut IMAGEHLP_LINEW64;
237 
238     #[repr(C)]
239     pub struct SYMBOL_INFOW {
240         pub SizeOfStruct: ULONG,
241         pub TypeIndex: ULONG,
242         pub Reserved: [ULONG64; 2],
243         pub Index: ULONG,
244         pub Size: ULONG,
245         pub ModBase: ULONG64,
246         pub Flags: ULONG,
247         pub Value: ULONG64,
248         pub Address: ULONG64,
249         pub Register: ULONG,
250         pub Scope: ULONG,
251         pub Tag: ULONG,
252         pub NameLen: ULONG,
253         pub MaxNameLen: ULONG,
254         pub Name: [WCHAR; 1],
255     }
256 
257     pub type PSYMBOL_INFOW = *mut SYMBOL_INFOW;
258 
259     pub type PTRANSLATE_ADDRESS_ROUTINE64 = Option<
260         unsafe extern "system" fn(hProcess: HANDLE, hThread: HANDLE, lpaddr: LPADDRESS64) -> DWORD64,
261     >;
262     pub type PGET_MODULE_BASE_ROUTINE64 =
263         Option<unsafe extern "system" fn(hProcess: HANDLE, Address: DWORD64) -> DWORD64>;
264     pub type PFUNCTION_TABLE_ACCESS_ROUTINE64 =
265         Option<unsafe extern "system" fn(ahProcess: HANDLE, AddrBase: DWORD64) -> PVOID>;
266     pub type PREAD_PROCESS_MEMORY_ROUTINE64 = Option<
267         unsafe extern "system" fn(
268             hProcess: HANDLE,
269             qwBaseAddress: DWORD64,
270             lpBuffer: PVOID,
271             nSize: DWORD,
272             lpNumberOfBytesRead: LPDWORD,
273         ) -> BOOL,
274     >;
275 
276     #[repr(C)]
277     pub struct ADDRESS64 {
278         pub Offset: DWORD64,
279         pub Segment: WORD,
280         pub Mode: ADDRESS_MODE,
281     }
282 
283     pub type LPADDRESS64 = *mut ADDRESS64;
284 
285     pub type ADDRESS_MODE = u32;
286 
287     #[repr(C)]
288     pub struct KDHELP64 {
289         pub Thread: DWORD64,
290         pub ThCallbackStack: DWORD,
291         pub ThCallbackBStore: DWORD,
292         pub NextCallback: DWORD,
293         pub FramePointer: DWORD,
294         pub KiCallUserMode: DWORD64,
295         pub KeUserCallbackDispatcher: DWORD64,
296         pub SystemRangeStart: DWORD64,
297         pub KiUserExceptionDispatcher: DWORD64,
298         pub StackBase: DWORD64,
299         pub StackLimit: DWORD64,
300         pub BuildVersion: DWORD,
301         pub Reserved0: DWORD,
302         pub Reserved1: [DWORD64; 4],
303     }
304 
305     pub const MAX_SYM_NAME: usize = 2000;
306     pub const AddrModeFlat: ADDRESS_MODE = 3;
307     pub const TRUE: BOOL = 1;
308     pub const FALSE: BOOL = 0;
309     pub const PROCESS_QUERY_INFORMATION: DWORD = 0x400;
310     pub const IMAGE_FILE_MACHINE_ARM64: u16 = 43620;
311     pub const IMAGE_FILE_MACHINE_AMD64: u16 = 34404;
312     pub const IMAGE_FILE_MACHINE_I386: u16 = 332;
313     pub const IMAGE_FILE_MACHINE_ARMNT: u16 = 452;
314     pub const FILE_SHARE_READ: DWORD = 0x1;
315     pub const FILE_SHARE_WRITE: DWORD = 0x2;
316     pub const OPEN_EXISTING: DWORD = 0x3;
317     pub const GENERIC_READ: DWORD = 0x80000000;
318     pub const INFINITE: DWORD = !0;
319 
320     pub type DWORD = u32;
321     pub type PDWORD = *mut u32;
322     pub type BOOL = i32;
323     pub type DWORD64 = u64;
324     pub type PDWORD64 = *mut u64;
325     pub type HANDLE = *mut c_void;
326     pub type PVOID = HANDLE;
327     pub type PCWSTR = *const u16;
328     pub type LPSTR = *mut i8;
329     pub type LPCSTR = *const i8;
330     pub type PWSTR = *mut u16;
331     pub type WORD = u16;
332     pub type ULONG = u32;
333     pub type ULONG64 = u64;
334     pub type WCHAR = u16;
335     pub type PCONTEXT = *mut CONTEXT;
336     pub type LPDWORD = *mut DWORD;
337     pub type DWORDLONG = u64;
338     pub type HMODULE = HINSTANCE;
339 
340     extern "system" {
341         pub fn GetCurrentProcess() -> HANDLE;
342         pub fn GetCurrentThread() -> HANDLE;
343         pub fn RtlCaptureContext(ContextRecord: PCONTEXT) -> ();
344         pub fn LoadLibraryA(a: *const i8) -> HMODULE;
345         pub fn GetProcAddress(h: HMODULE, name: *const i8) -> FARPROC;
346         pub fn OpenProcess(
347             dwDesiredAccess: DWORD,
348             bInheitHandle: BOOL,
349             dwProcessId: DWORD,
350         ) -> HANDLE;
351         pub fn GetCurrentProcessId() -> DWORD;
352         pub fn CloseHandle(h: HANDLE) -> BOOL;
353         pub fn QueryFullProcessImageNameA(
354             hProcess: HANDLE,
355             dwFlags: DWORD,
356             lpExeName: LPSTR,
357             lpdwSize: PDWORD,
358         ) -> BOOL;
359         pub fn CreateFileA(
360             lpFileName: LPCSTR,
361             dwDesiredAccess: DWORD,
362             dwShareMode: DWORD,
363             lpSecurityAttributes: LPSECURITY_ATTRIBUTES,
364             dwCreationDisposition: DWORD,
365             dwFlagsAndAttributes: DWORD,
366             hTemplateFile: HANDLE,
367         ) -> HANDLE;
368         pub fn CreateMutexA(
369             attrs: LPSECURITY_ATTRIBUTES,
370             initial: BOOL,
371             name: LPCSTR,
372         ) -> HANDLE;
373         pub fn ReleaseMutex(hMutex: HANDLE) -> BOOL;
374         pub fn WaitForSingleObjectEx(
375             hHandle: HANDLE,
376             dwMilliseconds: DWORD,
377             bAlertable: BOOL,
378         ) -> DWORD;
379     }
380 }
381 
382 #[cfg(target_arch = "aarch64")]
383 ffi! {
384     #[repr(C, align(16))]
385     pub struct CONTEXT {
386         pub ContextFlags: DWORD,
387         pub Cpsr: DWORD,
388         pub u: CONTEXT_u,
389         pub Sp: u64,
390         pub Pc: u64,
391         pub V: [ARM64_NT_NEON128; 32],
392         pub Fpcr: DWORD,
393         pub Fpsr: DWORD,
394         pub Bcr: [DWORD; ARM64_MAX_BREAKPOINTS],
395         pub Bvr: [DWORD64; ARM64_MAX_BREAKPOINTS],
396         pub Wcr: [DWORD; ARM64_MAX_WATCHPOINTS],
397         pub Wvr: [DWORD64; ARM64_MAX_WATCHPOINTS],
398     }
399 
400     #[repr(C)]
401     pub struct CONTEXT_u {
402         pub s: CONTEXT_u_s,
403     }
404 
405     impl CONTEXT_u {
406         pub unsafe fn s(&self) -> &CONTEXT_u_s {
407             &self.s
408         }
409     }
410 
411     #[repr(C)]
412     pub struct CONTEXT_u_s {
413         pub X0: u64,
414         pub X1: u64,
415         pub X2: u64,
416         pub X3: u64,
417         pub X4: u64,
418         pub X5: u64,
419         pub X6: u64,
420         pub X7: u64,
421         pub X8: u64,
422         pub X9: u64,
423         pub X10: u64,
424         pub X11: u64,
425         pub X12: u64,
426         pub X13: u64,
427         pub X14: u64,
428         pub X15: u64,
429         pub X16: u64,
430         pub X17: u64,
431         pub X18: u64,
432         pub X19: u64,
433         pub X20: u64,
434         pub X21: u64,
435         pub X22: u64,
436         pub X23: u64,
437         pub X24: u64,
438         pub X25: u64,
439         pub X26: u64,
440         pub X27: u64,
441         pub X28: u64,
442         pub Fp: u64,
443         pub Lr: u64,
444     }
445 
446     pub const ARM64_MAX_BREAKPOINTS: usize = 8;
447     pub const ARM64_MAX_WATCHPOINTS: usize = 2;
448 
449     #[repr(C)]
450     pub struct ARM64_NT_NEON128 {
451         pub D: [f64; 2],
452     }
453 }
454 
455 #[cfg(target_arch = "x86")]
456 ffi! {
457     #[repr(C)]
458     pub struct CONTEXT {
459         pub ContextFlags: DWORD,
460         pub Dr0: DWORD,
461         pub Dr1: DWORD,
462         pub Dr2: DWORD,
463         pub Dr3: DWORD,
464         pub Dr6: DWORD,
465         pub Dr7: DWORD,
466         pub FloatSave: FLOATING_SAVE_AREA,
467         pub SegGs: DWORD,
468         pub SegFs: DWORD,
469         pub SegEs: DWORD,
470         pub SegDs: DWORD,
471         pub Edi: DWORD,
472         pub Esi: DWORD,
473         pub Ebx: DWORD,
474         pub Edx: DWORD,
475         pub Ecx: DWORD,
476         pub Eax: DWORD,
477         pub Ebp: DWORD,
478         pub Eip: DWORD,
479         pub SegCs: DWORD,
480         pub EFlags: DWORD,
481         pub Esp: DWORD,
482         pub SegSs: DWORD,
483         pub ExtendedRegisters: [u8; 512],
484     }
485 
486     #[repr(C)]
487     pub struct FLOATING_SAVE_AREA {
488         pub ControlWord: DWORD,
489         pub StatusWord: DWORD,
490         pub TagWord: DWORD,
491         pub ErrorOffset: DWORD,
492         pub ErrorSelector: DWORD,
493         pub DataOffset: DWORD,
494         pub DataSelector: DWORD,
495         pub RegisterArea: [u8; 80],
496         pub Spare0: DWORD,
497     }
498 }
499 
500 #[cfg(target_arch = "x86_64")]
501 ffi! {
502     #[repr(C, align(8))]
503     pub struct CONTEXT {
504         pub P1Home: DWORDLONG,
505         pub P2Home: DWORDLONG,
506         pub P3Home: DWORDLONG,
507         pub P4Home: DWORDLONG,
508         pub P5Home: DWORDLONG,
509         pub P6Home: DWORDLONG,
510 
511         pub ContextFlags: DWORD,
512         pub MxCsr: DWORD,
513 
514         pub SegCs: WORD,
515         pub SegDs: WORD,
516         pub SegEs: WORD,
517         pub SegFs: WORD,
518         pub SegGs: WORD,
519         pub SegSs: WORD,
520         pub EFlags: DWORD,
521 
522         pub Dr0: DWORDLONG,
523         pub Dr1: DWORDLONG,
524         pub Dr2: DWORDLONG,
525         pub Dr3: DWORDLONG,
526         pub Dr6: DWORDLONG,
527         pub Dr7: DWORDLONG,
528 
529         pub Rax: DWORDLONG,
530         pub Rcx: DWORDLONG,
531         pub Rdx: DWORDLONG,
532         pub Rbx: DWORDLONG,
533         pub Rsp: DWORDLONG,
534         pub Rbp: DWORDLONG,
535         pub Rsi: DWORDLONG,
536         pub Rdi: DWORDLONG,
537         pub R8:  DWORDLONG,
538         pub R9:  DWORDLONG,
539         pub R10: DWORDLONG,
540         pub R11: DWORDLONG,
541         pub R12: DWORDLONG,
542         pub R13: DWORDLONG,
543         pub R14: DWORDLONG,
544         pub R15: DWORDLONG,
545 
546         pub Rip: DWORDLONG,
547 
548         pub FltSave: FLOATING_SAVE_AREA,
549 
550         pub VectorRegister: [M128A; 26],
551         pub VectorControl: DWORDLONG,
552 
553         pub DebugControl: DWORDLONG,
554         pub LastBranchToRip: DWORDLONG,
555         pub LastBranchFromRip: DWORDLONG,
556         pub LastExceptionToRip: DWORDLONG,
557         pub LastExceptionFromRip: DWORDLONG,
558     }
559 
560     #[repr(C)]
561     pub struct M128A {
562         pub Low: u64,
563         pub High: i64,
564     }
565 }
566 
567 #[repr(C)]
568 #[cfg(target_arch = "x86_64")]
569 #[derive(Copy, Clone)]
570 pub struct FLOATING_SAVE_AREA {
571     _Dummy: [u8; 512],
572 }
573 
574 #[cfg(target_arch = "arm")]
575 ffi! {
576     // #[repr(C)]
577     // pub struct NEON128 {
578     //     pub Low: ULONG64,
579     //     pub High: LONG64,
580     // }
581 
582     // pub type PNEON128 = *mut NEON128;
583 
584     #[repr(C)]
585     pub struct CONTEXT_u {
586         // pub Q: [NEON128; 16],
587         pub D: [ULONG64; 32],
588         // pub S: [DWORD; 32],
589     }
590 
591     pub const ARM_MAX_BREAKPOINTS: usize = 8;
592     pub const ARM_MAX_WATCHPOINTS: usize = 1;
593 
594     #[repr(C)]
595     pub struct CONTEXT {
596         pub ContextFlags: DWORD,
597         pub R0: DWORD,
598         pub R1: DWORD,
599         pub R2: DWORD,
600         pub R3: DWORD,
601         pub R4: DWORD,
602         pub R5: DWORD,
603         pub R6: DWORD,
604         pub R7: DWORD,
605         pub R8: DWORD,
606         pub R9: DWORD,
607         pub R10: DWORD,
608         pub R11: DWORD,
609         pub R12: DWORD,
610         pub Sp: DWORD,
611         pub Lr: DWORD,
612         pub Pc: DWORD,
613         pub Cpsr: DWORD,
614         pub Fpsrc: DWORD,
615         pub Padding: DWORD,
616         pub u: CONTEXT_u,
617         pub Bvr: [DWORD; ARM_MAX_BREAKPOINTS],
618         pub Bcr: [DWORD; ARM_MAX_BREAKPOINTS],
619         pub Wvr: [DWORD; ARM_MAX_WATCHPOINTS],
620         pub Wcr: [DWORD; ARM_MAX_WATCHPOINTS],
621         pub Padding2: [DWORD; 2],
622     }
623 } // IFDEF(arm)
624