trace_recorder_parser/streaming/
entry_table.rs

1use crate::streaming::Error;
2use crate::types::{
3    Endianness, Heap, ObjectClass, ObjectHandle, Priority, SymbolString, SymbolTableExt,
4    TrimmedString, STARTUP_TASK_NAME, TZ_CTRL_TASK_NAME,
5};
6use byteordered::ByteOrdered;
7use std::collections::BTreeMap;
8use std::io::Read;
9use tracing::debug;
10
11/// The address field of an entry is the key.
12/// This is either an object address (task, queue, etc) or the address of the
13/// entry "slot" in memory (self-referential, i.e. user event strings).
14#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
15pub struct EntryTable(BTreeMap<ObjectHandle, Entry>);
16
17impl Default for EntryTable {
18    fn default() -> Self {
19        let mut entries = BTreeMap::new();
20        let mut states = EntryStates::default();
21        states.set_priority(Priority(1));
22        entries.insert(
23            ObjectHandle::NO_TASK,
24            Entry {
25                symbol: SymbolString(STARTUP_TASK_NAME.to_owned()).into(),
26                options: 0,
27                states,
28                class: ObjectClass::Task.into(),
29            },
30        );
31        Self(entries)
32    }
33}
34
35impl EntryTable {
36    pub fn entries(&self) -> &BTreeMap<ObjectHandle, Entry> {
37        &self.0
38    }
39
40    pub fn symbol(&self, handle: ObjectHandle) -> Option<&SymbolString> {
41        self.0.get(&handle).and_then(|e| e.symbol.as_ref())
42    }
43
44    pub fn class(&self, handle: ObjectHandle) -> Option<ObjectClass> {
45        self.0.get(&handle).and_then(|e| e.class)
46    }
47
48    pub fn symbol_handle<S: AsRef<str>>(
49        &self,
50        symbol: S,
51        class: Option<ObjectClass>,
52    ) -> Option<ObjectHandle> {
53        self.0.iter().find_map(|(handle, entry)| {
54            let sym_match = entry.symbol.as_deref() == Some(symbol.as_ref());
55            let class_match = match class {
56                None => true,
57                Some(c) => entry.class == Some(c),
58            };
59            if sym_match && class_match {
60                Some(*handle)
61            } else {
62                None
63            }
64        })
65    }
66
67    pub(crate) fn system_heap(&self) -> Option<Heap> {
68        self.0
69            .values()
70            .find_map(|entry| {
71                if entry.symbol.as_deref() == Some(Entry::SYSTEM_HEAP_SYMBOL) {
72                    Some(&entry.states)
73                } else {
74                    None
75                }
76            })
77            .map(|states| Heap {
78                current: states.heap_current(),
79                high_water_mark: states.heap_high_water_mark(),
80                max: states.heap_max(),
81            })
82    }
83
84    pub(crate) fn entry(&mut self, handle: ObjectHandle) -> &mut Entry {
85        self.0.entry(handle).or_default()
86    }
87}
88
89impl SymbolTableExt for EntryTable {
90    fn symbol(&self, handle: ObjectHandle) -> Option<&SymbolString> {
91        EntryTable::symbol(self, handle)
92    }
93}
94
95#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
96pub struct Entry {
97    /// The symbol (lossy converted to UTF8)                                                                           
98    pub symbol: Option<SymbolString>,
99    pub options: u32,
100    pub states: EntryStates,
101    pub class: Option<ObjectClass>,
102}
103
104impl Entry {
105    /// See `TRC_ENTRY_TABLE_SLOT_SYMBOL_SIZE`
106    pub const MIN_SYMBOL_SIZE: usize = 1;
107
108    pub(crate) const SYSTEM_HEAP_SYMBOL: &'static str = "System Heap";
109
110    pub(crate) fn set_symbol(&mut self, symbol: SymbolString) {
111        self.symbol = symbol.into()
112    }
113
114    pub(crate) fn set_class(&mut self, class: ObjectClass) {
115        self.class = class.into()
116    }
117}
118
119#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
120pub struct EntryStates([u32; EntryStates::NUM_STATES]);
121
122impl EntryStates {
123    /// See `TRC_ENTRY_TABLE_STATE_COUNT`
124    pub const NUM_STATES: usize = 3;
125
126    pub(crate) fn new_unchecked(states: &[u32]) -> Self {
127        Self([states[0], states[1], states[2]])
128    }
129
130    pub(crate) const fn priority(&self) -> Priority {
131        Priority(self.0[0])
132    }
133
134    pub(crate) fn set_priority(&mut self, priority: Priority) {
135        self.0[0] = priority.0;
136    }
137
138    pub(crate) const fn heap_current(&self) -> u32 {
139        self.0[0]
140    }
141
142    pub(crate) const fn heap_high_water_mark(&self) -> u32 {
143        self.0[1]
144    }
145
146    pub(crate) const fn heap_max(&self) -> u32 {
147        self.0[2]
148    }
149}
150
151impl EntryTable {
152    pub(crate) fn read<R: Read>(r: &mut R, endianness: Endianness) -> Result<Self, Error> {
153        let mut r = ByteOrdered::new(r, byteordered::Endianness::from(endianness));
154        let num_entries = r.read_u32()?;
155        let symbol_size = r.read_u32()? as usize;
156        let state_count = r.read_u32()? as usize;
157        debug!(num_entries, symbol_size, state_count);
158
159        if symbol_size < Entry::MIN_SYMBOL_SIZE {
160            return Err(Error::InvalidEntryTableSymbolSize);
161        } else if state_count < EntryStates::NUM_STATES {
162            return Err(Error::InvalidEntryTableStateCount);
163        }
164
165        let mut table = EntryTable::default();
166        if num_entries == 0 {
167            Ok(table)
168        } else {
169            let mut buf = vec![0; symbol_size];
170            let mut states_buf = vec![0_u32; state_count];
171            for _ in 0..num_entries {
172                let address = r.read_u32()?;
173                r.read_u32_into(&mut states_buf)?;
174                let states = EntryStates::new_unchecked(&states_buf);
175                let options = r.read_u32()?;
176                r.read_exact(&mut buf)?;
177                if let Some(oh) = ObjectHandle::new(address) {
178                    let symbol: SymbolString = TrimmedString::from_raw(&buf).into();
179
180                    let class = if symbol.0 == TZ_CTRL_TASK_NAME {
181                        Some(ObjectClass::Task)
182                    } else {
183                        None
184                    };
185
186                    table.0.insert(
187                        oh,
188                        Entry {
189                            symbol: if !symbol.0.is_empty() {
190                                Some(symbol)
191                            } else {
192                                None
193                            },
194                            options,
195                            states,
196                            class,
197                        },
198                    );
199                }
200            }
201            Ok(table)
202        }
203    }
204}