trace_recorder_parser/snapshot/event/
parser.rs

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 of the data
51    endianness: Endianness,
52
53    /// Timestamp accumulated from differential timestamps
54    accumulated_time: Timestamp,
55
56    /// Differential timestamp upper bytes from an XTS8 or XTS16 event that precedes
57    /// an event to form a complete differential timestamp for the event
58    dts_for_next_event: DifferentialTimestamp,
59
60    /// Number of user event argument records that follow the base user event record
61    user_arg_record_count: usize,
62
63    /// User event record buffer, all other events are single records
64    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        // User events are special; they can span multiple records
88        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        // Everything else have a u8 event code prefix in the record
96        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                        _ /*EventType::TaskSwitchTaskResume*/ => 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                    // Other object classes not handled currently
172                    _ => 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            // NOTE XTS events aren't surfaced to the user, since they're just added to
183            // fulfill the differential timestamps of actual events
184            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            // If the record was being written at the time of reading, skip it
220            EventType::EventBeingWritten => None,
221
222            // The rest of the match arms are only to handle the various DTS-carrying
223            // event records and return Event::Unknown
224            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            // Default case, pass back a raw event record
395            //
396            // NOTE take extra care to handle DTS-carrying events
397            // elsewhere to maintain the accumulated time.
398            //
399            // This *must* only be for records that don't have DTS fields.
400            _ => Some((event_type, Event::Unknown(self.accumulated_time, record))),
401        })
402    }
403
404    /// Combines an events DTS (lower 8 or 16 bits) to the possibly
405    /// existing XTS DTS to form a complete DTS.
406    /// Then adds that to the timestamp accumulator for an absolute event timestamp.
407    fn get_timestamp(&mut self, dts: Dts) -> Timestamp {
408        // Form a complete DTS
409        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        // Add it to the accumulated time
419        self.accumulated_time += self.dts_for_next_event;
420
421        // Done with the DTS
422        self.dts_for_next_event.clear();
423
424        self.accumulated_time
425    }
426
427    /// Process the DTS portion of a record containing a `struct KernelCall`
428    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    /// Process the DTS portion of a record containing a `struct KernelCallWithParamAndHandle`
439    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    /// Process the DTS portion of a record containing a `struct KernelCallWithParam16`
450    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    /// Process the DTS portion of a record containing a `struct MemEventSize`
462    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    /// Process the DTS portion of a record containing a `struct TaskInstanceStatusEvent`
472    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            // SAFETY: we just ensured we have at least the base record
510            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            // Waiting for more arg records
565            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}