From 9b8afd2c5c37246f989ad5edb06e4b9c619c961e Mon Sep 17 00:00:00 2001 From: Julien THILLARD Date: Wed, 18 Mar 2026 19:58:23 +0100 Subject: [PATCH] Clean way to patch the std --- crates/std/Cargo.toml | 1 + crates/std/justfile | 31 +-- crates/std/patches.sed | 6 - crates/std/src/alloc.rs | 164 ++++++++-------- crates/std/src/lib.rs | 1 + crates/std/src/panicking.rs | 4 +- crates/std/src/sys/backtrace.rs | 328 ++++++++++++++++---------------- 7 files changed, 258 insertions(+), 277 deletions(-) diff --git a/crates/std/Cargo.toml b/crates/std/Cargo.toml index 6baaff8..4c67fc0 100644 --- a/crates/std/Cargo.toml +++ b/crates/std/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2024" [dependencies] +backtrace_rs = { package = "backtrace", version = "0.3", default-features = false } hashbrown = "0.16" os-std-macros = { path = "../os-std-macros" } shared = { path = "../shared", features = ["user"] } diff --git a/crates/std/justfile b/crates/std/justfile index fcbc083..5656b24 100644 --- a/crates/std/justfile +++ b/crates/std/justfile @@ -6,25 +6,13 @@ patch-std: @echo "Start patching the std..." @find {{ PATCH_DIR }} -type f | while read -r patch_file; do \ relative_path="${patch_file#{{ PATCH_DIR }}/}"; \ - case "$patch_file" in \ - *.rs) \ - echo "📄 [COPY] $relative_path"; \ - mkdir -p "{{ SRC_DIR }}/$(dirname "$relative_path")"; \ - cp "$patch_file" "{{ SRC_DIR }}/$relative_path"; \ - ;; \ - *.sed) \ - target_file="${relative_path%.sed}.rs"; \ - if [ -f "{{ SRC_DIR }}/$target_file" ]; then \ - echo " [SED] $target_file"; \ - sed -i -f "$patch_file" "{{ SRC_DIR }}/$target_file"; \ - else \ - echo "⚠️[WARN] target doesn't exist: $target_file"; \ - fi \ - ;; \ - *) \ - echo "❓ [SKIP] Unknown file : $relative_path"; \ - ;; \ - esac; \ + target_file="${relative_path%.sed}.rs"; \ + if [ -f "{{ SRC_DIR }}/$target_file" ]; then \ + echo " [SED] $target_file"; \ + sed -i -f "$patch_file" "{{ SRC_DIR }}/$target_file"; \ + else \ + echo "⚠ [WARN] target doesn't exist: $target_file"; \ + fi; \ done @echo "✅ Patching done." @@ -167,13 +155,14 @@ setup-std: @just cp_std "sys/io/is_terminal/unsupported.rs" @just cp_std "sys/io/kernel_copy/mod.rs" @just cp_std "sys/io/mod.rs" + @just cp_std "sys/io/error/mod.rs" @just cp_std "sys/pipe/mod.rs" @just cp_std "sys/pipe/unsupported.rs" @just cp_std "sys/stdio/mod.rs" @just cp_std "sys/stdio/unsupported.rs" @just cp_std "sys/alloc/mod.rs" + @just cp_std "sys/backtrace.rs" + @just cp_std "alloc.rs" @# Copied but edited for the moment # @just cp_std "sys/process/unsupported.rs" - @just cp_std "sys/io/error/mod.rs" - # @just cp_std "alloc.rs" # @just cp_std "path.rs" diff --git a/crates/std/patches.sed b/crates/std/patches.sed index 6c95e2d..1913a3e 100644 --- a/crates/std/patches.sed +++ b/crates/std/patches.sed @@ -5,11 +5,5 @@ s|alloc::slice::Join|alloc_crate::slice::Join|g s|alloc::bstr|alloc_crate::bstr|g s|alloc::collections::TryReserveError|alloc_crate::collections::TryReserveError|g s|crate::collections::VecDeque|alloc_crate::collections::VecDeque|g -# s|collections::HashMap|hashbrown::HashMap|g -/crate::backtrace_rs/c \ todo!() /crate::sys::os::getpid/c \ todo!() /\[doc = include_str!/c \ // todo retreive docs -# /target_os = "xous",/a \ target_os = "survos", - -# Ajouter d'autres modifications facilement ici : -# s|ancien_texte|nouveau_texte|g diff --git a/crates/std/src/alloc.rs b/crates/std/src/alloc.rs index 3d1c652..ed0322e 100644 --- a/crates/std/src/alloc.rs +++ b/crates/std/src/alloc.rs @@ -340,95 +340,95 @@ pub fn set_alloc_error_hook(hook: fn(Layout)) { HOOK.store(hook as *mut (), Ordering::Release); } -// /// Unregisters the current allocation error hook, returning it. -// /// -// /// *See also the function [`set_alloc_error_hook`].* -// /// -// /// If no custom hook is registered, the default hook will be returned. -// #[unstable(feature = "alloc_error_hook", issue = "51245")] -// pub fn take_alloc_error_hook() -> fn(Layout) { -// let hook = HOOK.swap(ptr::null_mut(), Ordering::Acquire); -// if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } } -// } +/// Unregisters the current allocation error hook, returning it. +/// +/// *See also the function [`set_alloc_error_hook`].* +/// +/// If no custom hook is registered, the default hook will be returned. +#[unstable(feature = "alloc_error_hook", issue = "51245")] +pub fn take_alloc_error_hook() -> fn(Layout) { + let hook = HOOK.swap(ptr::null_mut(), Ordering::Acquire); + if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } } +} -// #[optimize(size)] -// fn default_alloc_error_hook(layout: Layout) { -// if cfg!(panic = "immediate-abort") { -// return; -// } +#[optimize(size)] +fn default_alloc_error_hook(layout: Layout) { + if cfg!(panic = "immediate-abort") { + return; + } -// // This is the default path taken on OOM, and the only path taken on stable with std. -// // Crucially, it does *not* call any user-defined code, and therefore users do not have to -// // worry about allocation failure causing reentrancy issues. That makes it different from -// // the default `__rdl_alloc_error_handler` defined in alloc (i.e., the default alloc error -// // handler that is called when there is no `#[alloc_error_handler]`), which triggers a -// // regular panic and thus can invoke a user-defined panic hook, executing arbitrary -// // user-defined code. + // This is the default path taken on OOM, and the only path taken on stable with std. + // Crucially, it does *not* call any user-defined code, and therefore users do not have to + // worry about allocation failure causing reentrancy issues. That makes it different from + // the default `__rdl_alloc_error_handler` defined in alloc (i.e., the default alloc error + // handler that is called when there is no `#[alloc_error_handler]`), which triggers a + // regular panic and thus can invoke a user-defined panic hook, executing arbitrary + // user-defined code. -// static PREV_ALLOC_FAILURE: AtomicBool = AtomicBool::new(false); -// if PREV_ALLOC_FAILURE.swap(true, Ordering::Relaxed) { -// // Don't try to print a backtrace if a previous alloc error happened. This likely means -// // there is not enough memory to print a backtrace, although it could also mean that two -// // threads concurrently run out of memory. -// rtprintpanic!( -// "memory allocation of {} bytes failed\nskipping backtrace printing to avoid potential recursion\n", -// layout.size() -// ); -// return; -// } else { -// rtprintpanic!("memory allocation of {} bytes failed\n", layout.size()); -// } + static PREV_ALLOC_FAILURE: AtomicBool = AtomicBool::new(false); + if PREV_ALLOC_FAILURE.swap(true, Ordering::Relaxed) { + // Don't try to print a backtrace if a previous alloc error happened. This likely means + // there is not enough memory to print a backtrace, although it could also mean that two + // threads concurrently run out of memory. + rtprintpanic!( + "memory allocation of {} bytes failed\nskipping backtrace printing to avoid potential recursion\n", + layout.size() + ); + return; + } else { + rtprintpanic!("memory allocation of {} bytes failed\n", layout.size()); + } -// let Some(mut out) = crate::sys::stdio::panic_output() else { -// return; -// }; + let Some(mut out) = crate::sys::stdio::panic_output() else { + return; + }; -// // Use a lock to prevent mixed output in multithreading context. -// // Some platforms also require it when printing a backtrace, like `SymFromAddr` on Windows. -// // Make sure to not take this lock until after checking PREV_ALLOC_FAILURE to avoid deadlocks -// // when there is too little memory to print a backtrace. -// let mut lock = crate::sys::backtrace::lock(); + // Use a lock to prevent mixed output in multithreading context. + // Some platforms also require it when printing a backtrace, like `SymFromAddr` on Windows. + // Make sure to not take this lock until after checking PREV_ALLOC_FAILURE to avoid deadlocks + // when there is too little memory to print a backtrace. + let mut lock = crate::sys::backtrace::lock(); -// match crate::panic::get_backtrace_style() { -// Some(crate::panic::BacktraceStyle::Short) => { -// drop(lock.print(&mut out, crate::backtrace_rs::PrintFmt::Short)) -// } -// Some(crate::panic::BacktraceStyle::Full) => { -// drop(lock.print(&mut out, crate::backtrace_rs::PrintFmt::Full)) -// } -// Some(crate::panic::BacktraceStyle::Off) => { -// use crate::io::Write; -// let _ = writeln!( -// out, -// "note: run with `RUST_BACKTRACE=1` environment variable to display a \ -// backtrace" -// ); -// if cfg!(miri) { -// let _ = writeln!( -// out, -// "note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` \ -// for the environment variable to have an effect" -// ); -// } -// } -// // If backtraces aren't supported or are forced-off, do nothing. -// None => {} -// } -// } + match crate::panic::get_backtrace_style() { + Some(crate::panic::BacktraceStyle::Short) => { + drop(lock.print(&mut out, crate::backtrace_rs::PrintFmt::Short)) + } + Some(crate::panic::BacktraceStyle::Full) => { + drop(lock.print(&mut out, crate::backtrace_rs::PrintFmt::Full)) + } + Some(crate::panic::BacktraceStyle::Off) => { + use crate::io::Write; + let _ = writeln!( + out, + "note: run with `RUST_BACKTRACE=1` environment variable to display a \ + backtrace" + ); + if cfg!(miri) { + let _ = writeln!( + out, + "note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` \ + for the environment variable to have an effect" + ); + } + } + // If backtraces aren't supported or are forced-off, do nothing. + None => {} + } +} -// #[cfg(not(test))] -// #[doc(hidden)] -// #[alloc_error_handler] -// #[unstable(feature = "alloc_internals", issue = "none")] -// pub fn rust_oom(layout: Layout) -> ! { -// crate::sys::backtrace::__rust_end_short_backtrace(|| { -// let hook = HOOK.load(Ordering::Acquire); -// let hook: fn(Layout) = -// if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } }; -// hook(layout); -// crate::process::abort() -// }) -// } +#[cfg(not(test))] +#[doc(hidden)] +#[alloc_error_handler] +#[unstable(feature = "alloc_internals", issue = "none")] +pub fn rust_oom(layout: Layout) -> ! { + crate::sys::backtrace::__rust_end_short_backtrace(|| { + let hook = HOOK.load(Ordering::Acquire); + let hook: fn(Layout) = + if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } }; + hook(layout); + crate::process::abort() + }) +} #[cfg(not(test))] #[doc(hidden)] diff --git a/crates/std/src/lib.rs b/crates/std/src/lib.rs index 29e057d..cf236d9 100644 --- a/crates/std/src/lib.rs +++ b/crates/std/src/lib.rs @@ -295,6 +295,7 @@ pub mod sync; pub mod sys; pub mod thread; pub mod time; +pub use backtrace_rs; #[prelude_import] #[allow(unused_imports)] diff --git a/crates/std/src/panicking.rs b/crates/std/src/panicking.rs index a21aafe..a4a974d 100644 --- a/crates/std/src/panicking.rs +++ b/crates/std/src/panicking.rs @@ -286,10 +286,10 @@ fn default_hook(info: &PanicHookInfo<'_>) { match backtrace { Some(BacktraceStyle::Short) => { - todo!() + drop(lock.print(err, crate::backtrace_rs::PrintFmt::Short)) } Some(BacktraceStyle::Full) => { - todo!() + drop(lock.print(err, crate::backtrace_rs::PrintFmt::Full)) } Some(BacktraceStyle::Off) => { if FIRST_PANIC.swap(false, Ordering::Relaxed) { diff --git a/crates/std/src/sys/backtrace.rs b/crates/std/src/sys/backtrace.rs index 4bf30c3..858a958 100644 --- a/crates/std/src/sys/backtrace.rs +++ b/crates/std/src/sys/backtrace.rs @@ -1,7 +1,7 @@ //! Common code for printing backtraces. #![forbid(unsafe_op_in_unsafe_fn)] -// use crate::backtrace_rs::{self, BacktraceFmt, BytesOrWideString, PrintFmt}; +use crate::backtrace_rs::{self, BacktraceFmt, BytesOrWideString, PrintFmt}; use crate::borrow::Cow; use crate::io::prelude::*; use crate::path::{self, Path, PathBuf}; @@ -24,140 +24,136 @@ pub(crate) fn lock<'a>() -> BacktraceLock<'a> { BacktraceLock(LOCK.lock().unwrap_or_else(PoisonError::into_inner)) } -// impl BacktraceLock<'_> { -// /// Prints the current backtrace. -// pub(crate) fn print(&mut self, w: &mut dyn Write, format: PrintFmt) -> io::Result<()> { -// // There are issues currently linking libbacktrace into tests, and in -// // general during std's own unit tests we're not testing this path. In -// // test mode immediately return here to optimize away any references to the -// // libbacktrace symbols -// if cfg!(test) { -// return Ok(()); -// } +impl BacktraceLock<'_> { + /// Prints the current backtrace. + pub(crate) fn print(&mut self, w: &mut dyn Write, format: PrintFmt) -> io::Result<()> { + // There are issues currently linking libbacktrace into tests, and in + // general during std's own unit tests we're not testing this path. In + // test mode immediately return here to optimize away any references to the + // libbacktrace symbols + if cfg!(test) { + return Ok(()); + } -// struct DisplayBacktrace { -// format: PrintFmt, -// } -// impl fmt::Display for DisplayBacktrace { -// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { -// // SAFETY: the backtrace lock is held -// unsafe { _print_fmt(fmt, self.format) } -// } -// } -// write!(w, "{}", DisplayBacktrace { format }) -// } -// } + struct DisplayBacktrace { + format: PrintFmt, + } + impl fmt::Display for DisplayBacktrace { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + // SAFETY: the backtrace lock is held + unsafe { _print_fmt(fmt, self.format) } + } + } + write!(w, "{}", DisplayBacktrace { format }) + } +} -// /// # Safety -// /// -// /// This function is not Sync. The caller must hold a mutex lock, or there must be only one thread in the program. -// unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::Result { -// // Always 'fail' to get the cwd when running under Miri - -// // this allows Miri to display backtraces in isolation mode -// let cwd = if !cfg!(miri) { -// env::current_dir().ok() -// } else { -// None -// }; +/// # Safety +/// +/// This function is not Sync. The caller must hold a mutex lock, or there must be only one thread in the program. +unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::Result { + // Always 'fail' to get the cwd when running under Miri - + // this allows Miri to display backtraces in isolation mode + let cwd = if !cfg!(miri) { env::current_dir().ok() } else { None }; -// let mut print_path = move |fmt: &mut fmt::Formatter<'_>, bows: BytesOrWideString<'_>| { -// output_filename(fmt, bows, print_fmt, cwd.as_ref()) -// }; -// writeln!(fmt, "stack backtrace:")?; -// let mut bt_fmt = BacktraceFmt::new(fmt, print_fmt, &mut print_path); -// bt_fmt.add_context()?; -// let mut idx = 0; -// let mut res = Ok(()); -// let mut omitted_count: usize = 0; -// let mut first_omit = true; -// // If we're using a short backtrace, ignore all frames until we're told to start printing. -// let mut print = print_fmt != PrintFmt::Short; -// set_image_base(); -// // SAFETY: we roll our own locking in this town -// unsafe { -// backtrace_rs::trace_unsynchronized(|frame| { -// if print_fmt == PrintFmt::Short && idx > MAX_NB_FRAMES { -// return false; -// } + let mut print_path = move |fmt: &mut fmt::Formatter<'_>, bows: BytesOrWideString<'_>| { + output_filename(fmt, bows, print_fmt, cwd.as_ref()) + }; + writeln!(fmt, "stack backtrace:")?; + let mut bt_fmt = BacktraceFmt::new(fmt, print_fmt, &mut print_path); + bt_fmt.add_context()?; + let mut idx = 0; + let mut res = Ok(()); + let mut omitted_count: usize = 0; + let mut first_omit = true; + // If we're using a short backtrace, ignore all frames until we're told to start printing. + let mut print = print_fmt != PrintFmt::Short; + set_image_base(); + // SAFETY: we roll our own locking in this town + unsafe { + backtrace_rs::trace_unsynchronized(|frame| { + if print_fmt == PrintFmt::Short && idx > MAX_NB_FRAMES { + return false; + } -// if cfg!(feature = "backtrace-trace-only") { -// const HEX_WIDTH: usize = 2 + 2 * size_of::(); -// let frame_ip = frame.ip(); -// res = writeln!(bt_fmt.formatter(), "{idx:4}: {frame_ip:HEX_WIDTH$?}"); -// } else { -// let mut hit = false; -// backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| { -// hit = true; + if cfg!(feature = "backtrace-trace-only") { + const HEX_WIDTH: usize = 2 + 2 * size_of::(); + let frame_ip = frame.ip(); + res = writeln!(bt_fmt.formatter(), "{idx:4}: {frame_ip:HEX_WIDTH$?}"); + } else { + let mut hit = false; + backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| { + hit = true; -// // `__rust_end_short_backtrace` means we are done hiding symbols -// // for now. Print until we see `__rust_begin_short_backtrace`. -// if print_fmt == PrintFmt::Short { -// if let Some(sym) = symbol.name().and_then(|s| s.as_str()) { -// if sym.contains("__rust_end_short_backtrace") { -// print = true; -// return; -// } -// if print && sym.contains("__rust_begin_short_backtrace") { -// print = false; -// return; -// } -// if !print { -// omitted_count += 1; -// } -// } -// } + // `__rust_end_short_backtrace` means we are done hiding symbols + // for now. Print until we see `__rust_begin_short_backtrace`. + if print_fmt == PrintFmt::Short { + if let Some(sym) = symbol.name().and_then(|s| s.as_str()) { + if sym.contains("__rust_end_short_backtrace") { + print = true; + return; + } + if print && sym.contains("__rust_begin_short_backtrace") { + print = false; + return; + } + if !print { + omitted_count += 1; + } + } + } -// if print { -// if omitted_count > 0 { -// debug_assert!(print_fmt == PrintFmt::Short); -// // only print the message between the middle of frames -// if !first_omit { -// let _ = writeln!( -// bt_fmt.formatter(), -// " [... omitted {} frame{} ...]", -// omitted_count, -// if omitted_count > 1 { "s" } else { "" } -// ); -// } -// first_omit = false; -// omitted_count = 0; -// } -// res = bt_fmt.frame().symbol(frame, symbol); -// } -// }); -// #[cfg(all(target_os = "nto", any(target_env = "nto70", target_env = "nto71")))] -// if libc::__my_thread_exit as *mut libc::c_void == frame.ip() { -// if !hit && print { -// use crate::backtrace_rs::SymbolName; -// res = bt_fmt.frame().print_raw( -// frame.ip(), -// Some(SymbolName::new("__my_thread_exit".as_bytes())), -// None, -// None, -// ); -// } -// return false; -// } -// if !hit && print { -// res = bt_fmt.frame().print_raw(frame.ip(), None, None, None); -// } -// } + if print { + if omitted_count > 0 { + debug_assert!(print_fmt == PrintFmt::Short); + // only print the message between the middle of frames + if !first_omit { + let _ = writeln!( + bt_fmt.formatter(), + " [... omitted {} frame{} ...]", + omitted_count, + if omitted_count > 1 { "s" } else { "" } + ); + } + first_omit = false; + omitted_count = 0; + } + res = bt_fmt.frame().symbol(frame, symbol); + } + }); + #[cfg(all(target_os = "nto", any(target_env = "nto70", target_env = "nto71")))] + if libc::__my_thread_exit as *mut libc::c_void == frame.ip() { + if !hit && print { + use crate::backtrace_rs::SymbolName; + res = bt_fmt.frame().print_raw( + frame.ip(), + Some(SymbolName::new("__my_thread_exit".as_bytes())), + None, + None, + ); + } + return false; + } + if !hit && print { + res = bt_fmt.frame().print_raw(frame.ip(), None, None, None); + } + } -// idx += 1; -// res.is_ok() -// }) -// }; -// res?; -// bt_fmt.finish()?; -// if print_fmt == PrintFmt::Short { -// writeln!( -// fmt, -// "note: Some details are omitted, \ -// run with `RUST_BACKTRACE=full` for a verbose backtrace." -// )?; -// } -// Ok(()) -// } + idx += 1; + res.is_ok() + }) + }; + res?; + bt_fmt.finish()?; + if print_fmt == PrintFmt::Short { + writeln!( + fmt, + "note: Some details are omitted, \ + run with `RUST_BACKTRACE=full` for a verbose backtrace." + )?; + } + Ok(()) +} /// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that /// this is only inline(never) when backtraces in std are enabled, otherwise @@ -191,44 +187,44 @@ where result } -// /// Prints the filename of the backtrace frame. -// /// -// /// See also `output`. -// pub fn output_filename( -// fmt: &mut fmt::Formatter<'_>, -// bows: BytesOrWideString<'_>, -// print_fmt: PrintFmt, -// cwd: Option<&PathBuf>, -// ) -> fmt::Result { -// let file: Cow<'_, Path> = match bows { -// #[cfg(unix)] -// BytesOrWideString::Bytes(bytes) => { -// use crate::os::unix::prelude::*; -// Path::new(crate::ffi::OsStr::from_bytes(bytes)).into() -// } -// #[cfg(not(unix))] -// BytesOrWideString::Bytes(bytes) => { -// Path::new(crate::str::from_utf8(bytes).unwrap_or("")).into() -// } -// #[cfg(windows)] -// BytesOrWideString::Wide(wide) => { -// use crate::os::windows::prelude::*; -// Cow::Owned(crate::ffi::OsString::from_wide(wide).into()) -// } -// #[cfg(not(windows))] -// BytesOrWideString::Wide(_wide) => Path::new("").into(), -// }; -// if print_fmt == PrintFmt::Short && file.is_absolute() { -// if let Some(cwd) = cwd { -// if let Ok(stripped) = file.strip_prefix(&cwd) { -// if let Some(s) = stripped.to_str() { -// return write!(fmt, ".{}{s}", path::MAIN_SEPARATOR); -// } -// } -// } -// } -// fmt::Display::fmt(&file.display(), fmt) -// } +/// Prints the filename of the backtrace frame. +/// +/// See also `output`. +pub fn output_filename( + fmt: &mut fmt::Formatter<'_>, + bows: BytesOrWideString<'_>, + print_fmt: PrintFmt, + cwd: Option<&PathBuf>, +) -> fmt::Result { + let file: Cow<'_, Path> = match bows { + #[cfg(unix)] + BytesOrWideString::Bytes(bytes) => { + use crate::os::unix::prelude::*; + Path::new(crate::ffi::OsStr::from_bytes(bytes)).into() + } + #[cfg(not(unix))] + BytesOrWideString::Bytes(bytes) => { + Path::new(crate::str::from_utf8(bytes).unwrap_or("")).into() + } + #[cfg(windows)] + BytesOrWideString::Wide(wide) => { + use crate::os::windows::prelude::*; + Cow::Owned(crate::ffi::OsString::from_wide(wide).into()) + } + #[cfg(not(windows))] + BytesOrWideString::Wide(_wide) => Path::new("").into(), + }; + if print_fmt == PrintFmt::Short && file.is_absolute() { + if let Some(cwd) = cwd { + if let Ok(stripped) = file.strip_prefix(&cwd) { + if let Some(s) = stripped.to_str() { + return write!(fmt, ".{}{s}", path::MAIN_SEPARATOR); + } + } + } + } + fmt::Display::fmt(&file.display(), fmt) +} #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] pub fn set_image_base() {