1use crate::snapshot::event::*;
2use crate::snapshot::object_properties::ObjectPropertyTable;
3use crate::snapshot::symbol_table::SymbolTable;
4use crate::time::{DifferentialTimestamp, Dts16, Dts8};
5use crate::types::{
6 format_symbol_string, FormatString, FormattedString, FormattedStringError, ObjectHandle,
7 ObjectName, Protocol, UserEventChannel,
8};
9use byteordered::{ByteOrdered, Endianness};
10use derive_more::From;
11use std::io;
12use thiserror::Error;
13use tracing::error;
14
15#[derive(Debug, Error)]
16pub enum Error {
17 #[error("Found an invalid zero value symbol table index")]
18 InvalidSymbolTableIndex,
19
20 #[error(
21 "Found a user event with format string index {0} that doesn't exist in the symbol table"
22 )]
23 FormatSymbolLookup(ObjectHandle),
24
25 #[error(
26 "Found a user event with channel string index {0} that doesn't exist in the symbol table"
27 )]
28 ChannelSymbolLookup(ObjectHandle),
29
30 #[error(transparent)]
31 FormattedString(#[from] FormattedStringError),
32
33 #[error("Found an invalid zero value object property table handle")]
34 InvalidObjectHandle,
35
36 #[error(
37 "Found an event with object handle {0} that doesn't exist in the object properties table"
38 )]
39 ObjectLookup(ObjectHandle),
40
41 #[error(
42 "Encountered and IO error while parsing the event stream ({})",
43 .0.kind()
44 )]
45 Io(#[from] io::Error),
46}
47
48#[derive(Debug)]
49pub struct EventParser {
50 endianness: Endianness,
52
53 accumulated_time: Timestamp,
55
56 dts_for_next_event: DifferentialTimestamp,
59
60 user_arg_record_count: usize,
62
63 user_event_records: Vec<EventRecord>,
65}
66
67impl EventParser {
68 pub fn new(endianness: Endianness) -> Self {
69 Self {
70 endianness,
71 accumulated_time: Timestamp::zero(),
72 dts_for_next_event: DifferentialTimestamp::zero(),
73 user_arg_record_count: 0,
74 user_event_records: Vec::with_capacity(UserEventArgRecordCount::MAX),
75 }
76 }
77
78 pub fn parse(
79 &mut self,
80 obj_props: &ObjectPropertyTable,
81 symbol_table: &SymbolTable,
82 record: EventRecord,
83 ) -> Result<Option<(EventType, Event)>, Error> {
84 let event_code = record.event_code();
85 let event_type = EventType::from(event_code);
86
87 if self.is_capturing_user_event_records() {
89 self.capture_user_event_record(record);
90 return Ok(self
91 .parse_user_event(symbol_table)?
92 .map(|(et, ue)| (et, Event::User(ue))));
93 }
94
95 Ok(match event_type {
97 EventType::TaskSwitchIsrBegin | EventType::TaskSwitchIsrResume => {
98 let mut r = ByteOrdered::runtime(record.as_slice(), self.endianness);
99 let _event_code = r.read_u8()?;
100 let handle =
101 ObjectHandle::new(r.read_u8()?.into()).ok_or(Error::InvalidObjectHandle)?;
102 let dts = Dts16(r.read_u16()?);
103 let obj = obj_props
104 .isr_object_properties
105 .get(&handle)
106 .ok_or(Error::ObjectLookup(handle))?;
107 let event = IsrEvent {
108 handle,
109 name: ObjectName(obj.display_name().to_string()),
110 priority: obj.priority(),
111 timestamp: self.get_timestamp(dts.into()),
112 };
113 Some((
114 event_type,
115 if event_type == EventType::TaskSwitchIsrBegin {
116 Event::IsrBegin(event)
117 } else {
118 Event::IsrResume(event)
119 },
120 ))
121 }
122
123 EventType::TaskReady
124 | EventType::TaskSwitchTaskBegin
125 | EventType::TaskSwitchTaskResume => {
126 let mut r = ByteOrdered::runtime(record.as_slice(), self.endianness);
127 let _event_code = r.read_u8()?;
128 let handle =
129 ObjectHandle::new(r.read_u8()?.into()).ok_or(Error::InvalidObjectHandle)?;
130 let dts = Dts16(r.read_u16()?);
131 let obj = obj_props
132 .task_object_properties
133 .get(&handle)
134 .ok_or(Error::ObjectLookup(handle))?;
135 let event = TaskEvent {
136 handle,
137 name: ObjectName(obj.display_name().to_string()),
138 state: obj.state(),
139 priority: obj.current_priority(),
140 timestamp: self.get_timestamp(dts.into()),
141 };
142 Some((
143 event_type,
144 match event_type {
145 EventType::TaskReady => Event::TaskReady(event),
146 EventType::TaskSwitchTaskBegin => Event::TaskBegin(event),
147 _ => Event::TaskResume(event),
148 },
149 ))
150 }
151
152 EventType::CreateObject(occ) => {
153 let handle = self.parse_generic_kernel_call(&record)?;
154 match occ.into_class() {
155 ObjectClass::Task => {
156 let obj = obj_props
157 .task_object_properties
158 .get(&handle)
159 .ok_or(Error::ObjectLookup(handle))?;
160 Some((
161 event_type,
162 Event::TaskCreate(TaskEvent {
163 handle,
164 name: ObjectName(obj.display_name().to_string()),
165 state: obj.state(),
166 priority: obj.current_priority(),
167 timestamp: self.accumulated_time,
168 }),
169 ))
170 }
171 _ => Some((event_type, Event::Unknown(self.accumulated_time, record))),
173 }
174 }
175
176 EventType::UserEvent(arg_record_cnt) => {
177 self.begin_user_event(arg_record_cnt, record);
178 self.parse_user_event(symbol_table)?
179 .map(|(et, ue)| (et, Event::User(ue)))
180 }
181
182 EventType::Xts8 => {
185 let mut r = ByteOrdered::runtime(record.as_slice(), self.endianness);
186 let _event_code = r.read_u8()?;
187 let xts_8 = r.read_u8()?;
188 let xts_16 = r.read_u16()?;
189 self.dts_for_next_event = DifferentialTimestamp::from_xts8(xts_8, xts_16);
190 None
191 }
192 EventType::Xts16 => {
193 let mut r = ByteOrdered::runtime(record.as_slice(), self.endianness);
194 let _event_code = r.read_u8()?;
195 let _unused = r.read_u8()?;
196 let xts_16 = r.read_u16()?;
197 self.dts_for_next_event = DifferentialTimestamp::from_xts16(xts_16);
198 None
199 }
200
201 EventType::LowPowerBegin | EventType::LowPowerEnd => {
202 let mut r = ByteOrdered::runtime(record.as_slice(), self.endianness);
203 let _event_code = r.read_u8()?;
204 let _unused = r.read_u8()?;
205 let dts = Dts16(r.read_u16()?);
206 let event = LowPowerEvent {
207 timestamp: self.get_timestamp(dts.into()),
208 };
209 Some((
210 event_type,
211 if event_type == EventType::LowPowerBegin {
212 Event::LowPowerBegin(event)
213 } else {
214 Event::LowPowerEnd(event)
215 },
216 ))
217 }
218
219 EventType::EventBeingWritten => None,
221
222 EventType::NewTime => {
225 self.parse_generic_kernel_call_with_numeric_param(&record)?;
226 Some((event_type, Event::Unknown(self.accumulated_time, record)))
227 }
228
229 EventType::Send(_)
230 | EventType::Receive(_)
231 | EventType::SendFromIsr(_)
232 | EventType::ReceiveFromIsr(_) => {
233 self.parse_generic_kernel_call(&record)?;
234 Some((event_type, Event::Unknown(self.accumulated_time, record)))
235 }
236
237 EventType::CreateObjectFailed(_) => {
238 self.parse_generic_kernel_call_with_numeric_param(&record)?;
239 Some((event_type, Event::Unknown(self.accumulated_time, record)))
240 }
241
242 EventType::SendFailed(_)
243 | EventType::ReceiveFailed(_)
244 | EventType::SendFromIsrFailed(_)
245 | EventType::ReceiveFromIsrFailed(_)
246 | EventType::ReceiveBlock(_)
247 | EventType::SendBlock(_)
248 | EventType::Peek(_)
249 | EventType::DeleteObject(_) => {
250 self.parse_generic_kernel_call(&record)?;
251 Some((event_type, Event::Unknown(self.accumulated_time, record)))
252 }
253
254 EventType::TaskDelayUntil | EventType::TaskDelay => {
255 self.parse_generic_kernel_call_with_numeric_param(&record)?;
256 Some((event_type, Event::Unknown(self.accumulated_time, record)))
257 }
258
259 EventType::TaskSuspend | EventType::TaskResume | EventType::TaskResumeFromIsr => {
260 self.parse_generic_kernel_call(&record)?;
261 Some((event_type, Event::Unknown(self.accumulated_time, record)))
262 }
263
264 EventType::TaskPrioritySet
265 | EventType::TaskPriorityInherit
266 | EventType::TaskPriorityDisinherit => {
267 self.parse_generic_kernel_call_with_param(&record)?;
268 Some((event_type, Event::Unknown(self.accumulated_time, record)))
269 }
270
271 EventType::PendFuncCall
272 | EventType::PendFuncCallFromIsr
273 | EventType::PendFuncCallFailed
274 | EventType::PendFuncCallFromIsrFailed => {
275 self.parse_generic_kernel_call(&record)?;
276 Some((event_type, Event::Unknown(self.accumulated_time, record)))
277 }
278
279 EventType::MemoryMallocSize | EventType::MemoryFreeSize => {
280 self.parse_generic_mem_size(&record)?;
281 Some((event_type, Event::Unknown(self.accumulated_time, record)))
282 }
283
284 EventType::TimerCreate | EventType::TimerDeleteObject => {
285 self.parse_generic_kernel_call(&record)?;
286 Some((event_type, Event::Unknown(self.accumulated_time, record)))
287 }
288
289 EventType::TimerStart
290 | EventType::TimerReset
291 | EventType::TimerStop
292 | EventType::TimerChangePeriod
293 | EventType::TimerStartFromIsr
294 | EventType::TimerResetFromIsr
295 | EventType::TimerStopFromIsr => {
296 self.parse_generic_kernel_call_with_param(&record)?;
297 Some((event_type, Event::Unknown(self.accumulated_time, record)))
298 }
299
300 EventType::TimerCreateFailed => {
301 self.parse_generic_kernel_call_with_numeric_param(&record)?;
302 Some((event_type, Event::Unknown(self.accumulated_time, record)))
303 }
304
305 EventType::TimerStartFailed
306 | EventType::TimerResetFailed
307 | EventType::TimerStopFailed
308 | EventType::TimerChangePeriodFailed
309 | EventType::TimerDeleteFailed
310 | EventType::TimerStartFromIsrFailed
311 | EventType::TimerResetFromIsrFailed
312 | EventType::TimerStopFromIsrFailed => {
313 self.parse_generic_kernel_call_with_param(&record)?;
314 Some((event_type, Event::Unknown(self.accumulated_time, record)))
315 }
316
317 EventType::EventGroupCreate | EventType::EventGroupDeleteObject => {
318 self.parse_generic_kernel_call(&record)?;
319 Some((event_type, Event::Unknown(self.accumulated_time, record)))
320 }
321
322 EventType::EventGroupCreateFailed => {
323 self.parse_generic_kernel_call_with_numeric_param(&record)?;
324 Some((event_type, Event::Unknown(self.accumulated_time, record)))
325 }
326
327 EventType::EventGroupSyncBlock
328 | EventType::EventGroupSyncEnd
329 | EventType::EventGroupWaitBitsBlock
330 | EventType::EventGroupWaitBitsEnd
331 | EventType::EventGroupClearBits
332 | EventType::EventGroupClearBitsFromIsr
333 | EventType::EventGroupSetBits
334 | EventType::EventGroupSyncEndFailed
335 | EventType::EventGroupWaitBitsEndFailed
336 | EventType::EventGroupSetBitsFromIsr
337 | EventType::EventGroupSetBitsFromIsrFailed => {
338 self.parse_generic_kernel_call_with_param(&record)?;
339 Some((event_type, Event::Unknown(self.accumulated_time, record)))
340 }
341
342 EventType::TaskInstanceFinishedNextKse | EventType::TaskInstanceFinishedDirect => {
343 self.parse_generic_task_instance_status(&record)?;
344 Some((event_type, Event::Unknown(self.accumulated_time, record)))
345 }
346
347 EventType::TaskNotify
348 | EventType::TaskNotifyFromIsr
349 | EventType::TaskNotifyGiveFromIsr => {
350 self.parse_generic_kernel_call(&record)?;
351 Some((event_type, Event::Unknown(self.accumulated_time, record)))
352 }
353
354 EventType::TaskNotifyTake
355 | EventType::TaskNotifyTakeBlock
356 | EventType::TaskNotifyTakeFailed
357 | EventType::TaskNotifyWait
358 | EventType::TaskNotifyWaitBlock
359 | EventType::TaskNotifyWaitFailed => {
360 self.parse_generic_kernel_call_with_param(&record)?;
361 Some((event_type, Event::Unknown(self.accumulated_time, record)))
362 }
363
364 EventType::TimerExpired => {
365 self.parse_generic_kernel_call(&record)?;
366 Some((event_type, Event::Unknown(self.accumulated_time, record)))
367 }
368
369 EventType::QueuePeekBlock
370 | EventType::SemaphortPeekBlock
371 | EventType::MutexPeekBlock
372 | EventType::QueuePeekFailed
373 | EventType::SemaphortPeekFailed
374 | EventType::MutexPeekFailed => {
375 self.parse_generic_kernel_call(&record)?;
376 Some((event_type, Event::Unknown(self.accumulated_time, record)))
377 }
378
379 EventType::StreambufferReset | EventType::MessagebufferReset => {
380 self.parse_generic_kernel_call(&record)?;
381 Some((event_type, Event::Unknown(self.accumulated_time, record)))
382 }
383
384 EventType::MemoryMallocSizeFailed => {
385 self.parse_generic_mem_size(&record)?;
386 Some((event_type, Event::Unknown(self.accumulated_time, record)))
387 }
388
389 EventType::UnusedStack => {
390 self.parse_generic_kernel_call_with_param(&record)?;
391 Some((event_type, Event::Unknown(self.accumulated_time, record)))
392 }
393
394 _ => Some((event_type, Event::Unknown(self.accumulated_time, record))),
401 })
402 }
403
404 fn get_timestamp(&mut self, dts: Dts) -> Timestamp {
408 match dts {
410 Dts::Dts8(dts) => {
411 self.dts_for_next_event += dts;
412 }
413 Dts::Dts16(dts) => {
414 self.dts_for_next_event += dts;
415 }
416 }
417
418 self.accumulated_time += self.dts_for_next_event;
420
421 self.dts_for_next_event.clear();
423
424 self.accumulated_time
425 }
426
427 fn parse_generic_kernel_call(&mut self, record: &EventRecord) -> Result<ObjectHandle, Error> {
429 let mut r = ByteOrdered::runtime(record.as_slice(), self.endianness);
430 let _event_code = r.read_u8()?;
431 let obj_handle =
432 ObjectHandle::new(r.read_u8()?.into()).ok_or(Error::InvalidObjectHandle)?;
433 let dts = Dts8(r.read_u8()?);
434 let _timestamp = self.get_timestamp(dts.into());
435 Ok(obj_handle)
436 }
437
438 fn parse_generic_kernel_call_with_param(&mut self, record: &EventRecord) -> Result<(), Error> {
440 let mut r = ByteOrdered::runtime(record.as_slice(), self.endianness);
441 let _event_code = r.read_u8()?;
442 let _obj_handle = r.read_u8()?;
443 let _param = r.read_u8()?;
444 let dts = Dts8(r.read_u8()?);
445 let _timestamp = self.get_timestamp(dts.into());
446 Ok(())
447 }
448
449 fn parse_generic_kernel_call_with_numeric_param(
451 &mut self,
452 record: &EventRecord,
453 ) -> Result<(), Error> {
454 let mut r = ByteOrdered::runtime(record.as_slice(), self.endianness);
455 let _event_code = r.read_u8()?;
456 let dts = Dts8(r.read_u8()?);
457 let _timestamp = self.get_timestamp(dts.into());
458 Ok(())
459 }
460
461 fn parse_generic_mem_size(&mut self, record: &EventRecord) -> Result<(), Error> {
463 let mut r = ByteOrdered::runtime(record.as_slice(), self.endianness);
464 let _event_code = r.read_u8()?;
465 let dts = Dts8(r.read_u8()?);
466 let _size = r.read_u16()?;
467 let _timestamp = self.get_timestamp(dts.into());
468 Ok(())
469 }
470
471 fn parse_generic_task_instance_status(&mut self, record: &EventRecord) -> Result<(), Error> {
473 let mut r = ByteOrdered::runtime(record.as_slice(), self.endianness);
474 let _event_code = r.read_u8()?;
475 let _unused1 = r.read_u8()?;
476 let _unused2 = r.read_u8()?;
477 let dts = Dts8(r.read_u8()?);
478 let _timestamp = self.get_timestamp(dts.into());
479 Ok(())
480 }
481
482 fn begin_user_event(
483 &mut self,
484 user_arg_record_count: UserEventArgRecordCount,
485 record: EventRecord,
486 ) {
487 self.user_arg_record_count = usize::from(user_arg_record_count.0);
488 self.user_event_records.push(record);
489 }
490
491 fn end_user_event(&mut self) {
492 self.user_event_records.clear();
493 self.user_arg_record_count = 0;
494 }
495
496 fn capture_user_event_record(&mut self, record: EventRecord) {
497 self.user_event_records.push(record);
498 }
499
500 fn is_capturing_user_event_records(&self) -> bool {
501 !self.user_event_records.is_empty()
502 }
503
504 fn parse_user_event(
505 &mut self,
506 symbol_table: &SymbolTable,
507 ) -> Result<Option<(EventType, UserEvent)>, Error> {
508 if self.user_event_records.len() == (self.user_arg_record_count + 1) {
509 let base_record = self.user_event_records[0].as_slice();
511 let mut r = ByteOrdered::runtime(base_record, self.endianness);
512 let event_code = EventCode(r.read_u8()?);
513 let event_type = EventType::from(event_code);
514 let dts = Dts8(r.read_u8()?);
515 let format_string_index =
516 ObjectHandle::new(r.read_u16()?.into()).ok_or(Error::InvalidSymbolTableIndex)?;
517
518 let sym_entry = symbol_table
519 .get(format_string_index)
520 .ok_or(Error::FormatSymbolLookup(format_string_index))?;
521
522 let channel = sym_entry
523 .channel_index
524 .and_then(|ci| {
525 symbol_table
526 .get(ci)
527 .map(|se| UserEventChannel::Custom(se.symbol.clone().into()))
528 })
529 .unwrap_or(UserEventChannel::Default);
530
531 let arg_bytes: Vec<u8> = self
532 .user_event_records
533 .iter()
534 .skip(1)
535 .flat_map(|r| r.as_slice().iter())
536 .cloned()
537 .collect();
538 let (formatted_string, args) = match format_symbol_string(
539 symbol_table,
540 Protocol::Snapshot,
541 self.endianness.into(),
542 &sym_entry.symbol,
543 &arg_bytes,
544 ) {
545 Ok((fs, args)) => (fs, args),
546 Err(e) => {
547 error!("Failed to parse user event format string arguments, using the raw symbol instead. {e}");
548 (
549 FormattedString(sym_entry.symbol.to_string()),
550 Default::default(),
551 )
552 }
553 };
554 let event = UserEvent {
555 timestamp: self.get_timestamp(dts.into()),
556 channel,
557 format_string: FormatString(sym_entry.symbol.0.clone()),
558 formatted_string,
559 args,
560 };
561 self.end_user_event();
562 Ok(Some((event_type, event)))
563 } else {
564 Ok(None)
566 }
567 }
568}
569
570#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, From)]
571enum Dts {
572 Dts8(Dts8),
573 Dts16(Dts16),
574}