On Mon, May 27, 2024 at 04:14:18PM +0800, Zhao Liu wrote:
> Refer to scripts/simpletrace.py, add the helpers to read the trace file
> and parse the record type field, record header and log header.
> 
> Suggested-by: Paolo Bonzini <pbonz...@redhat.com>
> Signed-off-by: Zhao Liu <zhao1....@intel.com>
> ---
>  scripts/simpletrace-rust/src/main.rs | 151 +++++++++++++++++++++++++++
>  1 file changed, 151 insertions(+)
> 
> diff --git a/scripts/simpletrace-rust/src/main.rs 
> b/scripts/simpletrace-rust/src/main.rs
> index 2d2926b7658d..b3b8baee7c66 100644
> --- a/scripts/simpletrace-rust/src/main.rs
> +++ b/scripts/simpletrace-rust/src/main.rs
> @@ -14,21 +14,172 @@
>  mod trace;
>  
>  use std::env;
> +use std::fs::File;
> +use std::io::Error as IOError;
> +use std::io::ErrorKind;
> +use std::io::Read;
>  
>  use clap::Arg;
>  use clap::Command;
>  use thiserror::Error;
>  use trace::Event;
>  
> +const RECORD_TYPE_MAPPING: u64 = 0;
> +const RECORD_TYPE_EVENT: u64 = 1;
> +
>  #[derive(Error, Debug)]
>  pub enum Error
>  {
>      #[error("usage: {0} [--no-header] <trace-events> <trace-file>")]
>      CliOptionUnmatch(String),
> +    #[error("Failed to read file: {0}")]
> +    ReadFile(IOError),
> +    #[error("Unknown record type ({0})")]
> +    UnknownRecType(u64),
>  }
>  
>  pub type Result<T> = std::result::Result<T, Error>;
>  
> +enum RecordType
> +{
> +    Empty,
> +    Mapping,
> +    Event,
> +}
> +
> +#[repr(C)]
> +#[derive(Clone, Copy, Default)]
> +struct RecordRawType
> +{
> +    rtype: u64,
> +}
> +
> +impl RecordType
> +{
> +    fn read_type(mut fobj: &File) -> Result<RecordType>
> +    {
> +        let mut tbuf = [0u8; 8];
> +        if let Err(e) = fobj.read_exact(&mut tbuf) {
> +            if e.kind() == ErrorKind::UnexpectedEof {
> +                return Ok(RecordType::Empty);
> +            } else {
> +                return Err(Error::ReadFile(e));
> +            }
> +        }
> +
> +        /*
> +         * Safe because the layout of the trace record requires us to parse
> +         * the type first, and then there is a check on the validity of the
> +         * record type.
> +         */
> +        let raw_t =
> +            unsafe { std::mem::transmute::<[u8; 8], RecordRawType>(tbuf) };

A safe alternative: 
https://doc.rust-lang.org/std/primitive.u64.html#method.from_ne_bytes?

> +        match raw_t.rtype {
> +            RECORD_TYPE_MAPPING => Ok(RecordType::Mapping),
> +            RECORD_TYPE_EVENT => Ok(RecordType::Event),
> +            _ => Err(Error::UnknownRecType(raw_t.rtype)),
> +        }
> +    }
> +}
> +
> +trait ReadHeader
> +{
> +    fn read_header(fobj: &File) -> Result<Self>
> +    where
> +        Self: Sized;
> +}
> +
> +#[repr(C)]
> +#[derive(Clone, Copy)]
> +struct LogHeader
> +{
> +    event_id: u64,
> +    magic: u64,
> +    version: u64,
> +}
> +
> +impl ReadHeader for LogHeader
> +{
> +    fn read_header(mut fobj: &File) -> Result<Self>
> +    {
> +        let mut raw_hdr = [0u8; 24];
> +        fobj.read_exact(&mut raw_hdr).map_err(Error::ReadFile)?;
> +
> +        /*
> +         * Safe because the size of log header (struct LogHeader)
> +         * is 24 bytes, which is ensured by simple trace backend.
> +         */
> +        let hdr =
> +            unsafe { std::mem::transmute::<[u8; 24], LogHeader>(raw_hdr) };

Or u64::from_ne_bytes() for each field.

> +        Ok(hdr)
> +    }
> +}
> +
> +#[derive(Default)]
> +struct RecordInfo
> +{
> +    event_id: u64,
> +    timestamp_ns: u64,
> +    record_pid: u32,
> +    args_payload: Vec<u8>,
> +}
> +
> +impl RecordInfo
> +{
> +    fn new() -> Self
> +    {
> +        Default::default()
> +    }
> +}
> +
> +#[repr(C)]
> +#[derive(Clone, Copy)]
> +struct RecordHeader
> +{
> +    event_id: u64,
> +    timestamp_ns: u64,
> +    record_length: u32,
> +    record_pid: u32,
> +}
> +
> +impl RecordHeader
> +{
> +    fn extract_record(&self, mut fobj: &File) -> Result<RecordInfo>
> +    {
> +        let mut info = RecordInfo::new();
> +
> +        info.event_id = self.event_id;
> +        info.timestamp_ns = self.timestamp_ns;
> +        info.record_pid = self.record_pid;
> +        info.args_payload = vec![
> +            0u8;
> +            self.record_length as usize
> +                - std::mem::size_of::<RecordHeader>()
> +        ];
> +        fobj.read_exact(&mut info.args_payload)
> +            .map_err(Error::ReadFile)?;
> +
> +        Ok(info)
> +    }
> +}
> +
> +impl ReadHeader for RecordHeader
> +{
> +    fn read_header(mut fobj: &File) -> Result<Self>
> +    {
> +        let mut raw_hdr = [0u8; 24];
> +        fobj.read_exact(&mut raw_hdr).map_err(Error::ReadFile)?;
> +
> +        /*
> +         * Safe because the size of record header (struct RecordHeader)
> +         * is 24 bytes, which is ensured by simple trace backend.
> +         */
> +        let hdr: RecordHeader =
> +            unsafe { std::mem::transmute::<[u8; 24], RecordHeader>(raw_hdr) 
> };

Or u64::from_ne_bytes() and u32::from_ne_bytes() for all fields.

> +        Ok(hdr)
> +    }
> +}
> +
>  pub struct EventArgPayload {}
>  
>  trait Analyzer
> -- 
> 2.34.1
> 

Attachment: signature.asc
Description: PGP signature

Reply via email to