rust: teach the stdlib about our ld.so trickery
We deliver cross-platform cross-compilers in a trimmed-down chroot-like
environment that doesn't need to ever be `chroot`ed into. chromite's
`lddtree.py` sets this up, but the gist is that all binaries inside of
this chroot are executed like `${chroot}/lib/ld-linux-blah.so --args
"${actual_executable}" "$@"`.
This invocation strategy makes `/proc/self/exe` point to
`ld-linux-blah.so` instead of the ELF executable we're "actually"
invoking.
`lddtree.py` generates scripts which already set a special env var to
point to the "original" `argv[0]`, but that's a path relative to the
directory in which the current program was _initially_ invoked, so
that's not very useful as a general approach.
The intent of this change is to detect if the current binary is being
executed using this ld.so trickery. If it is, we should have an env
var(*) that tells us where the 'original' binary is, relative to ld.so,
so we consult that to find the original binary.
(*) -- once the corresponding change for that lands:
https://chromium-review.googlesource.com/c/chromiumos/chromite/+/2424046
BUG=chromium:1003841, chromium:1114301
TEST=Ran `rustc` in this environment; sysroot was properly detected
Change-Id: I6f6c01f08ad99064614dc0219a0eed2e4f481042
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/overlays/chromiumos-overlay/+/2453076
Reviewed-by: LaMont Jones <lamontjones@chromium.org>
Commit-Queue: Mike Nichols <mikenichols@chromium.org>
Tested-by: Mike Nichols <mikenichols@chromium.org>
diff --git a/dev-lang/rust/files/rust-1.46.0-ld-argv0.patch b/dev-lang/rust/files/rust-1.46.0-ld-argv0.patch
new file mode 100644
index 0000000..d967dba
--- /dev/null
+++ b/dev-lang/rust/files/rust-1.46.0-ld-argv0.patch
@@ -0,0 +1,56 @@
+Our cross-compilers and related tooling are executed via ld.so trickery, which
+makes /proc/self/exe not point to the right place. If we detect that we're in
+that situation in `current_exe()`, we _should_ have `LD_ARGV0_REL` in an env
+var. This is the path to the _original_ binary, relative to ld.so.
+
+diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs
+index a9cd509..92dd6b9 100644
+--- a/src/libstd/sys/unix/os.rs
++++ b/src/libstd/sys/unix/os.rs
+@@ -327,12 +327,45 @@ pub fn current_exe() -> io::Result<PathBuf> {
+
+ #[cfg(any(target_os = "linux", target_os = "android", target_os = "emscripten"))]
+ pub fn current_exe() -> io::Result<PathBuf> {
++ let is_ld_so = |p: &crate::path::Path| -> Option<bool> {
++ let parent_dir_name = p.parent()?.file_name()?;
++ if parent_dir_name != OsStr::new("lib") {
++ return Some(false);
++ }
++ // We assume that the `ld.so` path is always valid unicode, since there's... no reason for
++ // it not to be. :)
++ let file_name = p.file_name()?.to_str()?;
++ Some(
++ file_name.starts_with("ld-linux-")
++ && (file_name.ends_with(".so") || file_name.contains(".so.")),
++ )
++ };
++
+ match crate::fs::read_link("/proc/self/exe") {
+ Err(ref e) if e.kind() == io::ErrorKind::NotFound => Err(io::Error::new(
+ io::ErrorKind::Other,
+ "no /proc/self/exe available. Is /proc mounted?",
+ )),
+- other => other,
++ Err(x) => Err(x),
++ Ok(p) => {
++ // Chrome OS-specific: in some configurations, Rust binaries are invoked through
++ // `ld.so`. In these cases, we want to present the user with the path to the Rust
++ // binary that was invoked.
++ //
++ // Because the ld.so wrappers _generally_ don't want to invoke things with absolute
++ // paths, this is _generally_ a path relative to dirname(ld.so).
++ if is_ld_so(&p) == Some(true) {
++ if let Some(relative_to_ld) = crate::env::var_os("LD_ARGV0_REL") {
++ let relative_to_ld = PathBuf::from(relative_to_ld);
++ if relative_to_ld.is_absolute() {
++ return Ok(relative_to_ld);
++ }
++ // safety: is_ld_so checks the parent directory of `p`.
++ return Ok(p.parent().unwrap().join(relative_to_ld));
++ }
++ }
++ Ok(p)
++ }
+ }
+ }
+
diff --git a/dev-lang/rust/rust-1.46.0.ebuild b/dev-lang/rust/rust-1.46.0-r1.ebuild
similarity index 99%
rename from dev-lang/rust/rust-1.46.0.ebuild
rename to dev-lang/rust/rust-1.46.0-r1.ebuild
index d02e97e..d5048f2 100644
--- a/dev-lang/rust/rust-1.46.0.ebuild
+++ b/dev-lang/rust/rust-1.46.0-r1.ebuild
@@ -57,6 +57,7 @@
"${FILESDIR}/${P}-sanitizer-supported.patch"
"${FILESDIR}/${P}-cc.patch"
"${FILESDIR}/${P}-revert-libunwind-build.patch"
+ "${FILESDIR}/${P}-ld-argv0.patch"
)
S="${WORKDIR}/${MY_P}-src"