diff --git a/Cargo.lock b/Cargo.lock index b72f6821..a2f8b950 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -243,7 +243,7 @@ dependencies = [ "tokio", "tracing", "url", - "windows", + "windows 0.48.0", "xz2", ] @@ -596,6 +596,8 @@ dependencies = [ "cfg-if", "guess_host_triple", "tokio", + "windows-dll", + "windows-sys 0.42.0", ] [[package]] @@ -1617,6 +1619,16 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit", +] + [[package]] name = "proc-macro2" version = "1.0.59" @@ -2857,6 +2869,19 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08746b4b7ac95f708b3cccceb97b7f9a21a8916dd47fc99b0e6aaf7208f26fd7" +dependencies = [ + "windows_aarch64_msvc 0.35.0", + "windows_i686_gnu 0.35.0", + "windows_i686_msvc 0.35.0", + "windows_x86_64_gnu 0.35.0", + "windows_x86_64_msvc 0.35.0", +] + [[package]] name = "windows" version = "0.48.0" @@ -2866,6 +2891,30 @@ dependencies = [ "windows-targets 0.48.0", ] +[[package]] +name = "windows-dll" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0895e287d32aad509d5720ea1975e5d22b2fa51fc3e1f94163cdb73b185b5555" +dependencies = [ + "once_cell", + "thiserror", + "windows 0.35.0", + "windows-dll-codegen", +] + +[[package]] +name = "windows-dll-codegen" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7c2f703a1e16b2447f1ce6c6a7c9231535fef0ca2e260f4bc69ecc8e06b208b" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "windows-sys" version = "0.42.0" @@ -2941,6 +2990,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3bc5134e8ce0da5d64dcec3529793f1d33aee5a51fc2b4662e0f881dd463e6" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -2953,6 +3008,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +[[package]] +name = "windows_i686_gnu" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0343a6f35bf43a07b009b8591b78b10ea03de86b06f48e28c96206cd0f453b50" + [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -2965,6 +3026,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +[[package]] +name = "windows_i686_msvc" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1acdcbf4ca63d8e7a501be86fee744347186275ec2754d129ddeab7a1e3a02e4" + [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -2977,6 +3044,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +[[package]] +name = "windows_x86_64_gnu" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "893c0924c5a990ec73cd2264d1c0cba1773a929e1a3f5dbccffd769f8c4edebb" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -3001,6 +3074,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +[[package]] +name = "windows_x86_64_msvc" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a29bd61f32889c822c99a8fdf2e93378bd2fae4d7efd2693fab09fcaaf7eff4b" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" diff --git a/crates/detect-targets/Cargo.toml b/crates/detect-targets/Cargo.toml index 1f5d7a58..56d49dc5 100644 --- a/crates/detect-targets/Cargo.toml +++ b/crates/detect-targets/Cargo.toml @@ -14,5 +14,9 @@ tokio = { version = "1.28.2", features = ["rt", "process", "sync"], default-feat cfg-if = "1.0.0" guess_host_triple = "0.1.3" +[target.'cfg(target_os = "windows")'.dependencies] +windows-sys = { version = "0.42.0", features = ["Win32_System_Threading", "Win32_System_SystemInformation", "Win32_Foundation"] } +windows-dll = { version = "0.4.1", features = ["windows"], default-features = false } + [dev-dependencies] tokio = { version = "1.28.2", features = ["macros"], default-features = false } diff --git a/crates/detect-targets/src/detect/windows.rs b/crates/detect-targets/src/detect/windows.rs index 04e86428..e4178796 100644 --- a/crates/detect-targets/src/detect/windows.rs +++ b/crates/detect-targets/src/detect/windows.rs @@ -1,6 +1,111 @@ -pub(super) fn detect_alternative_targets(target: &str) -> Option { - let (prefix, abi) = target.rsplit_once('-')?; +use std::mem; +use windows_dll::dll; +use windows_sys::{ + core::HRESULT, + Win32::System::{ + SystemInformation::{ + IMAGE_FILE_MACHINE, IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_ARM, + IMAGE_FILE_MACHINE_ARM64, IMAGE_FILE_MACHINE_I386, + }, + Threading::{UserEnabled, Wow64Container, MACHINE_ATTRIBUTES}, + }, +}; - // detect abi in ["gnu", "gnullvm", ...] - (abi != "msvc").then(|| format!("{prefix}-msvc")) +#[dll("Kernel32")] +extern "system" { + #[allow(non_snake_case)] + #[fallible] + fn GetMachineTypeAttributes( + machine: IMAGE_FILE_MACHINE, + machine_attributes: *mut MACHINE_ATTRIBUTES, + ) -> HRESULT; +} + +fn is_arch_supported(arch: IMAGE_FILE_MACHINE) -> bool { + let mut machine_attributes = mem::MaybeUninit::uninit(); + + // SAFETY: GetMachineTypeAttributes takes type IMAGE_FILE_MACHINE + // plus it takes a pointer to machine_attributes which is only + // written to. + match unsafe { GetMachineTypeAttributes(arch, machine_attributes.as_mut_ptr()) } { + Ok(0) => { + // SAFETY: Symbol GetMachineTypeAttributes exists and calls to it + // succceeds. + // + // Thus, machine_attributes is initialized. + let machine_attributes = unsafe { machine_attributes.assume_init() }; + + (machine_attributes & (Wow64Container | UserEnabled)) != 0 + } + _ => false, + } +} + +pub(super) fn detect_alternative_targets(target: &str) -> impl Iterator { + let (prefix, abi) = target + .rsplit_once('-') + .expect("unwrap: target always has a -"); + + let arch = prefix + .split_once('-') + .expect("unwrap: target always has at least two -") + .0; + + let msvc_fallback_target = (abi != "msvc").then(|| format!("{prefix}-msvc")); + + let gnu_fallback_targets = (abi == "msvc") + .then(|| [format!("{prefix}-gnu"), format!("{prefix}-gnullvm")]) + .into_iter() + .flatten(); + + let x64_fallback_targets = (arch != "x86_64" && is_arch_supported(IMAGE_FILE_MACHINE_AMD64)) + .then_some([ + "x86_64-pc-windows-msvc", + "x86_64-pc-windows-gnu", + "x86_64-pc-windows-gnullvm", + ]) + .into_iter() + .flatten() + .map(ToString::to_string); + + let x86_fallback_targets = (arch != "x86" && is_arch_supported(IMAGE_FILE_MACHINE_I386)) + .then_some([ + "i586-pc-windows-msvc", + "i586-pc-windows-gnu", + "i586-pc-windows-gnullvm", + "i686-pc-windows-msvc", + "i686-pc-windows-gnu", + "i686-pc-windows-gnullvm", + ]) + .into_iter() + .flatten() + .map(ToString::to_string); + + let arm32_fallback_targets = (arch != "thumbv7a" && is_arch_supported(IMAGE_FILE_MACHINE_ARM)) + .then_some([ + "thumbv7a-pc-windows-msvc", + "thumbv7a-pc-windows-gnu", + "thumbv7a-pc-windows-gnullvm", + ]) + .into_iter() + .flatten() + .map(ToString::to_string); + + let arm64_fallback_targets = (arch != "aarch64" && is_arch_supported(IMAGE_FILE_MACHINE_ARM64)) + .then_some([ + "aarch64-pc-windows-msvc", + "aarch64-pc-windows-gnu", + "aarch64-pc-windows-gnullvm", + ]) + .into_iter() + .flatten() + .map(ToString::to_string); + + msvc_fallback_target + .into_iter() + .chain(gnu_fallback_targets) + .chain(x64_fallback_targets) + .chain(x86_fallback_targets) + .chain(arm32_fallback_targets) + .chain(arm64_fallback_targets) }