diff --git a/Cargo.lock b/Cargo.lock index c2b7f2d6bf..e8bc582b63 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4978,6 +4978,12 @@ dependencies = [ "yaxpeax-x86", ] +[[package]] +name = "ksym" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b543b77d8cfa33302b6b51b6a255f9e85b06997b7c4a0a7354fcc8304036eb09" + [[package]] name = "ktest-helper" version = "0.1.1" @@ -7955,6 +7961,7 @@ dependencies = [ "inherit-methods-macro", "kernel-elf-parser", "kprobe", + "ksym", "ktracepoint", "linux-raw-sys 0.12.1", "lock_api", diff --git a/os/StarryOS/kernel/Cargo.toml b/os/StarryOS/kernel/Cargo.toml index 54289cd536..66ac1c52aa 100644 --- a/os/StarryOS/kernel/Cargo.toml +++ b/os/StarryOS/kernel/Cargo.toml @@ -138,6 +138,7 @@ sg200x-bsp = { workspace = true, optional = true } # because Writeable trait must come from the same version as sg200x-bsp's types. tock-registers = { version = "0.9", optional = true } ktracepoint = "0.6" +ksym = "0.6" [target.'cfg(target_arch = "x86_64")'.dependencies] x86 = "0.52" diff --git a/os/StarryOS/kernel/src/pseudofs/dev/mod.rs b/os/StarryOS/kernel/src/pseudofs/dev/mod.rs index 459af3989a..fa482e1c1c 100644 --- a/os/StarryOS/kernel/src/pseudofs/dev/mod.rs +++ b/os/StarryOS/kernel/src/pseudofs/dev/mod.rs @@ -269,7 +269,7 @@ fn builder(fs: Arc) -> DirMaker { #[cfg(feature = "dev-log")] root.add( "log", - crate::pseudofs::SimpleFile::new(fs.clone(), NodeType::Socket, || Ok(b"")), + crate::pseudofs::SimpleFile::new(fs.clone(), NodeType::Socket, || Ok("")), ); #[cfg(feature = "memtrack")] diff --git a/os/StarryOS/kernel/src/pseudofs/file.rs b/os/StarryOS/kernel/src/pseudofs/file.rs index 73476f1bb4..a8341c998c 100644 --- a/os/StarryOS/kernel/src/pseudofs/file.rs +++ b/os/StarryOS/kernel/src/pseudofs/file.rs @@ -1,4 +1,4 @@ -use alloc::{borrow::Cow, sync::Arc, vec::Vec}; +use alloc::{borrow::Cow, string::String, sync::Arc, vec::Vec}; use core::{any::Any, cmp::Ordering, task::Context}; use ax_sync::Mutex; @@ -16,7 +16,9 @@ pub trait SimpleFileOps: Send + Sync + 'static { /// Reads all content in the file. fn read_all(&self) -> VfsResult>; /// Replaces the file's content with `data`. - fn write_all(&self, data: &[u8]) -> VfsResult<()>; + fn write_all(&self, _data: &[u8]) -> VfsResult<()> { + Err(VfsError::BadFileDescriptor) + } } /// Type representing operation applied to a simple file. @@ -56,17 +58,42 @@ where } } +pub trait SimpleFileContent { + /// Converts the content into bytes. + fn into_content(self) -> Cow<'static, [u8]>; +} + +impl SimpleFileContent for Vec { + fn into_content(self) -> Cow<'static, [u8]> { + Cow::Owned(self) + } +} + +impl SimpleFileContent for String { + fn into_content(self) -> Cow<'static, [u8]> { + Cow::Owned(self.into_bytes()) + } +} + +impl SimpleFileContent for &'static str { + fn into_content(self) -> Cow<'static, [u8]> { + Cow::Borrowed(self.as_bytes()) + } +} + +impl SimpleFileContent for &'static [u8] { + fn into_content(self) -> Cow<'static, [u8]> { + Cow::Borrowed(self) + } +} + impl SimpleFileOps for F where F: Fn() -> VfsResult + Send + Sync + 'static, - R: Into>, + R: SimpleFileContent, { fn read_all(&self) -> VfsResult> { - (self)().map(|it| Cow::Owned(it.into())) - } - - fn write_all(&self, _data: &[u8]) -> VfsResult<()> { - Err(VfsError::BadFileDescriptor) + Ok((self)()?.into_content()) } } @@ -262,8 +289,8 @@ impl FileNodeOps for SpecialFsFile { } fn append(&self, buf: &[u8]) -> VfsResult<(usize, u64)> { - self.ops.write_at(buf, 0)?; - Ok((buf.len(), 0)) + let w = self.ops.write_at(buf, 0)?; + Ok((w, 0)) } fn set_len(&self, len: u64) -> VfsResult<()> { diff --git a/os/StarryOS/kernel/src/pseudofs/proc.rs b/os/StarryOS/kernel/src/pseudofs/proc.rs index 4dd7d4cc8e..b16c7dce0b 100644 --- a/os/StarryOS/kernel/src/pseudofs/proc.rs +++ b/os/StarryOS/kernel/src/pseudofs/proc.rs @@ -14,6 +14,7 @@ use core::{ sync::atomic::{AtomicUsize, Ordering}, }; +use ax_lazyinit::LazyInit; use ax_memory_addr::PAGE_SIZE_4K; use ax_runtime::hal::{ paging::MappingFlags, @@ -21,6 +22,7 @@ use ax_runtime::hal::{ }; use ax_task::{AxCpuMask, AxTaskRef, TaskState, WeakAxTaskRef, current}; use axfs_ng_vfs::{DeviceId, Filesystem, NodePermission, NodeType, VfsError, VfsResult}; +use ksym::KallsymsMapped; use starry_process::{Pid, Process}; use crate::{ @@ -41,6 +43,36 @@ use crate::{ static IRQ_CNT: AtomicUsize = AtomicUsize::new(0); const PROCFS_INIT_PID: Pid = 1; +pub static KALLSYMS: LazyInit> = LazyInit::new(); + +fn read_kallsyms() -> KallsymsMapped<'static> { + unsafe extern "C" { + fn _stext(); + fn _etext(); + fn __kallsyms_start(); + fn __kallsyms_end(); + } + + let kallsyms_start = __kallsyms_start as *const () as usize; + let kallsyms_end = __kallsyms_end as *const () as usize; + let kallsyms_sec_size = kallsyms_end - kallsyms_start; + let kallsyms_sec = + unsafe { core::slice::from_raw_parts(__kallsyms_start as *const u8, kallsyms_sec_size) }; + + let total_size = + KallsymsMapped::check_total_bytes(kallsyms_sec).expect("Invalid kallsyms format"); + + let kallsyms = &kallsyms_sec[..total_size as usize]; + // TODO: recycle unused space in .kallsyms section + info!("Read kallsyms, size: {}KB", kallsyms.len() / 1024); + KallsymsMapped::from_blob( + kallsyms, + _stext as *const () as u64, + _etext as *const () as u64, + ) + .expect("Failed to create KallsymsMapped") +} + fn procfs_visible_pid(proc: &Arc) -> Pid { if proc.is_init() { PROCFS_INIT_PID @@ -961,6 +993,23 @@ fn builder(fs: Arc) -> DirMaker { SimpleDir::new_maker(fs.clone(), Arc::new(dynamic_debug)) }); + static ALL_SYMS: LazyInit = LazyInit::new(); + + let ksym = read_kallsyms(); + KALLSYMS.init_once(ksym); + + root.add("kallsyms", { + if !ALL_SYMS.is_inited() { + ALL_SYMS.init_once(KALLSYMS.dump_all_symbols()); + } + let seq_obj = SeqObject::new(|| Ok(ALL_SYMS.as_str())); + SpecialFsFile::new_regular_with_perm( + fs.clone(), + seq_obj, + NodePermission::from_bits_truncate(0o444), + ) + }); + let proc_dir = ProcFsHandler(fs.clone()); SimpleDir::new_maker(fs, Arc::new(proc_dir.chain(root))) } diff --git a/os/StarryOS/starryos/ext_linker.ld b/os/StarryOS/starryos/ext_linker.ld index 8e8253d8ed..b8db0952ab 100644 --- a/os/StarryOS/starryos/ext_linker.ld +++ b/os/StarryOS/starryos/ext_linker.ld @@ -16,6 +16,12 @@ SECTIONS { KEEP(*(.tracepoint .tracepoint.*)) __stop_tracepoint = .; } + + .kallsyms : ALIGN(4K) { + __kallsyms_start = .; + . += 8M; /* reserve space for kallsyms, can be recycled */ + __kallsyms_end = .; + } } -INSERT AFTER .data; \ No newline at end of file +INSERT AFTER .data; diff --git a/scripts/axbuild/scripts/starry-kallsyms.sh b/scripts/axbuild/scripts/starry-kallsyms.sh new file mode 100644 index 0000000000..372a0a29eb --- /dev/null +++ b/scripts/axbuild/scripts/starry-kallsyms.sh @@ -0,0 +1,104 @@ +#!/usr/bin/env sh +set -eu + +auto_install_enabled() { + case "${AXBUILD_STARRY_KALLSYMS_AUTO_INSTALL:-1}" in + 0 | n | no | false | off) return 1 ;; + *) return 0 ;; + esac +} + +install_rust_binutils() { + if ! auto_install_enabled; then + echo "rust-nm and rust-objcopy are required for Starry kallsyms generation" >&2 + echo "install them with: rustup component add llvm-tools-preview && cargo install cargo-binutils" >&2 + exit 1 + fi + + echo "Installing rust-nm and rust-objcopy (cargo-binutils)..." >&2 + if command -v rustup >/dev/null 2>&1; then + rustup component add llvm-tools-preview + fi + cargo install cargo-binutils +} + +ensure_llvm_tools() { + if command -v rust-nm >/dev/null 2>&1 \ + && command -v rust-objcopy >/dev/null 2>&1 \ + && rust-nm --version >/dev/null 2>&1 \ + && rust-objcopy --version >/dev/null 2>&1; then + return + fi + + if ! command -v rustup >/dev/null 2>&1; then + return + fi + if rustup component list --installed | grep -q '^llvm-tools'; then + return + fi + + if ! auto_install_enabled; then + echo "llvm-tools-preview is required for rust-nm and rust-objcopy" >&2 + echo "install it with: rustup component add llvm-tools-preview" >&2 + exit 1 + fi + + echo "Installing llvm-tools-preview via rustup..." >&2 + rustup component add llvm-tools-preview +} + +install_ksym() { + if ! auto_install_enabled; then + echo "gen_ksym is required for Starry kallsyms generation" >&2 + echo "install it with: cargo install ksym" >&2 + exit 1 + fi + + echo "Installing ksym (gen_ksym) via cargo..." >&2 + cargo install ksym +} + +ensure_tools() { + ensure_llvm_tools + + if ! command -v rust-nm >/dev/null 2>&1 || ! command -v rust-objcopy >/dev/null 2>&1; then + install_rust_binutils + fi + if ! command -v gen_ksym >/dev/null 2>&1; then + install_ksym + fi + + command -v rust-nm >/dev/null 2>&1 + command -v rust-objcopy >/dev/null 2>&1 + command -v gen_ksym >/dev/null 2>&1 +} + +generate_kallsyms() { + symbols=$(mktemp "${KERNEL_ELF}.symbols.XXXXXX") + kallsyms=$(mktemp "${KERNEL_ELF}.kallsyms.XXXXXX") + trap 'rm -f "$symbols" "$kallsyms"' EXIT + + rust-nm -n "$KERNEL_ELF" > "$symbols" + grep ' [TtDBR] ' "$symbols" \ + | awk '$3 !~ /^\.L/' \ + | awk '$3 != "$x"' \ + | gen_ksym > "$kallsyms" + + rust-objcopy --update-section .kallsyms="$kallsyms" "$KERNEL_ELF" +} + +refresh_bin_if_present() { + bin="${KERNEL_ELF%.elf}.bin" + if [ -f "$bin" ]; then + rust-objcopy --strip-all -O binary "$KERNEL_ELF" "$bin" + fi +} + +if [ -z "${KERNEL_ELF:-}" ]; then + echo "KERNEL_ELF is required for Starry kallsyms generation" >&2 + exit 1 +fi + +ensure_tools +generate_kallsyms +refresh_bin_if_present diff --git a/scripts/axbuild/src/arceos/test.rs b/scripts/axbuild/src/arceos/test.rs index 34971c8467..59628343f0 100644 --- a/scripts/axbuild/src/arceos/test.rs +++ b/scripts/axbuild/src/arceos/test.rs @@ -1634,7 +1634,6 @@ mod tests { env: Default::default(), target: "x86_64-unknown-none".to_string(), package: package.to_string(), - bin: None, features: Vec::new(), log: None, extra_config: None, @@ -1644,6 +1643,7 @@ mod tests { pre_build_cmds: Vec::new(), post_build_cmds: Vec::new(), to_bin: false, + bin: None, }, qemu: QemuConfig::default(), } diff --git a/scripts/axbuild/src/build.rs b/scripts/axbuild/src/build.rs index e0bab7f43c..3caf0bbfc7 100644 --- a/scripts/axbuild/src/build.rs +++ b/scripts/axbuild/src/build.rs @@ -159,7 +159,6 @@ impl BuildInfo { env: self.env, target, package, - bin: None, features: self.features, log: Some(self.log), extra_config: None, @@ -169,6 +168,7 @@ impl BuildInfo { pre_build_cmds: vec![], post_build_cmds: vec![], to_bin, + bin: None, } } diff --git a/scripts/axbuild/src/starry/build.rs b/scripts/axbuild/src/starry/build.rs index 7664f5bc3b..e304ffbd3e 100644 --- a/scripts/axbuild/src/starry/build.rs +++ b/scripts/axbuild/src/starry/build.rs @@ -145,6 +145,8 @@ fn patch_starry_cargo_config( .or_insert_with(|| platform.to_string()); } + inject_kallsyms_post_build_cmd(cargo)?; + if cargo.env.get("UIMAGE").map(|v| v.as_str()) == Some("y") { inject_uimage_post_build_cmd(cargo, &request.arch)?; } @@ -152,6 +154,22 @@ fn patch_starry_cargo_config( Ok(()) } +fn inject_kallsyms_post_build_cmd(cargo: &mut Cargo) -> anyhow::Result<()> { + let script = crate::context::workspace_root_path()? + .join("scripts") + .join("axbuild") + .join("scripts") + .join("starry-kallsyms.sh"); + cargo + .post_build_cmds + .push(format!("sh {}", shell_quote(&script.display().to_string()))); + Ok(()) +} + +fn shell_quote(value: &str) -> String { + format!("'{}'", value.replace('\'', "'\\''")) +} + fn uimg_arch_for(arch: &str) -> String { match arch { "aarch64" => "arm64".to_string(), @@ -461,6 +479,8 @@ HELLO = "world" assert_eq!(cargo.env.get("AX_LOG").map(String::as_str), Some("info")); assert_eq!(cargo.env.get("CUSTOM").map(String::as_str), Some("1")); assert!(cargo.to_bin); + assert_eq!(cargo.post_build_cmds.len(), 1); + assert!(cargo.post_build_cmds[0].contains("scripts/axbuild/scripts/starry-kallsyms.sh")); } #[test] @@ -691,4 +711,31 @@ HELLO = "world" assert_eq!(args, vec!["--bin".to_string(), "starryos".to_string()]); } + + #[test] + fn patch_starry_cargo_config_runs_kallsyms_before_uimage_generation() { + let request = request( + PathBuf::from("/tmp/.build.toml"), + "aarch64", + "aarch64-unknown-none-softfloat", + ); + let mut build_info = default_starry_build_info_for_target(&request.target); + build_info.env.insert("UIMAGE".to_string(), "y".to_string()); + build_info.env.insert( + "AX_CONFIG_PATH".to_string(), + "/tmp/.axconfig.toml".to_string(), + ); + let mut cargo = build_info.into_base_cargo_config_with_log( + request.package.clone(), + request.target.clone(), + StarryBuildInfo::build_cargo_args(&request.target, false, &[]), + ); + + let metadata = crate::build::workspace_metadata().unwrap(); + patch_starry_cargo_config(&mut cargo, &request, &metadata).unwrap(); + + assert_eq!(cargo.post_build_cmds.len(), 2); + assert!(cargo.post_build_cmds[0].contains("scripts/axbuild/scripts/starry-kallsyms.sh")); + assert!(cargo.post_build_cmds[1].contains("mkimage")); + } } diff --git a/test-suit/starryos/normal/qemu-smp1/util-linux/qemu-aarch64.toml b/test-suit/starryos/normal/qemu-smp1/util-linux/qemu-aarch64.toml index 2dad49652b..6ebfe58dd9 100644 --- a/test-suit/starryos/normal/qemu-smp1/util-linux/qemu-aarch64.toml +++ b/test-suit/starryos/normal/qemu-smp1/util-linux/qemu-aarch64.toml @@ -2,6 +2,8 @@ args = [ "-nographic", "-cpu", "cortex-a53", + "-m", + "512M", "-device", "virtio-blk-pci,drive=disk0", "-drive", diff --git a/test-suit/starryos/normal/qemu-smp1/util-linux/qemu-loongarch64.toml b/test-suit/starryos/normal/qemu-smp1/util-linux/qemu-loongarch64.toml index ca2e59d304..de5ff7cbd2 100644 --- a/test-suit/starryos/normal/qemu-smp1/util-linux/qemu-loongarch64.toml +++ b/test-suit/starryos/normal/qemu-smp1/util-linux/qemu-loongarch64.toml @@ -5,7 +5,7 @@ args = [ "la464", "-nographic", "-m", - "128M", + "512M", "-device", "virtio-blk-pci,drive=disk0", "-drive", diff --git a/test-suit/starryos/normal/qemu-smp1/util-linux/qemu-riscv64.toml b/test-suit/starryos/normal/qemu-smp1/util-linux/qemu-riscv64.toml index 9aa6085026..a5c178dd36 100644 --- a/test-suit/starryos/normal/qemu-smp1/util-linux/qemu-riscv64.toml +++ b/test-suit/starryos/normal/qemu-smp1/util-linux/qemu-riscv64.toml @@ -1,5 +1,7 @@ args = [ "-nographic", + "-m", + "512M", "-cpu", "rv64", "-device", diff --git a/test-suit/starryos/normal/qemu-smp1/util-linux/qemu-x86_64.toml b/test-suit/starryos/normal/qemu-smp1/util-linux/qemu-x86_64.toml index 8cb956e76a..6b51b6735b 100644 --- a/test-suit/starryos/normal/qemu-smp1/util-linux/qemu-x86_64.toml +++ b/test-suit/starryos/normal/qemu-smp1/util-linux/qemu-x86_64.toml @@ -1,5 +1,7 @@ args = [ "-nographic", + "-m", + "512M", "-device", "virtio-blk-pci,drive=disk0", "-drive",