diff --git a/Cargo.lock b/Cargo.lock index 38b5fe1b..e4a21b70 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -93,9 +93,9 @@ checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" [[package]] name = "libc" -version = "0.2.159" +version = "0.2.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" +checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" [[package]] name = "libloading" diff --git a/Cargo.toml b/Cargo.toml index c2d4f15b..b363e458 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,7 @@ cpp_demangle = { default-features = false, version = "0.4.0", optional = true, f "alloc", ] } -[target.'cfg(windows)'.dependencies] +[target.'cfg(any(windows, target_os = "cygwin"))'.dependencies] windows-targets = "0.52.6" [target.'cfg(not(all(windows, target_env = "msvc", not(target_vendor = "uwp"))))'.dependencies] diff --git a/crates/as-if-std/Cargo.toml b/crates/as-if-std/Cargo.toml index 092905fe..9e11b5e0 100644 --- a/crates/as-if-std/Cargo.toml +++ b/crates/as-if-std/Cargo.toml @@ -27,7 +27,7 @@ default-features = false optional = true features = ['read_core', 'elf', 'macho', 'pe', 'xcoff', 'unaligned', 'archive'] -[target.'cfg(windows)'.dependencies] +[target.'cfg(any(windows, target_os = "cygwin"))'.dependencies] windows-targets = "0.52.6" [features] diff --git a/src/lib.rs b/src/lib.rs index 1377509d..13ca6b58 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -247,5 +247,5 @@ mod lock { ))] mod dbghelp; // Auto-generated by windows-bindgen/riddle -#[cfg(windows)] +#[cfg(any(windows, target_os = "cygwin"))] mod windows_sys; diff --git a/src/symbolize/gimli.rs b/src/symbolize/gimli.rs index e92f98b5..19756c17 100644 --- a/src/symbolize/gimli.rs +++ b/src/symbolize/gimli.rs @@ -43,6 +43,7 @@ cfg_if::cfg_if! { target_os = "solaris", target_os = "illumos", target_os = "aix", + target_os = "cygwin", ))] { #[path = "gimli/mmap_unix.rs"] mod mmap; @@ -193,7 +194,7 @@ fn mmap(path: &Path) -> Option { } cfg_if::cfg_if! { - if #[cfg(windows)] { + if #[cfg(any(windows, target_os = "cygwin"))] { mod coff; use self::coff::{handle_split_dwarf, Object}; } else if #[cfg(any(target_vendor = "apple"))] { @@ -209,7 +210,7 @@ cfg_if::cfg_if! { } cfg_if::cfg_if! { - if #[cfg(windows)] { + if #[cfg(any(windows, target_os = "cygwin"))] { mod libs_windows; use libs_windows::native_libraries; } else if #[cfg(target_vendor = "apple")] { diff --git a/src/symbolize/gimli/libs_windows.rs b/src/symbolize/gimli/libs_windows.rs index 355dc068..1d9a74cc 100644 --- a/src/symbolize/gimli/libs_windows.rs +++ b/src/symbolize/gimli/libs_windows.rs @@ -1,6 +1,5 @@ use super::super::super::windows_sys::*; use super::mystd::ffi::OsString; -use super::mystd::os::windows::prelude::*; use super::{coff, mmap, Library, LibrarySegment}; use alloc::vec; use alloc::vec::Vec; @@ -43,13 +42,79 @@ unsafe fn add_loaded_images(ret: &mut Vec) { } } +// Safety: long_path should be null-terminated +#[cfg(target_os = "cygwin")] +unsafe fn get_posix_path(long_path: &[u16]) -> Option { + use super::mystd::os::unix::ffi::OsStringExt; + + unsafe extern "C" { + // Doc: https://cygwin.com/cygwin-api/func-cygwin-conv-path.html + // Src: https://github.com/cygwin/cygwin/blob/718a15ba50e0d01c79800bd658c2477f9a603540/winsup/cygwin/path.cc#L3902 + // Safety: + // * `what` should be `CCP_WIN_W_TO_POSIX` here + // * `from` is null-terminated UTF-16 path + // * `to` is buffer, the buffer size is `size`. + fn cygwin_conv_path( + what: libc::c_uint, + from: *const u16, + to: *mut u8, + size: libc::size_t, + ) -> libc::ssize_t; + } + const CCP_WIN_W_TO_POSIX: libc::c_uint = 3; + + // If `size` is 0, returns needed buffer size, including null terminator; + // or -1 if error. + // Safety: if `size` is 0, `to` is not used. + let name_len = unsafe { + cygwin_conv_path( + CCP_WIN_W_TO_POSIX, + long_path.as_ptr(), + core::ptr::null_mut(), + 0, + ) + }; + // Expect at least 1 for null terminator. + // It's not likely to return error here. + if name_len < 1 { + return None; + } + let name_len = name_len as usize; + let mut name_buffer = Vec::with_capacity(name_len); + // Safety: `name_buffer` is large enough. + let res = unsafe { + cygwin_conv_path( + CCP_WIN_W_TO_POSIX, + long_path.as_ptr(), + name_buffer.as_mut_ptr(), + name_len, + ) + }; + // It's not likely to return error here. + if res != 0 { + return None; + } + // Remove the null terminator. + unsafe { name_buffer.set_len(name_len - 1) }; + let name = OsString::from_vec(name_buffer); + Some(name) +} + unsafe fn load_library(me: &MODULEENTRY32W) -> Option { - let pos = me - .szExePath - .iter() - .position(|i| *i == 0) - .unwrap_or(me.szExePath.len()); - let name = OsString::from_wide(&me.szExePath[..pos]); + #[cfg(windows)] + let name = { + use super::mystd::os::windows::prelude::*; + let pos = me + .szExePath + .iter() + .position(|i| *i == 0) + .unwrap_or(me.szExePath.len()); + OsString::from_wide(&me.szExePath[..pos]) + }; + #[cfg(target_os = "cygwin")] + // Safety: the path with max length MAX_PATH always contains a null + // terminator. Don't slice it. + let name = unsafe { get_posix_path(&me.szExePath[..])? }; // MinGW libraries currently don't support ASLR // (rust-lang/rust#16514), but DLLs can still be relocated around in