blob: d091874f12c4c5f5d4b05abdcd23aa3bfccad5d4 [file] [log] [blame]
//! A module to define the FFI definitions we use on Windows for `dbghelp.dll`
//!
//! This module uses a custom macro, `ffi!`, to wrap all definitions to
//! automatically generate tests to assert that our definitions here are the
//! same as `winapi`.
//!
//! This module largely exists to integrate into libstd itself where winapi is
//! not currently available.
#![allow(bad_style, dead_code)]
cfg_if::cfg_if! {
if #[cfg(feature = "verify-winapi")] {
pub use self::winapi::c_void;
pub use self::winapi::HINSTANCE;
pub use self::winapi::FARPROC;
pub use self::winapi::LPSECURITY_ATTRIBUTES;
#[cfg(target_pointer_width = "64")]
pub use self::winapi::PUNWIND_HISTORY_TABLE;
#[cfg(target_pointer_width = "64")]
pub use self::winapi::PRUNTIME_FUNCTION;
mod winapi {
pub use winapi::ctypes::*;
pub use winapi::shared::basetsd::*;
pub use winapi::shared::minwindef::*;
pub use winapi::um::dbghelp::*;
pub use winapi::um::fileapi::*;
pub use winapi::um::handleapi::*;
pub use winapi::um::libloaderapi::*;
pub use winapi::um::memoryapi::*;
pub use winapi::um::minwinbase::*;
pub use winapi::um::processthreadsapi::*;
pub use winapi::um::synchapi::*;
pub use winapi::um::tlhelp32::*;
pub use winapi::um::winbase::*;
pub use winapi::um::winnt::*;
}
} else {
pub use core::ffi::c_void;
pub type HINSTANCE = *mut c_void;
pub type FARPROC = *mut c_void;
pub type LPSECURITY_ATTRIBUTES = *mut c_void;
#[cfg(target_pointer_width = "64")]
pub type PRUNTIME_FUNCTION = *mut c_void;
#[cfg(target_pointer_width = "64")]
pub type PUNWIND_HISTORY_TABLE = *mut c_void;
}
}
macro_rules! ffi {
() => ();
(#[repr($($r:tt)*)] pub struct $name:ident { $(pub $field:ident: $ty:ty,)* } $($rest:tt)*) => (
#[repr($($r)*)]
#[cfg(not(feature = "verify-winapi"))]
#[derive(Copy, Clone)]
pub struct $name {
$(pub $field: $ty,)*
}
#[cfg(feature = "verify-winapi")]
pub use self::winapi::$name;
#[test]
#[cfg(feature = "verify-winapi")]
fn $name() {
use core::mem;
#[repr($($r)*)]
pub struct $name {
$(pub $field: $ty,)*
}
assert_eq!(
mem::size_of::<$name>(),
mem::size_of::<winapi::$name>(),
concat!("size of ", stringify!($name), " is wrong"),
);
assert_eq!(
mem::align_of::<$name>(),
mem::align_of::<winapi::$name>(),
concat!("align of ", stringify!($name), " is wrong"),
);
type Winapi = winapi::$name;
fn assert_same<T>(_: T, _: T) {}
unsafe {
let a = &*(mem::align_of::<$name>() as *const $name);
let b = &*(mem::align_of::<Winapi>() as *const Winapi);
$(
ffi!(@test_fields a b $field $ty);
)*
}
}
ffi!($($rest)*);
);
// Handling verification against unions in winapi requires some special care
(@test_fields $a:ident $b:ident FltSave $ty:ty) => (
// Skip this field on x86_64 `CONTEXT` since it's a union and a bit funny
);
(@test_fields $a:ident $b:ident D $ty:ty) => ({
let a = &$a.D;
let b = $b.D();
assert_same(a, b);
assert_eq!(a as *const $ty, b as *const $ty, "misplaced field D");
});
(@test_fields $a:ident $b:ident s $ty:ty) => ({
let a = &$a.s;
let b = $b.s();
assert_same(a, b);
assert_eq!(a as *const $ty, b as *const $ty, "misplaced field s");
});
// Otherwise test all fields normally.
(@test_fields $a:ident $b:ident $field:ident $ty:ty) => ({
let a = &$a.$field;
let b = &$b.$field;
assert_same(a, b);
assert_eq!(a as *const $ty, b as *const $ty,
concat!("misplaced field ", stringify!($field)));
});
(pub type $name:ident = $ty:ty; $($rest:tt)*) => (
pub type $name = $ty;
#[cfg(feature = "verify-winapi")]
#[allow(dead_code)]
const $name: () = {
fn _foo() {
trait SameType {}
impl<T> SameType for (T, T) {}
fn assert_same<T: SameType>() {}
assert_same::<($name, winapi::$name)>();
}
};
ffi!($($rest)*);
);
(pub const $name:ident: $ty:ty = $val:expr; $($rest:tt)*) => (
pub const $name: $ty = $val;
#[cfg(feature = "verify-winapi")]
#[allow(unused_imports)]
mod $name {
use super::*;
#[test]
fn assert_valid() {
let x: $ty = winapi::$name;
assert_eq!(x, $val);
}
}
ffi!($($rest)*);
);
(extern "system" { $(pub fn $name:ident($($args:tt)*) -> $ret:ty;)* } $($rest:tt)*) => (
extern "system" {
$(pub fn $name($($args)*) -> $ret;)*
}
$(
#[cfg(feature = "verify-winapi")]
mod $name {
#[test]
fn assert_same() {
use super::*;
assert_eq!($name as usize, winapi::$name as usize);
let mut x: unsafe extern "system" fn($($args)*) -> $ret;
x = $name;
drop(x);
x = winapi::$name;
drop(x);
}
}
)*
ffi!($($rest)*);
);
(impl $name:ident { $($i:tt)* } $($rest:tt)*) => (
#[cfg(not(feature = "verify-winapi"))]
impl $name {
$($i)*
}
ffi!($($rest)*);
);
}
ffi! {
#[repr(C)]
pub struct STACKFRAME64 {
pub AddrPC: ADDRESS64,
pub AddrReturn: ADDRESS64,
pub AddrFrame: ADDRESS64,
pub AddrStack: ADDRESS64,
pub AddrBStore: ADDRESS64,
pub FuncTableEntry: PVOID,
pub Params: [DWORD64; 4],
pub Far: BOOL,
pub Virtual: BOOL,
pub Reserved: [DWORD64; 3],
pub KdHelp: KDHELP64,
}
pub type LPSTACKFRAME64 = *mut STACKFRAME64;
#[repr(C)]
pub struct STACKFRAME_EX {
pub AddrPC: ADDRESS64,
pub AddrReturn: ADDRESS64,
pub AddrFrame: ADDRESS64,
pub AddrStack: ADDRESS64,
pub AddrBStore: ADDRESS64,
pub FuncTableEntry: PVOID,
pub Params: [DWORD64; 4],
pub Far: BOOL,
pub Virtual: BOOL,
pub Reserved: [DWORD64; 3],
pub KdHelp: KDHELP64,
pub StackFrameSize: DWORD,
pub InlineFrameContext: DWORD,
}
pub type LPSTACKFRAME_EX = *mut STACKFRAME_EX;
#[repr(C)]
pub struct IMAGEHLP_LINEW64 {
pub SizeOfStruct: DWORD,
pub Key: PVOID,
pub LineNumber: DWORD,
pub FileName: PWSTR,
pub Address: DWORD64,
}
pub type PIMAGEHLP_LINEW64 = *mut IMAGEHLP_LINEW64;
#[repr(C)]
pub struct SYMBOL_INFOW {
pub SizeOfStruct: ULONG,
pub TypeIndex: ULONG,
pub Reserved: [ULONG64; 2],
pub Index: ULONG,
pub Size: ULONG,
pub ModBase: ULONG64,
pub Flags: ULONG,
pub Value: ULONG64,
pub Address: ULONG64,
pub Register: ULONG,
pub Scope: ULONG,
pub Tag: ULONG,
pub NameLen: ULONG,
pub MaxNameLen: ULONG,
pub Name: [WCHAR; 1],
}
pub type PSYMBOL_INFOW = *mut SYMBOL_INFOW;
pub type PTRANSLATE_ADDRESS_ROUTINE64 = Option<
unsafe extern "system" fn(hProcess: HANDLE, hThread: HANDLE, lpaddr: LPADDRESS64) -> DWORD64,
>;
pub type PGET_MODULE_BASE_ROUTINE64 =
Option<unsafe extern "system" fn(hProcess: HANDLE, Address: DWORD64) -> DWORD64>;
pub type PFUNCTION_TABLE_ACCESS_ROUTINE64 =
Option<unsafe extern "system" fn(ahProcess: HANDLE, AddrBase: DWORD64) -> PVOID>;
pub type PREAD_PROCESS_MEMORY_ROUTINE64 = Option<
unsafe extern "system" fn(
hProcess: HANDLE,
qwBaseAddress: DWORD64,
lpBuffer: PVOID,
nSize: DWORD,
lpNumberOfBytesRead: LPDWORD,
) -> BOOL,
>;
#[repr(C)]
pub struct ADDRESS64 {
pub Offset: DWORD64,
pub Segment: WORD,
pub Mode: ADDRESS_MODE,
}
pub type LPADDRESS64 = *mut ADDRESS64;
pub type ADDRESS_MODE = u32;
#[repr(C)]
pub struct KDHELP64 {
pub Thread: DWORD64,
pub ThCallbackStack: DWORD,
pub ThCallbackBStore: DWORD,
pub NextCallback: DWORD,
pub FramePointer: DWORD,
pub KiCallUserMode: DWORD64,
pub KeUserCallbackDispatcher: DWORD64,
pub SystemRangeStart: DWORD64,
pub KiUserExceptionDispatcher: DWORD64,
pub StackBase: DWORD64,
pub StackLimit: DWORD64,
pub BuildVersion: DWORD,
pub Reserved0: DWORD,
pub Reserved1: [DWORD64; 4],
}
#[repr(C)]
pub struct MODULEENTRY32W {
pub dwSize: DWORD,
pub th32ModuleID: DWORD,
pub th32ProcessID: DWORD,
pub GlblcntUsage: DWORD,
pub ProccntUsage: DWORD,
pub modBaseAddr: *mut u8,
pub modBaseSize: DWORD,
pub hModule: HMODULE,
pub szModule: [WCHAR; MAX_MODULE_NAME32 + 1],
pub szExePath: [WCHAR; MAX_PATH],
}
pub const MAX_SYM_NAME: usize = 2000;
pub const AddrModeFlat: ADDRESS_MODE = 3;
pub const TRUE: BOOL = 1;
pub const FALSE: BOOL = 0;
pub const PROCESS_QUERY_INFORMATION: DWORD = 0x400;
pub const IMAGE_FILE_MACHINE_ARM64: u16 = 43620;
pub const IMAGE_FILE_MACHINE_AMD64: u16 = 34404;
pub const IMAGE_FILE_MACHINE_I386: u16 = 332;
pub const IMAGE_FILE_MACHINE_ARMNT: u16 = 452;
pub const FILE_SHARE_READ: DWORD = 0x1;
pub const FILE_SHARE_WRITE: DWORD = 0x2;
pub const OPEN_EXISTING: DWORD = 0x3;
pub const GENERIC_READ: DWORD = 0x80000000;
pub const INFINITE: DWORD = !0;
pub const PAGE_READONLY: DWORD = 2;
pub const FILE_MAP_READ: DWORD = 4;
pub const TH32CS_SNAPMODULE: DWORD = 0x00000008;
pub const INVALID_HANDLE_VALUE: HANDLE = -1isize as HANDLE;
pub const MAX_MODULE_NAME32: usize = 255;
pub const MAX_PATH: usize = 260;
pub type DWORD = u32;
pub type PDWORD = *mut u32;
pub type BOOL = i32;
pub type DWORD64 = u64;
pub type PDWORD64 = *mut u64;
pub type HANDLE = *mut c_void;
pub type PVOID = HANDLE;
pub type PCWSTR = *const u16;
pub type LPSTR = *mut i8;
pub type LPCSTR = *const i8;
pub type PWSTR = *mut u16;
pub type WORD = u16;
pub type ULONG = u32;
pub type ULONG64 = u64;
pub type WCHAR = u16;
pub type PCONTEXT = *mut CONTEXT;
pub type LPDWORD = *mut DWORD;
pub type DWORDLONG = u64;
pub type HMODULE = HINSTANCE;
pub type SIZE_T = usize;
pub type LPVOID = *mut c_void;
pub type LPCVOID = *const c_void;
pub type LPMODULEENTRY32W = *mut MODULEENTRY32W;
extern "system" {
pub fn GetCurrentProcess() -> HANDLE;
pub fn GetCurrentThread() -> HANDLE;
pub fn RtlCaptureContext(ContextRecord: PCONTEXT) -> ();
pub fn LoadLibraryA(a: *const i8) -> HMODULE;
pub fn GetProcAddress(h: HMODULE, name: *const i8) -> FARPROC;
pub fn GetModuleHandleA(name: *const i8) -> HMODULE;
pub fn OpenProcess(
dwDesiredAccess: DWORD,
bInheitHandle: BOOL,
dwProcessId: DWORD,
) -> HANDLE;
pub fn GetCurrentProcessId() -> DWORD;
pub fn CloseHandle(h: HANDLE) -> BOOL;
pub fn CreateFileA(
lpFileName: LPCSTR,
dwDesiredAccess: DWORD,
dwShareMode: DWORD,
lpSecurityAttributes: LPSECURITY_ATTRIBUTES,
dwCreationDisposition: DWORD,
dwFlagsAndAttributes: DWORD,
hTemplateFile: HANDLE,
) -> HANDLE;
pub fn CreateMutexA(
attrs: LPSECURITY_ATTRIBUTES,
initial: BOOL,
name: LPCSTR,
) -> HANDLE;
pub fn ReleaseMutex(hMutex: HANDLE) -> BOOL;
pub fn WaitForSingleObjectEx(
hHandle: HANDLE,
dwMilliseconds: DWORD,
bAlertable: BOOL,
) -> DWORD;
pub fn CreateFileMappingA(
hFile: HANDLE,
lpFileMappingAttributes: LPSECURITY_ATTRIBUTES,
flProtect: DWORD,
dwMaximumSizeHigh: DWORD,
dwMaximumSizeLow: DWORD,
lpName: LPCSTR,
) -> HANDLE;
pub fn MapViewOfFile(
hFileMappingObject: HANDLE,
dwDesiredAccess: DWORD,
dwFileOffsetHigh: DWORD,
dwFileOffsetLow: DWORD,
dwNumberOfBytesToMap: SIZE_T,
) -> LPVOID;
pub fn UnmapViewOfFile(lpBaseAddress: LPCVOID) -> BOOL;
pub fn CreateToolhelp32Snapshot(
dwFlags: DWORD,
th32ProcessID: DWORD,
) -> HANDLE;
pub fn Module32FirstW(
hSnapshot: HANDLE,
lpme: LPMODULEENTRY32W,
) -> BOOL;
pub fn Module32NextW(
hSnapshot: HANDLE,
lpme: LPMODULEENTRY32W,
) -> BOOL;
}
}
#[cfg(target_pointer_width = "64")]
ffi! {
extern "system" {
pub fn RtlLookupFunctionEntry(
ControlPc: DWORD64,
ImageBase: PDWORD64,
HistoryTable: PUNWIND_HISTORY_TABLE,
) -> PRUNTIME_FUNCTION;
}
}
#[cfg(target_arch = "aarch64")]
ffi! {
#[repr(C, align(16))]
pub struct CONTEXT {
pub ContextFlags: DWORD,
pub Cpsr: DWORD,
pub u: CONTEXT_u,
pub Sp: u64,
pub Pc: u64,
pub V: [ARM64_NT_NEON128; 32],
pub Fpcr: DWORD,
pub Fpsr: DWORD,
pub Bcr: [DWORD; ARM64_MAX_BREAKPOINTS],
pub Bvr: [DWORD64; ARM64_MAX_BREAKPOINTS],
pub Wcr: [DWORD; ARM64_MAX_WATCHPOINTS],
pub Wvr: [DWORD64; ARM64_MAX_WATCHPOINTS],
}
#[repr(C)]
pub struct CONTEXT_u {
pub s: CONTEXT_u_s,
}
impl CONTEXT_u {
pub unsafe fn s(&self) -> &CONTEXT_u_s {
&self.s
}
}
#[repr(C)]
pub struct CONTEXT_u_s {
pub X0: u64,
pub X1: u64,
pub X2: u64,
pub X3: u64,
pub X4: u64,
pub X5: u64,
pub X6: u64,
pub X7: u64,
pub X8: u64,
pub X9: u64,
pub X10: u64,
pub X11: u64,
pub X12: u64,
pub X13: u64,
pub X14: u64,
pub X15: u64,
pub X16: u64,
pub X17: u64,
pub X18: u64,
pub X19: u64,
pub X20: u64,
pub X21: u64,
pub X22: u64,
pub X23: u64,
pub X24: u64,
pub X25: u64,
pub X26: u64,
pub X27: u64,
pub X28: u64,
pub Fp: u64,
pub Lr: u64,
}
pub const ARM64_MAX_BREAKPOINTS: usize = 8;
pub const ARM64_MAX_WATCHPOINTS: usize = 2;
#[repr(C)]
pub struct ARM64_NT_NEON128 {
pub D: [f64; 2],
}
}
#[cfg(target_arch = "x86")]
ffi! {
#[repr(C)]
pub struct CONTEXT {
pub ContextFlags: DWORD,
pub Dr0: DWORD,
pub Dr1: DWORD,
pub Dr2: DWORD,
pub Dr3: DWORD,
pub Dr6: DWORD,
pub Dr7: DWORD,
pub FloatSave: FLOATING_SAVE_AREA,
pub SegGs: DWORD,
pub SegFs: DWORD,
pub SegEs: DWORD,
pub SegDs: DWORD,
pub Edi: DWORD,
pub Esi: DWORD,
pub Ebx: DWORD,
pub Edx: DWORD,
pub Ecx: DWORD,
pub Eax: DWORD,
pub Ebp: DWORD,
pub Eip: DWORD,
pub SegCs: DWORD,
pub EFlags: DWORD,
pub Esp: DWORD,
pub SegSs: DWORD,
pub ExtendedRegisters: [u8; 512],
}
#[repr(C)]
pub struct FLOATING_SAVE_AREA {
pub ControlWord: DWORD,
pub StatusWord: DWORD,
pub TagWord: DWORD,
pub ErrorOffset: DWORD,
pub ErrorSelector: DWORD,
pub DataOffset: DWORD,
pub DataSelector: DWORD,
pub RegisterArea: [u8; 80],
pub Spare0: DWORD,
}
}
#[cfg(target_arch = "x86_64")]
ffi! {
#[repr(C, align(8))]
pub struct CONTEXT {
pub P1Home: DWORDLONG,
pub P2Home: DWORDLONG,
pub P3Home: DWORDLONG,
pub P4Home: DWORDLONG,
pub P5Home: DWORDLONG,
pub P6Home: DWORDLONG,
pub ContextFlags: DWORD,
pub MxCsr: DWORD,
pub SegCs: WORD,
pub SegDs: WORD,
pub SegEs: WORD,
pub SegFs: WORD,
pub SegGs: WORD,
pub SegSs: WORD,
pub EFlags: DWORD,
pub Dr0: DWORDLONG,
pub Dr1: DWORDLONG,
pub Dr2: DWORDLONG,
pub Dr3: DWORDLONG,
pub Dr6: DWORDLONG,
pub Dr7: DWORDLONG,
pub Rax: DWORDLONG,
pub Rcx: DWORDLONG,
pub Rdx: DWORDLONG,
pub Rbx: DWORDLONG,
pub Rsp: DWORDLONG,
pub Rbp: DWORDLONG,
pub Rsi: DWORDLONG,
pub Rdi: DWORDLONG,
pub R8: DWORDLONG,
pub R9: DWORDLONG,
pub R10: DWORDLONG,
pub R11: DWORDLONG,
pub R12: DWORDLONG,
pub R13: DWORDLONG,
pub R14: DWORDLONG,
pub R15: DWORDLONG,
pub Rip: DWORDLONG,
pub FltSave: FLOATING_SAVE_AREA,
pub VectorRegister: [M128A; 26],
pub VectorControl: DWORDLONG,
pub DebugControl: DWORDLONG,
pub LastBranchToRip: DWORDLONG,
pub LastBranchFromRip: DWORDLONG,
pub LastExceptionToRip: DWORDLONG,
pub LastExceptionFromRip: DWORDLONG,
}
#[repr(C)]
pub struct M128A {
pub Low: u64,
pub High: i64,
}
}
#[repr(C)]
#[cfg(target_arch = "x86_64")]
#[derive(Copy, Clone)]
pub struct FLOATING_SAVE_AREA {
_Dummy: [u8; 512],
}
#[cfg(target_arch = "arm")]
ffi! {
// #[repr(C)]
// pub struct NEON128 {
// pub Low: ULONG64,
// pub High: LONG64,
// }
// pub type PNEON128 = *mut NEON128;
#[repr(C)]
pub struct CONTEXT_u {
// pub Q: [NEON128; 16],
pub D: [ULONG64; 32],
// pub S: [DWORD; 32],
}
pub const ARM_MAX_BREAKPOINTS: usize = 8;
pub const ARM_MAX_WATCHPOINTS: usize = 1;
#[repr(C)]
pub struct CONTEXT {
pub ContextFlags: DWORD,
pub R0: DWORD,
pub R1: DWORD,
pub R2: DWORD,
pub R3: DWORD,
pub R4: DWORD,
pub R5: DWORD,
pub R6: DWORD,
pub R7: DWORD,
pub R8: DWORD,
pub R9: DWORD,
pub R10: DWORD,
pub R11: DWORD,
pub R12: DWORD,
pub Sp: DWORD,
pub Lr: DWORD,
pub Pc: DWORD,
pub Cpsr: DWORD,
pub Fpsrc: DWORD,
pub Padding: DWORD,
pub u: CONTEXT_u,
pub Bvr: [DWORD; ARM_MAX_BREAKPOINTS],
pub Bcr: [DWORD; ARM_MAX_BREAKPOINTS],
pub Wvr: [DWORD; ARM_MAX_WATCHPOINTS],
pub Wcr: [DWORD; ARM_MAX_WATCHPOINTS],
pub Padding2: [DWORD; 2],
}
} // IFDEF(arm)