diff --git a/procfs-core/src/kallsyms.rs b/procfs-core/src/kallsyms.rs new file mode 100644 index 0000000..f960d0a --- /dev/null +++ b/procfs-core/src/kallsyms.rs @@ -0,0 +1,133 @@ +use std::io::BufRead; +use std::str::FromStr; + +use crate::{FromBufRead, ProcError, ProcResult}; + +#[cfg(feature = "serde1")] +use serde::{Deserialize, Serialize}; + +/// KAllSyms entries under `/proc/kallsyms` +#[derive(Debug, Clone)] +#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] +pub struct KAllSyms { + /// Kernel symbols + pub symbols: Vec, +} + +/// A kernel symbol entry under `/proc/kallsyms` +#[derive(Debug, Clone)] +#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] +pub struct KAllSymsEntry { + /// Address of the symbol + pub address: u64, + /// Symbol type + pub symbol_type: char, + /// Symbol name + pub name: String, + /// Optional module name + pub module_name: Option, +} + +impl FromBufRead for KAllSyms { + fn from_buf_read(r: R) -> ProcResult { + let mut symbols = Vec::new(); + for line in r.lines() { + let line = line?; + let entry = KAllSymsEntry::from_str(&line)?; + symbols.push(entry); + } + Ok(KAllSyms { symbols }) + } +} + +impl std::str::FromStr for KAllSymsEntry { + type Err = ProcError; + + fn from_str(s: &str) -> Result { + let mut it = s.splitn(3, ' '); + let address = from_str!(u64, expect!(it.next()), 16); + let symbol_type = expect!(it.next()); + + let symbol_type = { + if symbol_type.len() != 1 { + return Err(ProcError::Other(format!( + "Invalid symbol type: {}, expected a single character", + symbol_type + ))); + } + symbol_type.chars().next().unwrap() + }; + + let mut it = expect!(it.next()).splitn(2, '\t'); + let name = expect!(it.next()).to_string(); + + let module_name = if let Some(module_name) = it.next() { + // Check [ and ] around module name + if module_name.starts_with('[') && module_name.ends_with(']') { + Some(module_name[1..module_name.len() - 1].to_string()) + } else { + return Err(ProcError::Other(format!( + "Invalid module name format: {}, expected [module_name]", + module_name + ))); + } + } else { + None + }; + + Ok(KAllSymsEntry { + address, + symbol_type, + name, + module_name, + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_kallsymsentry() { + let s = "c000000000000000 T _text"; + let entry = KAllSymsEntry::from_str(s).unwrap(); + assert_eq!(entry.address, 0xc000000000000000); + assert_eq!(entry.symbol_type, 'T'); + assert_eq!(entry.name, "_text"); + assert!(entry.module_name.is_none()); + + let s = "c000000000000000 T _text\t[module_name]"; + let entry = KAllSymsEntry::from_str(s).unwrap(); + assert_eq!(entry.address, 0xc000000000000000); + assert_eq!(entry.symbol_type, 'T'); + assert_eq!(entry.name, "_text"); + assert_eq!(entry.module_name.unwrap(), "module_name"); + } + + #[test] + fn test_kallsyms() { + let data = "cb00000000000000 T _text +c000000000000000 T _start +c000000000000100 t bpf_text\t[bpf] +"; + let mut reader = std::io::Cursor::new(data); + let kallsyms = KAllSyms::from_buf_read(&mut reader).unwrap(); + + assert_eq!(kallsyms.symbols.len(), 3); + assert_eq!(kallsyms.symbols[0].address, 0xcb00000000000000); + assert_eq!(kallsyms.symbols[0].symbol_type, 'T'); + assert_eq!(kallsyms.symbols[0].name, "_text"); + assert!(kallsyms.symbols[0].module_name.is_none()); + + assert_eq!(kallsyms.symbols[1].address, 0xc000000000000000); + assert_eq!(kallsyms.symbols[1].symbol_type, 'T'); + assert_eq!(kallsyms.symbols[1].name, "_start"); + assert!(kallsyms.symbols[1].module_name.is_none()); + + assert_eq!(kallsyms.symbols[2].address, 0xc000000000000100); + assert_eq!(kallsyms.symbols[2].symbol_type, 't'); + assert_eq!(kallsyms.symbols[2].name, "bpf_text"); + assert_eq!(kallsyms.symbols[2].module_name.as_ref().unwrap(), "bpf"); + } +} diff --git a/procfs-core/src/lib.rs b/procfs-core/src/lib.rs index 34c77cf..352b88e 100644 --- a/procfs-core/src/lib.rs +++ b/procfs-core/src/lib.rs @@ -361,6 +361,9 @@ pub use diskstats::*; mod iomem; pub use iomem::*; +mod kallsyms; +pub use kallsyms::*; + pub mod keyring; mod locks; diff --git a/procfs/src/lib.rs b/procfs/src/lib.rs index 451c8a6..1ea1986 100644 --- a/procfs/src/lib.rs +++ b/procfs/src/lib.rs @@ -449,6 +449,15 @@ pub fn diskstats() -> ProcResult> { DiskStats::current().map(|d| d.0) } +impl Current for KAllSyms { + const PATH: &'static str = "/proc/kallsyms"; +} + +/// Get a list of kernel symbols from `/proc/kallsyms` +pub fn kallsyms() -> ProcResult> { + KAllSyms::current().map(|k| k.symbols) +} + impl Current for Vec { const PATH: &'static str = "/proc/mounts"; } @@ -704,6 +713,13 @@ mod tests { } } + #[test] + fn test_kallsyms() { + for symbol in kallsyms().unwrap() { + println!("{:?}", symbol); + } + } + #[test] fn test_locks() { for lock in locks().unwrap() { diff --git a/support.md b/support.md index 5e3ff9d..770b17a 100644 --- a/support.md +++ b/support.md @@ -83,7 +83,7 @@ This is an approximate list of all the files under the `/proc` mount, and an ind * [ ] `/proc/interrupts` * [x] `/proc/iomem` * [ ] `/proc/ioports` -* [ ] `/proc/kallsyms` +* [x] `/proc/kallsyms` * [ ] `/proc/kcore` * [x] `/proc/keys` * [x] `/proc/key-users`