Skip to content

Commit 9729e91

Browse files
committed
Allow using read_file to consume pipe mode data
1 parent 2323e5b commit 9729e91

3 files changed

Lines changed: 33 additions & 7 deletions

File tree

src/error.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ pub enum Error {
6363

6464
#[error("The specified size in the perf event header was smaller than the header itself")]
6565
InvalidPerfEventSize,
66+
67+
#[error("Cannot parse non-streaming perf.data file with parse_pipe. Use parse_file instead.")]
68+
FileFormatDetectedInPipeMode,
69+
70+
#[error("Detected pipe format in file mode")]
71+
PipeFormatDetectedInFileMode,
6672
}
6773

6874
impl From<std::str::Utf8Error> for Error {

src/file_reader.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,15 @@ pub struct PerfFileReader<R: Read> {
5858

5959
impl<C: Read + Seek> PerfFileReader<C> {
6060
pub fn parse_file(mut cursor: C) -> Result<Self, Error> {
61-
let header = PerfHeader::parse(&mut cursor)?;
61+
let header = match PerfHeader::parse(&mut cursor) {
62+
Ok(header) => header,
63+
Err(Error::PipeFormatDetectedInFileMode) => {
64+
// Rewind and parse as pipe format instead
65+
cursor.seek(SeekFrom::Start(0))?;
66+
return Self::parse_pipe(cursor);
67+
}
68+
Err(e) => return Err(e),
69+
};
6270
match &header.magic {
6371
b"PERFILE2" => {
6472
Self::parse_file_impl::<LittleEndian>(cursor, header, Endianness::LittleEndian)

src/header.rs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::io::Read;
22

33
use byteorder::{ByteOrder, ReadBytesExt};
44

5+
use super::error::Error;
56
use super::features::FeatureSet;
67
use super::section::PerfFileSection;
78

@@ -28,7 +29,7 @@ pub struct PerfHeader {
2829
}
2930

3031
impl PerfHeader {
31-
pub fn parse<R: Read>(mut reader: R) -> Result<Self, std::io::Error> {
32+
pub fn parse<R: Read>(mut reader: R) -> Result<Self, Error> {
3233
let mut magic = [0; 8];
3334
reader.read_exact(&mut magic)?;
3435

@@ -39,11 +40,14 @@ impl PerfHeader {
3940
}
4041
}
4142

42-
fn parse_impl<R: Read, T: ByteOrder>(
43-
mut reader: R,
44-
magic: [u8; 8],
45-
) -> Result<Self, std::io::Error> {
43+
fn parse_impl<R: Read, T: ByteOrder>(mut reader: R, magic: [u8; 8]) -> Result<Self, Error> {
4644
let header_size = reader.read_u64::<T>()?;
45+
46+
// Detect if this is actually a pipe format instead of file format.
47+
if header_size == std::mem::size_of::<PerfPipeHeader>() as u64 {
48+
return Err(Error::PipeFormatDetectedInFileMode);
49+
}
50+
4751
let attr_size = reader.read_u64::<T>()?;
4852
let attr_section = PerfFileSection::parse::<_, T>(&mut reader)?;
4953
let data_section = PerfFileSection::parse::<_, T>(&mut reader)?;
@@ -81,7 +85,7 @@ pub struct PerfPipeHeader {
8185
}
8286

8387
impl PerfPipeHeader {
84-
pub fn parse<R: Read>(mut reader: R) -> Result<Self, std::io::Error> {
88+
pub fn parse<R: Read>(mut reader: R) -> Result<Self, Error> {
8589
let mut magic = [0; 8];
8690
reader.read_exact(&mut magic)?;
8791

@@ -90,6 +94,14 @@ impl PerfPipeHeader {
9094
} else {
9195
reader.read_u64::<byteorder::BigEndian>()?
9296
};
97+
98+
// Detect if this is actually a file format instead of pipe format.
99+
if size > std::mem::size_of::<Self>() as u64
100+
&& size == std::mem::size_of::<PerfHeader>() as u64
101+
{
102+
return Err(Error::FileFormatDetectedInPipeMode);
103+
}
104+
93105
Ok(Self { magic, size })
94106
}
95107
}

0 commit comments

Comments
 (0)