linux_perf_event_reader/
sample.rs

1use byteorder::ByteOrder;
2
3use crate::{BranchSampleFormat, CpuMode, RawData, RawDataU64, ReadFormat, SampleFormat};
4
5use super::{RecordParseInfo, Regs};
6
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub struct SampleRecord<'a> {
9    pub id: Option<u64>,
10    pub addr: Option<u64>,
11    pub stream_id: Option<u64>,
12    pub raw: Option<RawData<'a>>,
13    pub ip: Option<u64>,
14    pub timestamp: Option<u64>,
15    pub pid: Option<i32>,
16    pub tid: Option<i32>,
17    pub cpu: Option<u32>,
18    pub period: Option<u64>,
19    pub user_regs: Option<Regs<'a>>,
20    pub user_stack: Option<(RawData<'a>, u64)>,
21    pub callchain: Option<RawDataU64<'a>>,
22    pub phys_addr: Option<u64>,
23    pub data_page_size: Option<u64>,
24    pub code_page_size: Option<u64>,
25    pub intr_regs: Option<Regs<'a>>,
26    pub cpu_mode: CpuMode,
27}
28
29impl<'a> SampleRecord<'a> {
30    pub fn parse<T: ByteOrder>(
31        data: RawData<'a>,
32        misc: u16,
33        parse_info: &RecordParseInfo,
34    ) -> Result<Self, std::io::Error> {
35        let sample_format = parse_info.sample_format;
36        let branch_sample_format = parse_info.branch_sample_format;
37        let read_format = parse_info.read_format;
38        let sample_regs_user = parse_info.sample_regs_user;
39        let user_regs_count = parse_info.user_regs_count;
40        let sample_regs_intr = parse_info.sample_regs_intr;
41        let intr_regs_count = parse_info.intr_regs_count;
42        let cpu_mode = CpuMode::from_misc(misc);
43        let mut cur = data;
44
45        let identifier = if sample_format.contains(SampleFormat::IDENTIFIER) {
46            Some(cur.read_u64::<T>()?)
47        } else {
48            None
49        };
50
51        let ip = if sample_format.contains(SampleFormat::IP) {
52            Some(cur.read_u64::<T>()?)
53        } else {
54            None
55        };
56
57        let (pid, tid) = if sample_format.contains(SampleFormat::TID) {
58            let pid = cur.read_i32::<T>()?;
59            let tid = cur.read_i32::<T>()?;
60            (Some(pid), Some(tid))
61        } else {
62            (None, None)
63        };
64
65        let timestamp = if sample_format.contains(SampleFormat::TIME) {
66            Some(cur.read_u64::<T>()?)
67        } else {
68            None
69        };
70
71        let addr = if sample_format.contains(SampleFormat::ADDR) {
72            Some(cur.read_u64::<T>()?)
73        } else {
74            None
75        };
76
77        let id = if sample_format.contains(SampleFormat::ID) {
78            Some(cur.read_u64::<T>()?)
79        } else {
80            None
81        };
82        let id = identifier.or(id);
83
84        let stream_id = if sample_format.contains(SampleFormat::STREAM_ID) {
85            Some(cur.read_u64::<T>()?)
86        } else {
87            None
88        };
89
90        let cpu = if sample_format.contains(SampleFormat::CPU) {
91            let cpu = cur.read_u32::<T>()?;
92            let _reserved = cur.read_u32::<T>()?;
93            Some(cpu)
94        } else {
95            None
96        };
97
98        let period = if sample_format.contains(SampleFormat::PERIOD) {
99            let period = cur.read_u64::<T>()?;
100            Some(period)
101        } else {
102            None
103        };
104
105        if sample_format.contains(SampleFormat::READ) {
106            if read_format.contains(ReadFormat::GROUP) {
107                let _value = cur.read_u64::<T>()?;
108                if read_format.contains(ReadFormat::TOTAL_TIME_ENABLED) {
109                    let _time_enabled = cur.read_u64::<T>()?;
110                }
111                if read_format.contains(ReadFormat::TOTAL_TIME_RUNNING) {
112                    let _time_running = cur.read_u64::<T>()?;
113                }
114                if read_format.contains(ReadFormat::ID) {
115                    let _id = cur.read_u64::<T>()?;
116                }
117            } else {
118                let nr = cur.read_u64::<T>()?;
119                if read_format.contains(ReadFormat::TOTAL_TIME_ENABLED) {
120                    let _time_enabled = cur.read_u64::<T>()?;
121                }
122                if read_format.contains(ReadFormat::TOTAL_TIME_RUNNING) {
123                    let _time_running = cur.read_u64::<T>()?;
124                }
125                for _ in 0..nr {
126                    let _value = cur.read_u64::<T>()?;
127                    if read_format.contains(ReadFormat::ID) {
128                        let _id = cur.read_u64::<T>()?;
129                    }
130                }
131            }
132        }
133
134        let callchain = if sample_format.contains(SampleFormat::CALLCHAIN) {
135            let callchain_length = cur.read_u64::<T>()?;
136            let callchain =
137                cur.split_off_prefix(callchain_length as usize * std::mem::size_of::<u64>())?;
138            Some(RawDataU64::from_raw_data::<T>(callchain))
139        } else {
140            None
141        };
142
143        let raw = if sample_format.contains(SampleFormat::RAW) {
144            let size = cur.read_u32::<T>()?;
145            Some(cur.split_off_prefix(size as usize)?)
146        } else {
147            None
148        };
149
150        if sample_format.contains(SampleFormat::BRANCH_STACK) {
151            let nr = cur.read_u64::<T>()?;
152            if branch_sample_format.contains(BranchSampleFormat::HW_INDEX) {
153                let _hw_idx = cur.read_u64::<T>()?;
154            }
155            for _ in 0..nr {
156                let _from = cur.read_u64::<T>()?;
157                let _to = cur.read_u64::<T>()?;
158                let _flags = cur.read_u64::<T>()?;
159            }
160        }
161
162        let user_regs = if sample_format.contains(SampleFormat::REGS_USER) {
163            let regs_abi = cur.read_u64::<T>()?;
164            if regs_abi == 0 {
165                None
166            } else {
167                let regs_data =
168                    cur.split_off_prefix(user_regs_count as usize * std::mem::size_of::<u64>())?;
169                let raw_regs = RawDataU64::from_raw_data::<T>(regs_data);
170                let user_regs = Regs::new(sample_regs_user, raw_regs);
171                Some(user_regs)
172            }
173        } else {
174            None
175        };
176
177        let user_stack = if sample_format.contains(SampleFormat::STACK_USER) {
178            let stack_size = cur.read_u64::<T>()?;
179            let stack = cur.split_off_prefix(stack_size as usize)?;
180
181            let dynamic_size = if stack_size != 0 {
182                cur.read_u64::<T>()?
183            } else {
184                0
185            };
186            Some((stack, dynamic_size))
187        } else {
188            None
189        };
190
191        if sample_format.contains(SampleFormat::WEIGHT) {
192            let _weight = cur.read_u64::<T>()?;
193        }
194
195        if sample_format.contains(SampleFormat::DATA_SRC) {
196            let _data_src = cur.read_u64::<T>()?;
197        }
198
199        if sample_format.contains(SampleFormat::TRANSACTION) {
200            let _transaction = cur.read_u64::<T>()?;
201        }
202
203        let intr_regs = if sample_format.contains(SampleFormat::REGS_INTR) {
204            let regs_abi = cur.read_u64::<T>()?;
205            if regs_abi == 0 {
206                None
207            } else {
208                let regs_data =
209                    cur.split_off_prefix(intr_regs_count as usize * std::mem::size_of::<u64>())?;
210                let raw_regs = RawDataU64::from_raw_data::<T>(regs_data);
211                let intr_regs = Regs::new(sample_regs_intr, raw_regs);
212                Some(intr_regs)
213            }
214        } else {
215            None
216        };
217
218        let phys_addr = if sample_format.contains(SampleFormat::PHYS_ADDR) {
219            Some(cur.read_u64::<T>()?)
220        } else {
221            None
222        };
223
224        if sample_format.contains(SampleFormat::AUX) {
225            let size = cur.read_u64::<T>()?;
226            cur.skip(size as usize)?;
227        }
228
229        let data_page_size = if sample_format.contains(SampleFormat::DATA_PAGE_SIZE) {
230            Some(cur.read_u64::<T>()?)
231        } else {
232            None
233        };
234
235        let code_page_size = if sample_format.contains(SampleFormat::CODE_PAGE_SIZE) {
236            Some(cur.read_u64::<T>()?)
237        } else {
238            None
239        };
240
241        Ok(Self {
242            id,
243            ip,
244            addr,
245            stream_id,
246            raw,
247            user_regs,
248            user_stack,
249            callchain,
250            cpu,
251            timestamp,
252            pid,
253            tid,
254            period,
255            intr_regs,
256            phys_addr,
257            data_page_size,
258            code_page_size,
259            cpu_mode,
260        })
261    }
262}