Skip to content

Commit

Permalink
symbolizer: add symbol store
Browse files Browse the repository at this point in the history
  • Loading branch information
noneback committed Jul 25, 2024
1 parent f0b4f52 commit dd53bce
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 30 deletions.
2 changes: 1 addition & 1 deletion doctor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ thiserror = "1.0.63"
procfs = "0.16.0"
clap = "4.5.9"
goblin = {version = "0.8.2", features = ["elf32","elf32"]}
moka = { version = "0.12.8", features = ["future"] }
moka = { version = "0.12.8", features = ["future","sync"] }

[[bin]]
name = "doctor"
Expand Down
6 changes: 5 additions & 1 deletion doctor/src/symbolizer/error.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
use std::path::PathBuf;

use thiserror::Error;

#[derive(Error, Debug)]
pub enum SymbolizerError {
#[error("fail to open symbol store:{0}")]
#[error("fail to open symbol store: {0}")]
OpenSymbolStoreFailed(#[from] std::io::Error),
#[error("failed to fetch elf: {0}")]
FetchElfFailed(PathBuf),
}
98 changes: 70 additions & 28 deletions doctor/src/symbolizer/symbol_store.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,30 @@
use anyhow::Error;
use goblin::elf::{Elf, Sym};
use std::clone;
use goblin::elf::Elf;
use std::cmp::Ordering;
use std::collections::{BTreeSet, HashSet};
use std::collections::BTreeSet;
use std::fmt::Display;
use std::fs::File;
use std::hash::{Hash, Hasher};
use std::io::{BufReader, Read};
use std::path::PathBuf;

use moka::future::Cache;
use moka::sync::Cache;

use super::error::SymbolizerError;

#[derive(PartialEq, Eq, PartialOrd, Clone)]
#[derive(PartialEq, Eq, PartialOrd, Clone, Debug)]
struct Symbol {
pub(crate) addr: u64,


pub(crate) name: String,
pub(crate) name: Option<String>,
}

impl Display for Symbol {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self.name {
Some(name) => write!(f, "{} (f_0x{:016X})", name, self.addr),
None => write!(f, "Unnamed (f_0x{:016X})", self.addr),
}
}
}

impl Hash for Symbol {
fn hash<H: Hasher>(&self, state: &mut H) {
Expand All @@ -38,21 +43,41 @@ impl Ord for Symbol {
// use rusqlite::Connection;
pub struct SymbolStore {
cache: Cache<PathBuf, BTreeSet<Symbol>>,
// db: Connection,
}

impl SymbolStore {
pub fn new(path: PathBuf) -> Result<SymbolStore, SymbolizerError> {
// let conn = Connection::open(path)?;
Ok(Self {
pub fn new(path: PathBuf) -> SymbolStore {
Self {
cache: Cache::new(100),
// db: conn,
})
}
}

pub fn get_symbol(&self, dso: &PathBuf, offset: u64) -> Option<Symbol> {
let syms = self.fetch_elf(&dso).unwrap();
let target = Symbol {
addr: offset,
name: None,
};

match syms.range(..target).next_back() {
Some(s) => Some(s.clone()),
None => None,
}
}

pub fn fetch_process(pid: u64) {}
fn fetch_elf(&self, dso: &PathBuf) -> Result<BTreeSet<Symbol>, SymbolizerError> {
self.load_elf(dso)?;
match self.cache.get(dso) {
Some(val) => Ok(val),
None => Err(SymbolizerError::FetchElfFailed(dso.clone())),
}
}

fn load_elf(&self, dso: &PathBuf) -> Result<(), SymbolizerError> {
if self.cache.contains_key(dso) {
return Ok(());
}

pub fn fetch_elf(&self, dso: PathBuf) -> Result<(), Error> {
let file = File::open(dso.clone())?;
let mut reader = BufReader::new(file);
let mut buffer = Vec::new();
Expand All @@ -65,8 +90,16 @@ impl SymbolStore {
.filter(|s| s.is_function())
.map(|sym| {
let addr = sym.st_value;
let name = elf.strtab.get_at(sym.st_name).unwrap_or("unknow");
Symbol { addr, String::from("test") }
match elf.dynstrtab.get_at(sym.st_name) {
Some(n) => Symbol {
addr: addr,
name: Some(String::from(n)),
},
None => Symbol {
addr: addr,
name: None,
},
}
})
.collect::<BTreeSet<_>>();

Expand All @@ -76,29 +109,38 @@ impl SymbolStore {
.filter(|s| s.is_function())
.map(|sym| {
let addr = sym.st_value;
let name = elf.dynstrtab.get_at(sym.st_name).unwrap_or("unknow");
Symbol { addr, name }
match elf.dynstrtab.get_at(sym.st_name) {
Some(n) => Symbol {
addr: addr,
name: Some(String::from(n)),
},
None => Symbol {
addr: addr,
name: None,
},
}
})
.collect::<BTreeSet<_>>();

syms.extend(dyn_syms);
self.cache.insert(dso, syms);
self.cache.insert(dso.clone(), syms);
Ok(())
}
}

#[cfg(test)]
mod tests {
use super::*;
use std::env;

#[test]
fn test_fetch_elf() {
// 获取当前可执行文件路径
println!("start");
let ss = SymbolStore::new("./".into()).unwrap();
ss.fetch_elf("/proc/135657/root/usr/lib64/mysql/private/libprotobuf-lite.so.3.19.4".into())
.unwrap();
println!("end");
let ss = SymbolStore::new("./".into());
let sym = ss.get_symbol(
&"/usr/local/aegis/aegis_client/aegis_11_91/libFileQuara.so".into(),
0x65417,
);

println!("sym:\n {}", sym.unwrap());
}
}

0 comments on commit dd53bce

Please sign in to comment.