trace_recorder_parser/streaming/
entry_table.rs1use 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#[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 pub symbol: Option<SymbolString>,
99 pub options: u32,
100 pub states: EntryStates,
101 pub class: Option<ObjectClass>,
102}
103
104impl Entry {
105 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 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}