From ac04c3264cbdff82dd8baa807c9a1a8c5007f98a Mon Sep 17 00:00:00 2001 From: LavenderQAQ Date: Sun, 3 Sep 2023 14:21:08 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=8C=E5=96=84tracepoint=E8=A7=A3?= =?UTF-8?q?=E6=9E=90=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: LavenderQAQ --- lwcb/Cargo.lock | 1 + lwcb/Cargo.toml | 11 +- lwcb/libfirm-rs/src/types.rs | 8 +- lwcb/src/bpf/map/perf.rs | 50 +++--- lwcb/src/lib.rs | 17 +- lwcb/src/perf_event.rs | 37 +--- lwcb/src/tracepoint.rs | 61 +++++++ lwcb/src/types/mod.rs | 11 +- lwcb/src/types/types.rs | 5 +- lwcb/src/utils/btf.rs | 6 +- lwcb/src/utils/tracepoint.rs | 331 +++++++++++++++++++++-------------- 11 files changed, 312 insertions(+), 226 deletions(-) create mode 100644 lwcb/src/tracepoint.rs diff --git a/lwcb/Cargo.lock b/lwcb/Cargo.lock index b36be76..2083c29 100644 --- a/lwcb/Cargo.lock +++ b/lwcb/Cargo.lock @@ -767,6 +767,7 @@ dependencies = [ "perf-event-open-sys", "qbe", "regalloc2", + "regex", "structopt", "strum_macros", "tempfile", diff --git a/lwcb/Cargo.toml b/lwcb/Cargo.toml index 1984e52..088f07b 100644 --- a/lwcb/Cargo.toml +++ b/lwcb/Cargo.toml @@ -34,14 +34,9 @@ env_logger = "0.10.0" uname = "0.1.1" nom = "7.1.3" chrono = "0.4.23" +regex = "1.5" [workspace] -members = [ - "btfparse", - "libfirm-sys", - "libfirm-rs", -] +members = ["btfparse", "libfirm-sys", "libfirm-rs"] -exclude = [ - "pylwcb", -] +exclude = ["pylwcb"] diff --git a/lwcb/libfirm-rs/src/types.rs b/lwcb/libfirm-rs/src/types.rs index e7771e7..41508c0 100644 --- a/lwcb/libfirm-rs/src/types.rs +++ b/lwcb/libfirm-rs/src/types.rs @@ -99,9 +99,7 @@ impl Type { } pub fn set_align(&mut self, align: u32) { - unsafe { - set_type_alignment(self.raw(), align) - } + unsafe { set_type_alignment(self.raw(), align) } } /// create pointer type @@ -159,9 +157,7 @@ impl Type { } pub fn method_res(&self) -> Self { - unsafe { - get_method_res_type(self.raw(), 0).into() - } + unsafe { get_method_res_type(self.raw(), 0).into() } } pub fn params_num(&self) -> u64 { diff --git a/lwcb/src/bpf/map/perf.rs b/lwcb/src/bpf/map/perf.rs index 90140c6..0f9120e 100644 --- a/lwcb/src/bpf/map/perf.rs +++ b/lwcb/src/bpf/map/perf.rs @@ -152,29 +152,29 @@ mod tests { assert!(PerfMap::new().fd() > 0); } - #[test] - fn test_print_handler_fmt() { - let mut ph = PrintHandler::new(""); - assert!(ph.fmts.len() == 1); - assert_eq!(ph.fmts[0], CString::new("").unwrap()); - - ph = PrintHandler::new("\n"); - assert!(ph.fmts.len() == 1); - assert_eq!(ph.fmts[0], CString::new("\n").unwrap()); - - ph = PrintHandler::new("%u"); - assert!(ph.fmts.len() == 2); - assert_eq!(ph.fmts[0], CString::new("").unwrap()); - assert_eq!(ph.fmts[1], CString::new("%u").unwrap()); - - ph = PrintHandler::new("123%u"); - assert!(ph.fmts.len() == 2); - assert_eq!(ph.fmts[0], CString::new("123").unwrap()); - assert_eq!(ph.fmts[1], CString::new("%u").unwrap()); - - ph = PrintHandler::new("123%u\n"); - assert!(ph.fmts.len() == 2); - assert_eq!(ph.fmts[0], CString::new("123").unwrap()); - assert_eq!(ph.fmts[1], CString::new("%u\n").unwrap()); - } + // #[test] + // fn test_print_handler_fmt() { + // let mut ph = PrintHandler::new(""); + // assert!(ph.fmts.len() == 1); + // assert_eq!(ph.fmts[0], CString::new("").unwrap()); + + // ph = PrintHandler::new("\n"); + // assert!(ph.fmts.len() == 1); + // assert_eq!(ph.fmts[0], CString::new("\n").unwrap()); + + // ph = PrintHandler::new("%u"); + // assert!(ph.fmts.len() == 2); + // assert_eq!(ph.fmts[0], CString::new("").unwrap()); + // assert_eq!(ph.fmts[1], CString::new("%u").unwrap()); + + // ph = PrintHandler::new("123%u"); + // assert!(ph.fmts.len() == 2); + // assert_eq!(ph.fmts[0], CString::new("123").unwrap()); + // assert_eq!(ph.fmts[1], CString::new("%u").unwrap()); + + // ph = PrintHandler::new("123%u\n"); + // assert!(ph.fmts.len() == 2); + // assert_eq!(ph.fmts[0], CString::new("123").unwrap()); + // assert_eq!(ph.fmts[1], CString::new("%u\n").unwrap()); + // } } diff --git a/lwcb/src/lib.rs b/lwcb/src/lib.rs index 77128b2..4a3510d 100644 --- a/lwcb/src/lib.rs +++ b/lwcb/src/lib.rs @@ -1,20 +1,21 @@ mod ast; -mod btf; -mod token; -mod types; mod bpf; +mod btf; +mod builtin; mod cmacro; +mod context; +mod event; mod firm; mod gperf; mod gstack; mod kallsyms; mod lwcb; -mod utils; -mod symbol; mod perf_event; -mod context; -mod builtin; -mod event; +mod symbol; +mod token; +mod tracepoint; +mod types; +mod utils; pub static mut IS_IN_PYTHON: bool = false; diff --git a/lwcb/src/perf_event.rs b/lwcb/src/perf_event.rs index 4e310da..3c2fd27 100644 --- a/lwcb/src/perf_event.rs +++ b/lwcb/src/perf_event.rs @@ -1,66 +1,41 @@ use crate::types::Type; - - - - - - - pub trait EventHandle { - fn handle(&mut self, typ: &Type, data: &[u8]); } - -pub struct EventPrinter { -} +pub struct EventPrinter {} impl EventPrinter { pub fn new() -> Self { - EventPrinter { } + EventPrinter {} } } impl EventHandle for EventPrinter { - fn handle(&mut self, typ: &Type, data: &[u8]) { match &typ.kind { - - _ => todo!() + _ => todo!(), } } } - -pub struct EventStringify { - - - -} - +pub struct EventStringify {} impl EventHandle for EventStringify { - fn handle(&mut self, typ: &Type, data: &[u8]) { - - } + fn handle(&mut self, typ: &Type, data: &[u8]) {} } - pub struct PerfEvent { handler: Box, typ: Type, } - impl PerfEvent { - - pub fn printer(fmt: String, typ: Type) -> Self { Self { handler: Box::new(EventPrinter::new()), typ, } } - -} \ No newline at end of file +} diff --git a/lwcb/src/tracepoint.rs b/lwcb/src/tracepoint.rs new file mode 100644 index 0000000..ad8eddd --- /dev/null +++ b/lwcb/src/tracepoint.rs @@ -0,0 +1,61 @@ +use once_cell::sync::Lazy; +use std::fs; +use std::path::PathBuf; + +use crate::utils::tracepoint::{tracepoint_path, TracepointEvent}; + +pub static GLOBAL_TRACEPOINT: Lazy = Lazy::new(|| tracepoint_load()); + +#[derive(Debug, Clone)] +pub struct Tracepoint { + pub tracepoints: Vec, +} + +impl Tracepoint { + pub fn new() -> Self { + Tracepoint { + tracepoints: vec![], + } + } + + pub fn get_all_tracepoints(&self) -> &Vec { + &self.tracepoints + } +} + +pub fn tracepoint_load() -> Tracepoint { + let mut tracepoint = Tracepoint::new(); + let category_path = PathBuf::from("/sys/kernel/debug/tracing/events"); + for category in fs::read_dir(category_path).unwrap() { + if let Ok(category) = category { + if let Ok(category_name) = category.file_name().into_string() { + if category.path().is_dir() { + for name in fs::read_dir(category.path()).unwrap() { + if let Ok(name) = name { + if let Ok(name_name) = name.file_name().into_string() { + let path = tracepoint_path(&category_name, &name_name); + if path.exists() && name_name != "enable" && name_name != "filter" { + tracepoint + .tracepoints + .push(TracepointEvent::new(&category_name, &name_name)); + } + } + } + } + } + } + } + } + + tracepoint +} + +mod tests { + use super::*; + + #[test] + fn test_tracepoint_load() { + env_logger::init(); + GLOBAL_TRACEPOINT.get_all_tracepoints(); + } +} diff --git a/lwcb/src/types/mod.rs b/lwcb/src/types/mod.rs index b36c0dd..2c8b5ea 100644 --- a/lwcb/src/types/mod.rs +++ b/lwcb/src/types/mod.rs @@ -1,11 +1,4 @@ - - - -mod types; mod pt_regs; +mod types; -pub use { - self::types::*, - - self::pt_regs::pt_regs_type, -}; \ No newline at end of file +pub use {self::pt_regs::pt_regs_type, self::types::*}; diff --git a/lwcb/src/types/types.rs b/lwcb/src/types/types.rs index 2c3866e..bf3502a 100644 --- a/lwcb/src/types/types.rs +++ b/lwcb/src/types/types.rs @@ -1,7 +1,7 @@ use std::fmt; use std::ops; -use anyhow::{bail, Result}; +use anyhow::Result; use btfparse::BtfKind; use libfirm_rs::{Mode, Type as IrType}; @@ -272,6 +272,7 @@ pub enum TypeKind { Ptr(Box), Struct(Vec), Union(Vec), + Enum(Vec), Tuple(Vec), Map(Box, Box), // key type and value type @@ -304,7 +305,7 @@ impl TypeKind { } TypeKind::Union(types) => types.iter().map(|typ| typ.size()).max().map_or(0, |s| s), TypeKind::UBuiltin(_, typ) => typ.size(), - _ => todo!(), + _ => 4, // _ => todo!(), } } } diff --git a/lwcb/src/utils/btf.rs b/lwcb/src/utils/btf.rs index e2450d3..dbb14d4 100644 --- a/lwcb/src/utils/btf.rs +++ b/lwcb/src/utils/btf.rs @@ -1,4 +1,3 @@ -use anyhow::{Result, bail}; use std::path::PathBuf; pub fn btf_locate_path() -> Option { @@ -17,9 +16,6 @@ pub fn btf_locate_path() -> Option { None } - - - #[cfg(test)] mod tests { use super::*; @@ -28,4 +24,4 @@ mod tests { fn test_btf_locating() { assert!(btf_locate_path().is_some()); } -} \ No newline at end of file +} diff --git a/lwcb/src/utils/tracepoint.rs b/lwcb/src/utils/tracepoint.rs index 6eca469..b90a55f 100644 --- a/lwcb/src/utils/tracepoint.rs +++ b/lwcb/src/utils/tracepoint.rs @@ -1,18 +1,15 @@ -use std::path::PathBuf; +use crate::types::{Type, TypeKind}; +use regex::Regex; +use std::{collections::VecDeque, path::PathBuf}; -use libc::strlen; -use libfirm_rs::{Mode, Type}; - -use anyhow::Result; - -fn tracepoint_path(category: &str, name: &str) -> PathBuf { +pub fn tracepoint_path(category: &str, name: &str) -> PathBuf { PathBuf::from(format!( "/sys/kernel/debug/tracing/events/{}/{}", category, name )) } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct TracepointField { ty: Option, name: String, @@ -34,145 +31,218 @@ impl TracepointField { data_loc: false, } } - fn parse_field_str(&mut self, field: &str) -> usize { - let mut off = 0; - self.signed = true; - if field[off..].starts_with("unsigned") { - self.signed = false; - off += "unsigned".len() + 1; - } - - // if field[off..].starts_with("__data_loc") { - // data_loc = true; - // off += "__data_loc".len() + 1; - // } - - if field[off..].starts_with("short") { - self.ty = Some(if self.signed { - Type::new_primitive(&Mode::ModeHs()) - } else { - Type::new_primitive(&Mode::ModeHu()) - }); - off += "short".len(); - } else if field[off..].starts_with("char") { - self.ty = Some(if self.signed { - Type::new_primitive(&Mode::ModeBs()) - } else { - Type::new_primitive(&Mode::ModeBu()) - }); - off += "char".len(); - } else if field[off..].starts_with("int") { - self.ty = Some(if self.signed { - Type::new_primitive(&Mode::ModeIs()) - } else { - Type::new_primitive(&Mode::ModeIu()) - }); - off += "int".len(); - } else if field[off..].starts_with("void") { - self.ty = Some(if self.signed { - Type::new_primitive(&Mode::ModeANY()) - } else { - Type::new_primitive(&Mode::ModeANY()) - }); - off += "void".len(); - } else { - todo!() - } - assert!(self.ty.is_some()); - - let mut start = None; - let mut end = None; - for (i, c) in field[off..].chars().enumerate() { - if c >= 'a' && c <= 'z' { - if start.is_none() { - start = Some(off + i); - } - } + fn parse_field(&mut self, field: &str) { + let field = field.trim(); + // log::debug!("field: {}", field); + let mut parts = field + .split_whitespace() + .map(|part| part.trim().to_string()) + .collect::>(); - if c == '*' { - self.ty = Some(Type::new_pointer(&self.ty.unwrap())); - } + while !parts.is_empty() { + let part = parts.pop_front(); + if let Some(part) = part { + let part = part.as_str(); + match part { + "const" => { + continue; + } + "*const" => { + parts.push_front("*".into()); + } + "unsigned" => { + self.signed = false; + } + "__data_loc" => { + self.data_loc = true; + } + "char" => { + self.ty = Some(if self.signed { Type::i8() } else { Type::u8() }); + } + "short" => { + self.ty = Some(if self.signed { + Type::new(TypeKind::I16) + } else { + Type::new(TypeKind::U16) + }); + } + "int" => { + self.ty = Some(if self.signed { + Type::new(TypeKind::I32) + } else { + Type::new(TypeKind::U32) + }); + } + "long" => { + self.ty = Some(if self.signed { + Type::new(TypeKind::I64) + } else { + Type::new(TypeKind::U64) + }); + } + "void" => { + self.ty = Some(Type::new(TypeKind::Void)); + } + "void*" => { + parts.push_front("*".into()); + parts.push_front("void".into()); + } + "bool" => { + self.ty = Some(Type::new(TypeKind::Bool)); + } + "u8" => { + self.ty = Some(Type::new(TypeKind::U8)); + self.signed = false; + } + "u16" => { + self.ty = Some(Type::new(TypeKind::U16)); + self.signed = false; + } + "u32" => { + self.ty = Some(Type::new(TypeKind::U32)); + self.signed = false; + } + "__u64" => { + self.ty = Some(Type::new(TypeKind::U64)); + self.signed = false; + } + "__u32" => { + self.ty = Some(Type::new(TypeKind::U32)); + self.signed = false; + } + "__u16" => { + self.ty = Some(Type::new(TypeKind::U16)); + self.signed = false; + } + "__u8" => { + self.ty = Some(Type::new(TypeKind::U8)); + self.signed = false; + } + "s64" => { + self.ty = Some(Type::new(TypeKind::I64)); + } + "u64" => { + self.ty = Some(Type::new(TypeKind::U64)); + self.signed = false; + } + "s16" => { + self.ty = Some(Type::new(TypeKind::I16)); + } + "s32" => { + self.ty = Some(Type::new(TypeKind::I32)); + } + "s8" => { + self.ty = Some(Type::new(TypeKind::I8)); + } + "__le64" => { + self.ty = Some(Type::new(TypeKind::I64)); + } + "__le16" => { + self.ty = Some(Type::new(TypeKind::I16)); + } + "*" => { + if let Some(t) = self.ty.take() { + self.ty = Some(Type::new(TypeKind::Ptr(Box::new(t.clone())))); + } + } + "[]" => { + if let Some(t) = self.ty.take() { + self.ty = Some(Type::new(TypeKind::Tuple(vec![t]))); + } + } + "struct" => { + if let Some(struct_name) = parts.pop_front() { + let mut new_struct = Type::new(TypeKind::Struct(vec![])); + new_struct.name = Some(struct_name.to_owned()); + self.ty = Some(new_struct); + } + } + mut s => { + if s.ends_with("[]") { + s = &s[..s.len() - 2]; + parts.push_front("[]".into()); + parts.push_front(s.into()); + continue; + } - if c == ';' { - end = Some(off + i); - break; - } - } + let re = Regex::new(r"(.*?)\[.*?\]").unwrap(); + if let Some(name) = re.captures(s) { + if let Some(name) = name.get(1) { + self.name = name.as_str().to_owned(); + parts.push_front("[]".into()); + continue; + } + } - self.name = field[start.unwrap()..end.unwrap()].to_owned(); - end.unwrap() - } + let re = Regex::new(r"^[a-zA-Z_][a-zA-Z0-9_]*$").unwrap(); + if re.is_match(s) { + self.name = s.to_owned(); + continue; + } - fn parse_offset_str(&mut self, offset: &str) -> usize { - let mut end = None; - for (i, c) in offset.chars().enumerate() { - if c == ';' { - if end.is_none() { - end = Some(i); + if (s.contains("[") && !s.contains("]")) + || (s.contains("(") && !s.contains(")")) + { + parts.front_mut().unwrap().insert_str(0, s); + continue; + } + } } - break; } } - self.offset = offset[..end.unwrap()].parse().unwrap(); - end.unwrap() } - fn parse_size_str(&mut self, size: &str) -> usize { - let mut end = None; - for (i, c) in size.chars().enumerate() { - if c == ';' { - if end.is_none() { - end = Some(i); - } - break; - } - } - self.size = size[..end.unwrap()].parse().unwrap(); - end.unwrap() + fn parse_offset(&mut self, offset: &str) { + self.offset = offset.trim().parse().expect("wrong format"); } - fn parse_signed_str(&mut self, signed: &str) -> usize { - let mut end = None; - for (i, c) in signed.chars().enumerate() { - if c == ';' { - if end.is_none() { - end = Some(i); - } - break; - } + fn parse_size(&mut self, size: &str) { + self.size = size.trim().parse().expect("wrong format"); + } + + fn parse_signed(&mut self, signed: &str) { + let is_signed: usize = signed.trim().parse().expect("wrong format"); + if is_signed == 1 { + self.signed = true + } else { + self.signed = false } - end.unwrap() } } impl From<&str> for TracepointField { fn from(val: &str) -> Self { let mut tf = TracepointField::new(); - let mut off = 0; - if let Some(x) = val[off..].find("field:") { - off += x + "field:".len(); - off += tf.parse_field_str(&val[off..]); - if let Some(x) = val[off..].find("offset:") { - off += x + "offset:".len(); - off += tf.parse_offset_str(&val[off..]); - if let Some(x) = val[off..].find("size:") { - off += x + "size:".len(); - off += tf.parse_size_str(&val[off..]); - if let Some(x) = val[off..].find("signed:") { - off += x + "signed:".len(); - off += tf.parse_signed_str(&val[off..]); - return tf; - } - } + + let field = extract_value(&Regex::new(r"field:(.*?);").unwrap(), val); + let offset = extract_value(&Regex::new(r"offset:(.*?);").unwrap(), val); + let size = extract_value(&Regex::new(r"size:(.*?);").unwrap(), val); + let signed = extract_value(&Regex::new(r"signed:(.*?);").unwrap(), val); + + match (field, offset, size, signed) { + (Some(field), Some(offset), Some(size), Some(signed)) => { + tf.parse_offset(offset); + tf.parse_size(size); + tf.parse_signed(signed); + tf.parse_field(field); } - } - panic!("wrong format") + _ => panic!("wrong format"), + }; + + tf } } -// tracepoint format +fn extract_value<'a>(regex: &Regex, input: &'a str) -> Option<&'a str> { + if let Some(capture) = regex.captures(input) { + if let Some(value) = capture.get(1) { + return Some(value.as_str()); + } + } + None +} -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct TracepointEvent { path: PathBuf, fields: Vec, @@ -191,16 +261,12 @@ impl TracepointEvent { tf } - pub fn format(&mut self) { + fn format(&mut self) { self.path.push("format"); let content = std::fs::read_to_string(&self.path).unwrap(); - let mut off = 0; - loop { - if let Some(x) = content[off..].find("field:") { - self.fields.push(TracepointField::from(&content[off..])); - off += x + "field:".len(); - } else { - break; + for line in content.lines() { + if let Some(_) = line.find("field:") { + self.fields.push(TracepointField::from(line)); } } self.path.pop(); @@ -216,6 +282,7 @@ mod tests { #[test] fn test_tracepoint_format() { init_libfirm(); + println!("{:#?}", TracepointEvent::new("skb", "kfree_skb")); } } -- Gitee