From f7db955a456a119988f6b916c6aa585c47ad2765 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AE=87=E9=80=B8?= Date: Fri, 28 Mar 2025 13:36:28 +0800 Subject: [PATCH 01/10] Add cygwin support --- Cargo.toml | 2 +- src/lib.rs | 2 +- src/symbolize/gimli.rs | 4 ++-- src/symbolize/gimli/libs_windows.rs | 21 +++++++++++++++++++-- 4 files changed, 23 insertions(+), 6 deletions(-) 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/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..b1527949 100644 --- a/src/symbolize/gimli.rs +++ b/src/symbolize/gimli.rs @@ -193,7 +193,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 +209,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..25aa1ea6 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; @@ -49,7 +48,25 @@ unsafe fn load_library(me: &MODULEENTRY32W) -> Option { .iter() .position(|i| *i == 0) .unwrap_or(me.szExePath.len()); - let name = OsString::from_wide(&me.szExePath[..pos]); + let mut name_buffer = vec![0_u8; pos * 4]; + let name_len = unsafe { + WideCharToMultiByte( + CP_UTF8, + 0, + me.szExePath.as_ptr(), + pos as i32, + name_buffer.as_mut_ptr(), + name_buffer.len() as i32, + core::ptr::null_mut(), + core::ptr::null_mut(), + ) as usize + }; + if name_len == 0 || name_len > name_buffer.len() { + // This can't happen. + return None; + } + unsafe { name_buffer.set_len(name_len) }; + let name = unsafe { OsString::from_encoded_bytes_unchecked(name_buffer) }; // MinGW libraries currently don't support ASLR // (rust-lang/rust#16514), but DLLs can still be relocated around in From 2f6a162106e42cab64e43c60da01ebdd8bf1d990 Mon Sep 17 00:00:00 2001 From: Berrysoft Date: Tue, 1 Apr 2025 12:07:22 +0800 Subject: [PATCH 02/10] Use correct name buffer size --- src/symbolize/gimli/libs_windows.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/symbolize/gimli/libs_windows.rs b/src/symbolize/gimli/libs_windows.rs index 25aa1ea6..b321df71 100644 --- a/src/symbolize/gimli/libs_windows.rs +++ b/src/symbolize/gimli/libs_windows.rs @@ -48,7 +48,19 @@ unsafe fn load_library(me: &MODULEENTRY32W) -> Option { .iter() .position(|i| *i == 0) .unwrap_or(me.szExePath.len()); - let mut name_buffer = vec![0_u8; pos * 4]; + let name_len = unsafe { + WideCharToMultiByte( + CP_UTF8, + 0, + me.szExePath.as_ptr(), + pos as i32, + core::ptr::null_mut(), + 0, + core::ptr::null_mut(), + core::ptr::null_mut(), + ) as usize + }; + let mut name_buffer = vec![0_u8; name_len]; let name_len = unsafe { WideCharToMultiByte( CP_UTF8, From ef10159d871aa469bc3683a1b54e6623898023f4 Mon Sep 17 00:00:00 2001 From: Berrysoft Date: Mon, 28 Apr 2025 10:07:32 +0800 Subject: [PATCH 03/10] Convert path to posix --- src/symbolize/gimli.rs | 1 + src/symbolize/gimli/libs_windows.rs | 81 ++++++++++++++++++----------- 2 files changed, 53 insertions(+), 29 deletions(-) diff --git a/src/symbolize/gimli.rs b/src/symbolize/gimli.rs index b1527949..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; diff --git a/src/symbolize/gimli/libs_windows.rs b/src/symbolize/gimli/libs_windows.rs index b321df71..651b914f 100644 --- a/src/symbolize/gimli/libs_windows.rs +++ b/src/symbolize/gimli/libs_windows.rs @@ -1,5 +1,7 @@ use super::super::super::windows_sys::*; use super::mystd::ffi::OsString; +#[cfg(windows)] +use super::mystd::os::windows::prelude::*; use super::{coff, mmap, Library, LibrarySegment}; use alloc::vec; use alloc::vec::Vec; @@ -42,43 +44,64 @@ unsafe fn add_loaded_images(ret: &mut Vec) { } } -unsafe fn load_library(me: &MODULEENTRY32W) -> Option { - let pos = me - .szExePath - .iter() - .position(|i| *i == 0) - .unwrap_or(me.szExePath.len()); +// Safety: long_path should be null-terminated +#[cfg(target_os = "cygwin")] +unsafe fn get_posix_path(long_path: &[u16]) -> Option { + use std::os::unix::ffi::OsStringExt; + + unsafe extern "C" { + fn cygwin_conv_path( + what: libc::c_uint, + from: *const libc::c_void, + to: *mut libc::c_void, + size: libc::size_t, + ) -> libc::ssize_t; + } + const CCP_WIN_W_TO_POSIX: libc::c_uint = 3; + let name_len = unsafe { - WideCharToMultiByte( - CP_UTF8, - 0, - me.szExePath.as_ptr(), - pos as i32, + cygwin_conv_path( + CCP_WIN_W_TO_POSIX, + long_path.as_ptr().cast(), core::ptr::null_mut(), 0, - core::ptr::null_mut(), - core::ptr::null_mut(), - ) as usize + ) }; + // Expect at least 1 for null terminator. + if name_len < 1 { + return None; + } + let name_len = name_len as usize; let mut name_buffer = vec![0_u8; name_len]; - let name_len = unsafe { - WideCharToMultiByte( - CP_UTF8, - 0, - me.szExePath.as_ptr(), - pos as i32, - name_buffer.as_mut_ptr(), - name_buffer.len() as i32, - core::ptr::null_mut(), - core::ptr::null_mut(), - ) as usize + let res = unsafe { + cygwin_conv_path( + CCP_WIN_W_TO_POSIX, + long_path.as_ptr().cast(), + name_buffer.as_mut_ptr().cast(), + name_buffer.len(), + ) }; - if name_len == 0 || name_len > name_buffer.len() { - // This can't happen. + if res != 0 { return None; } - unsafe { name_buffer.set_len(name_len) }; - let name = unsafe { OsString::from_encoded_bytes_unchecked(name_buffer) }; + // Ignore 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()); + #[cfg(windows)] + let name = OsString::from_wide(&me.szExePath[..pos]); + #[cfg(target_os = "cygwin")] + // Safety: the path with max length MAX_PATH always contains a null + // terminator + let name = unsafe { get_posix_path(&me.szExePath[..pos])? }; // MinGW libraries currently don't support ASLR // (rust-lang/rust#16514), but DLLs can still be relocated around in From 8432d21240751f9e02bdbcd1a372c84c9571c6f3 Mon Sep 17 00:00:00 2001 From: Berrysoft Date: Mon, 28 Apr 2025 10:08:58 +0800 Subject: [PATCH 04/10] Update libc to 0.2.171 to meet cygwin's requirement --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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" From fdc3c80810d7f67763080a331165e349c19abf84 Mon Sep 17 00:00:00 2001 From: Berrysoft Date: Mon, 28 Apr 2025 12:59:28 +0800 Subject: [PATCH 05/10] Use mystd instead of std --- src/symbolize/gimli/libs_windows.rs | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/symbolize/gimli/libs_windows.rs b/src/symbolize/gimli/libs_windows.rs index 651b914f..8a1c5bda 100644 --- a/src/symbolize/gimli/libs_windows.rs +++ b/src/symbolize/gimli/libs_windows.rs @@ -1,7 +1,5 @@ use super::super::super::windows_sys::*; use super::mystd::ffi::OsString; -#[cfg(windows)] -use super::mystd::os::windows::prelude::*; use super::{coff, mmap, Library, LibrarySegment}; use alloc::vec; use alloc::vec::Vec; @@ -47,7 +45,7 @@ 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 std::os::unix::ffi::OsStringExt; + use super::mystd::os::unix::ffi::OsStringExt; unsafe extern "C" { fn cygwin_conv_path( @@ -91,17 +89,20 @@ unsafe fn get_posix_path(long_path: &[u16]) -> Option { } unsafe fn load_library(me: &MODULEENTRY32W) -> Option { - let pos = me - .szExePath - .iter() - .position(|i| *i == 0) - .unwrap_or(me.szExePath.len()); #[cfg(windows)] - let name = OsString::from_wide(&me.szExePath[..pos]); + 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 - let name = unsafe { get_posix_path(&me.szExePath[..pos])? }; + // 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 From 6ec5f9d573c215df527df88917695f3f71481421 Mon Sep 17 00:00:00 2001 From: Berrysoft Date: Tue, 29 Apr 2025 14:05:44 +0800 Subject: [PATCH 06/10] Add docs for cygwin_conv_path --- src/symbolize/gimli/libs_windows.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/symbolize/gimli/libs_windows.rs b/src/symbolize/gimli/libs_windows.rs index 8a1c5bda..42c773a0 100644 --- a/src/symbolize/gimli/libs_windows.rs +++ b/src/symbolize/gimli/libs_windows.rs @@ -48,6 +48,12 @@ 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 `*const u16`, null-terminated, UTF-16 path + // * `to` is `*mut u8` buffer, the buffer size is `size`. fn cygwin_conv_path( what: libc::c_uint, from: *const libc::c_void, @@ -57,6 +63,9 @@ unsafe fn get_posix_path(long_path: &[u16]) -> Option { } 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: **Confirmed from source:** If `size` is 0, `to` is not used. let name_len = unsafe { cygwin_conv_path( CCP_WIN_W_TO_POSIX, @@ -66,11 +75,13 @@ unsafe fn get_posix_path(long_path: &[u16]) -> Option { ) }; // 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![0_u8; name_len]; + // Safety: `name_buffer` is large enough. let res = unsafe { cygwin_conv_path( CCP_WIN_W_TO_POSIX, @@ -79,6 +90,7 @@ unsafe fn get_posix_path(long_path: &[u16]) -> Option { name_buffer.len(), ) }; + // It's not likely to return error here. if res != 0 { return None; } From 698409a0092970aa5736637f164c5b39eaf99558 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AE=87=E9=80=B8?= Date: Wed, 30 Apr 2025 10:49:28 +0800 Subject: [PATCH 07/10] Adjust signature of cygwin_conv_path ...and remove set_len --- src/symbolize/gimli/libs_windows.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/symbolize/gimli/libs_windows.rs b/src/symbolize/gimli/libs_windows.rs index 42c773a0..648ea3fb 100644 --- a/src/symbolize/gimli/libs_windows.rs +++ b/src/symbolize/gimli/libs_windows.rs @@ -52,12 +52,12 @@ unsafe fn get_posix_path(long_path: &[u16]) -> Option { // 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 `*const u16`, null-terminated, UTF-16 path - // * `to` is `*mut u8` buffer, the buffer size is `size`. + // * `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 libc::c_void, - to: *mut libc::c_void, + from: *const u16, + to: *mut u8, size: libc::size_t, ) -> libc::ssize_t; } @@ -69,7 +69,7 @@ unsafe fn get_posix_path(long_path: &[u16]) -> Option { let name_len = unsafe { cygwin_conv_path( CCP_WIN_W_TO_POSIX, - long_path.as_ptr().cast(), + long_path.as_ptr(), core::ptr::null_mut(), 0, ) @@ -85,8 +85,8 @@ unsafe fn get_posix_path(long_path: &[u16]) -> Option { let res = unsafe { cygwin_conv_path( CCP_WIN_W_TO_POSIX, - long_path.as_ptr().cast(), - name_buffer.as_mut_ptr().cast(), + long_path.as_ptr(), + name_buffer.as_mut_ptr(), name_buffer.len(), ) }; @@ -94,8 +94,6 @@ unsafe fn get_posix_path(long_path: &[u16]) -> Option { if res != 0 { return None; } - // Ignore null terminator. - unsafe { name_buffer.set_len(name_len - 1) }; let name = OsString::from_vec(name_buffer); Some(name) } From f26c931219cf423d515214a15a059aaf5db5c563 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AE=87=E9=80=B8?= Date: Wed, 30 Apr 2025 11:05:49 +0800 Subject: [PATCH 08/10] Restore set_len. --- src/symbolize/gimli/libs_windows.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/symbolize/gimli/libs_windows.rs b/src/symbolize/gimli/libs_windows.rs index 648ea3fb..f30187b1 100644 --- a/src/symbolize/gimli/libs_windows.rs +++ b/src/symbolize/gimli/libs_windows.rs @@ -94,6 +94,8 @@ unsafe fn get_posix_path(long_path: &[u16]) -> Option { 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) } From 369afa5992fec6e945fbfbadcf66131e33c713db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AE=87=E9=80=B8?= Date: Wed, 30 Apr 2025 11:29:37 +0800 Subject: [PATCH 09/10] Fix windows-targets dep in as-if-std --- crates/as-if-std/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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] From 366250ef25c27062c0d425479cac1c44a3714546 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AE=87=E9=80=B8?= Date: Wed, 30 Apr 2025 11:38:59 +0800 Subject: [PATCH 10/10] Use Vec::with_capacity to alloc buffer --- src/symbolize/gimli/libs_windows.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/symbolize/gimli/libs_windows.rs b/src/symbolize/gimli/libs_windows.rs index f30187b1..49754bd7 100644 --- a/src/symbolize/gimli/libs_windows.rs +++ b/src/symbolize/gimli/libs_windows.rs @@ -80,14 +80,14 @@ unsafe fn get_posix_path(long_path: &[u16]) -> Option { return None; } let name_len = name_len as usize; - let mut name_buffer = vec![0_u8; name_len]; + 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_buffer.len(), + name_len, ) }; // It's not likely to return error here.