use std::collections::HashMap;
use byteorder::{BigEndian, LittleEndian, ReadBytesExt};
use linux_perf_event_reader::Endianness;
use prost::Message;
use crate::Error;
pub struct SimplePerfEventType {
pub name: String,
pub type_: u64,
pub config: u64,
}
impl SimplePerfEventType {
pub fn new(name: String, type_: u64, config: u64) -> Self {
Self {
name,
type_,
config,
}
}
}
pub fn parse_meta_info_map(bytes: &[u8]) -> Result<HashMap<&str, &str>, std::str::Utf8Error> {
let iter = bytes.split(|c| *c == b'\0');
let keys = iter.clone().step_by(2);
let values = iter.skip(1).step_by(2);
let mut map = HashMap::new();
for (key, value) in keys.zip(values) {
let key = std::str::from_utf8(key)?;
let value = std::str::from_utf8(value)?;
map.insert(key, value);
}
Ok(map)
}
pub fn get_event_types(meta_info_map: &HashMap<&str, &str>) -> Option<Vec<SimplePerfEventType>> {
let event_type_info = meta_info_map.get("event_type_info")?;
let mut event_types = Vec::new();
for line in event_type_info.split('\n') {
let mut parts = line.split(',');
let name = parts.next()?.to_string();
let type_ = parts.next()?.parse().ok()?;
let config = parts.next()?.parse().ok()?;
event_types.push(SimplePerfEventType::new(name, type_, config));
}
Some(event_types)
}
#[derive(Clone, PartialEq, Eq, ::prost_derive::Message)]
pub struct SimpleperfFileRecord {
#[prost(string, tag = "1")]
pub path: ::prost::alloc::string::String,
#[prost(uint32, tag = "2")]
pub r#type: u32,
#[prost(uint64, tag = "3")]
pub min_vaddr: u64,
#[prost(message, repeated, tag = "4")]
pub symbol: ::prost::alloc::vec::Vec<SimpleperfSymbol>,
#[prost(oneof = "SimpleperfTypeSpecificInfo", tags = "5, 6, 7")]
pub type_specific_msg: ::core::option::Option<SimpleperfTypeSpecificInfo>,
}
#[derive(Clone, PartialEq, Eq, ::prost_derive::Message)]
pub struct SimpleperfSymbol {
#[prost(uint64, tag = "1")]
pub vaddr: u64,
#[prost(uint32, tag = "2")]
pub len: u32,
#[prost(string, tag = "3")]
pub name: ::prost::alloc::string::String,
}
#[derive(Clone, PartialEq, Eq, ::prost_derive::Message)]
pub struct SimpleperfDexFileInfo {
#[prost(uint64, repeated, tag = "1")]
pub dex_file_offset: ::prost::alloc::vec::Vec<u64>,
}
#[derive(Clone, PartialEq, Eq, ::prost_derive::Message)]
pub struct SimpleperfElfFileInfo {
#[prost(uint64, tag = "1")]
pub file_offset_of_min_vaddr: u64,
}
#[derive(Clone, PartialEq, Eq, ::prost_derive::Message)]
pub struct SimpleperfKernelModuleInfo {
#[prost(uint64, tag = "1")]
pub memory_offset_of_min_vaddr: u64,
}
#[derive(Clone, PartialEq, Eq, ::prost_derive::Oneof)]
pub enum SimpleperfTypeSpecificInfo {
#[prost(message, tag = "5")]
SimpleperfDexFileInfo(SimpleperfDexFileInfo),
#[prost(message, tag = "6")]
ElfFile(SimpleperfElfFileInfo),
#[prost(message, tag = "7")]
KernelModule(SimpleperfKernelModuleInfo),
}
pub fn parse_file2_section(
mut bytes: &[u8],
endian: Endianness,
) -> Result<Vec<SimpleperfFileRecord>, Error> {
let mut files = Vec::new();
while !bytes.is_empty() {
let len = match endian {
Endianness::LittleEndian => bytes.read_u32::<LittleEndian>()?,
Endianness::BigEndian => bytes.read_u32::<BigEndian>()?,
};
let len = len as usize;
let file_data = bytes.get(..len).ok_or(Error::FeatureSectionTooSmall)?;
bytes = &bytes[len..];
let file = SimpleperfFileRecord::decode(file_data)
.map_err(Error::ProtobufParsingSimpleperfFileSection)?;
files.push(file);
}
Ok(files)
}