mirror of https://github.com/rust-lang/rust.git
113 lines
3.9 KiB
Rust
113 lines
3.9 KiB
Rust
// Check that the compiler toolchain (rustc) that we distribute is not using newer glibc
|
|
// symbols than a specified minimum.
|
|
// This test should only be executed on an extracted dist archive or in a dist-* CI job.
|
|
|
|
//@ only-dist
|
|
//@ only-x86_64-unknown-linux-gnu
|
|
//@ ignore-cross-compile
|
|
|
|
use std::path::{Path, PathBuf};
|
|
|
|
use run_make_support::{cmd, llvm_objdump, regex, rustc_path};
|
|
|
|
fn main() {
|
|
// This is the maximum glibc version that we are *permitted* to use for the
|
|
// x86_64-unknown-linux-gnu target.
|
|
// All glibc symbols used in the compiler must be lower or equal than this version.
|
|
// So that if a given machine only has glibc 2.17, it is able to run the compiler.
|
|
let max_supported = (2, 17, 99);
|
|
|
|
let rustc = PathBuf::from(rustc_path());
|
|
// Check symbols directly in rustc
|
|
check_symbols(&rustc, max_supported);
|
|
|
|
// Find dynamic libraries referenced by rustc that come from our lib directory
|
|
let lib_path = rustc.parent().unwrap().parent().unwrap().join("lib");
|
|
let dynamic_libs = find_dynamic_libs(&rustc)
|
|
.into_iter()
|
|
.filter_map(|path| path.canonicalize().ok())
|
|
.filter(|lib| lib.starts_with(&lib_path))
|
|
.collect::<Vec<_>>();
|
|
for lib in dynamic_libs {
|
|
check_symbols(&lib, max_supported);
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq)]
|
|
struct GlibcSymbol {
|
|
name: String,
|
|
version: (u32, u32, u32),
|
|
}
|
|
|
|
fn find_dynamic_libs(path: &Path) -> Vec<PathBuf> {
|
|
cmd("ldd")
|
|
.arg(path)
|
|
.run()
|
|
.stdout_utf8()
|
|
.lines()
|
|
.filter_map(|line| {
|
|
let line = line.trim();
|
|
let Some((_, line)) = line.split_once(" => ") else {
|
|
return None;
|
|
};
|
|
line.split_ascii_whitespace().next().map(|path| PathBuf::from(path))
|
|
})
|
|
.collect()
|
|
}
|
|
|
|
fn check_symbols(file: &Path, max_supported: (u32, u32, u32)) {
|
|
println!("Checking {}", file.display());
|
|
let mut invalid: Vec<GlibcSymbol> = get_glibc_symbols(file)
|
|
.into_iter()
|
|
.filter(|symbol| symbol.version > max_supported)
|
|
.collect();
|
|
if !invalid.is_empty() {
|
|
invalid.sort();
|
|
panic!(
|
|
"Found invalid glibc symbols in {}:\n{}",
|
|
file.display(),
|
|
invalid
|
|
.into_iter()
|
|
.map(|symbol| format!(
|
|
"{} ({:?} higher than max allowed {:?})",
|
|
symbol.name, symbol.version, max_supported
|
|
))
|
|
.collect::<Vec<_>>()
|
|
.join("\n")
|
|
)
|
|
}
|
|
}
|
|
|
|
fn get_glibc_symbols(file: &Path) -> Vec<GlibcSymbol> {
|
|
let regex = regex::Regex::new(r#"GLIBC_(\d)+\.(\d+)(:?\.(\d+))?"#).unwrap();
|
|
|
|
// FIXME(kobzol): llvm-objdump currently chokes on the BOLTed librustc_driver.so file.
|
|
// Use objdump instead, since it seems to work, and we only run this test in a specific
|
|
// CI environment anyway.
|
|
cmd("objdump")
|
|
.arg("--dynamic-syms")
|
|
.arg(file)
|
|
.run()
|
|
.stdout_utf8()
|
|
.lines()
|
|
.filter_map(|line| {
|
|
// Example line
|
|
// 0000000000000000 DF *UND* 0000000000000000 (GLIBC_2.2.5) sbrk
|
|
let mut parts = line.split(" ").collect::<Vec<_>>().into_iter().rev();
|
|
let Some(name) = parts.next() else {
|
|
return None;
|
|
};
|
|
let Some(lib) = parts.next() else {
|
|
return None;
|
|
};
|
|
let Some(version) = regex.captures(lib) else {
|
|
return None;
|
|
};
|
|
let major = version.get(1).and_then(|m| m.as_str().parse().ok()).unwrap_or(0);
|
|
let minor = version.get(2).and_then(|m| m.as_str().parse().ok()).unwrap_or(0);
|
|
let patch = version.get(3).and_then(|m| m.as_str().parse().ok()).unwrap_or(0);
|
|
Some(GlibcSymbol { version: (major, minor, patch), name: name.to_string() })
|
|
})
|
|
.collect()
|
|
}
|