use std::path::{Path, PathBuf};
pub(crate) fn find_vmlinux(kernel_path: &Path) -> Option<PathBuf> {
let dir = kernel_path.parent()?;
let candidate = dir.join("vmlinux");
if candidate.exists() {
return Some(candidate);
}
if let Ok(root) = dir.join("../../..").canonicalize() {
let candidate = root.join("vmlinux");
if candidate.exists() {
return Some(candidate);
}
}
if let Some(name) = kernel_path.file_name().and_then(|n| n.to_str()) {
let version = name.strip_prefix("vmlinuz-").unwrap_or(name);
for candidate in [
PathBuf::from(format!("/usr/lib/debug/boot/vmlinux-{version}")),
PathBuf::from(format!("/boot/vmlinux-{version}")),
PathBuf::from(format!("/lib/modules/{version}/build/vmlinux")),
] {
if candidate.exists() {
return Some(candidate);
}
}
}
if let Some(parent_name) = dir.file_name().and_then(|n| n.to_str()) {
for candidate in [
dir.join("build/vmlinux"),
PathBuf::from(format!("/boot/vmlinux-{parent_name}")),
] {
if candidate.exists() {
return Some(candidate);
}
}
}
None
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[cfg(target_arch = "x86_64")]
fn find_vmlinux_from_bzimage_path() {
let tmp = std::env::temp_dir().join("ktstr-find-vmlinux-test");
let boot_dir = tmp.join("arch/x86/boot");
std::fs::create_dir_all(&boot_dir).unwrap();
let vmlinux = tmp.join("vmlinux");
std::fs::write(&vmlinux, b"ELF").unwrap();
let bzimage = boot_dir.join("bzImage");
std::fs::write(&bzimage, b"kernel").unwrap();
let found = find_vmlinux(&bzimage);
assert_eq!(found, Some(vmlinux));
std::fs::remove_dir_all(&tmp).unwrap();
}
#[test]
fn find_vmlinux_sibling() {
let tmp = std::env::temp_dir().join("ktstr-find-vmlinux-sibling");
std::fs::create_dir_all(&tmp).unwrap();
let vmlinux = tmp.join("vmlinux");
std::fs::write(&vmlinux, b"ELF").unwrap();
let kernel = tmp.join("bzImage");
std::fs::write(&kernel, b"kernel").unwrap();
let found = find_vmlinux(&kernel);
assert_eq!(found, Some(vmlinux));
std::fs::remove_dir_all(&tmp).unwrap();
}
#[test]
fn find_vmlinux_bare_filename() {
assert_eq!(find_vmlinux(Path::new("vmlinuz")), None);
}
#[test]
fn find_vmlinux_root_parent() {
let result = find_vmlinux(Path::new("/vmlinuz"));
if !Path::new("/vmlinux").exists() {
assert_eq!(result, None);
}
}
#[test]
fn find_vmlinux_missing_returns_none() {
let tmp = std::env::temp_dir().join("ktstr-find-vmlinux-none");
std::fs::create_dir_all(&tmp).unwrap();
let kernel = tmp.join("bzImage");
std::fs::write(&kernel, b"kernel").unwrap();
assert_eq!(find_vmlinux(&kernel), None);
std::fs::remove_dir_all(&tmp).unwrap();
}
}