1use crate::string::parse_padded_string;
6use crate::{METADATA_RECORD_TYPE, ParseError, ParseResult, trace_header};
7use flyweights::FlyStr;
8use nom::Parser;
9use nom::combinator::all_consuming;
10
11const PROVIDER_INFO_METADATA_TYPE: u8 = 1;
12const PROVIDER_SECTION_METADATA_TYPE: u8 = 2;
13const PROVIDER_EVENT_METADATA_TYPE: u8 = 3;
14const TRACE_INFO_METADATA_TYPE: u8 = 4;
15
16#[derive(Clone, Debug, PartialEq)]
17pub struct Provider {
18 pub id: u32,
19 pub name: FlyStr,
20}
21
22#[derive(Debug, PartialEq)]
23pub(super) enum MetadataRecord {
24 ProviderInfo(ProviderInfoMetadataRecord),
25 ProviderSection(ProviderSectionMetadataRecord),
26 ProviderEvent(ProviderEventMetadataRecord),
27 TraceInfo(TraceInfoMetadataRecord),
28 Unknown { raw_type: u8 },
29}
30
31impl MetadataRecord {
32 pub(super) fn parse(buf: &[u8]) -> ParseResult<'_, Self> {
33 use nom::combinator::map;
34 match BaseMetadataHeader::parse(buf)?.1.metadata_type() {
35 PROVIDER_INFO_METADATA_TYPE => {
36 map(ProviderInfoMetadataRecord::parse, |i| Self::ProviderInfo(i)).parse(buf)
37 }
38 PROVIDER_SECTION_METADATA_TYPE => {
39 map(ProviderSectionMetadataRecord::parse, |s| Self::ProviderSection(s)).parse(buf)
40 }
41 PROVIDER_EVENT_METADATA_TYPE => {
42 map(ProviderEventMetadataRecord::parse, |e| Self::ProviderEvent(e)).parse(buf)
43 }
44 TRACE_INFO_METADATA_TYPE => {
45 map(TraceInfoMetadataRecord::parse, |t| Self::TraceInfo(t)).parse(buf)
46 }
47 unknown => Ok((buf, Self::Unknown { raw_type: unknown })),
48 }
49 }
50}
51
52macro_rules! metadata_header {
53 ($name:ident $(($metadata_ty:expr))? { $($record_specific:tt)* }) => {
54 trace_header! {
55 $name (METADATA_RECORD_TYPE) {
56 $($record_specific)*
57 u8, metadata_type: 16, 19;
58 } => |_h: &$name| {
59 $(if _h.metadata_type() != $metadata_ty {
60 return Err(ParseError::WrongType {
61 context: stringify!($name),
62 expected: $metadata_ty,
63 observed: _h.metadata_type(),
64 });
65 })?
66 Ok(())
67 }
68 }
69 };
70}
71
72metadata_header! { BaseMetadataHeader {} }
73
74#[derive(Debug, PartialEq)]
75pub(super) struct ProviderInfoMetadataRecord {
76 pub provider_id: u32,
77 pub name: FlyStr,
78}
79
80metadata_header! {
81 ProviderInfoMetadataHeader (PROVIDER_INFO_METADATA_TYPE) {
82 u32, provider_id: 20, 51;
83 u8, name_len: 52, 59;
84 }
85}
86
87impl ProviderInfoMetadataRecord {
88 fn parse(buf: &[u8]) -> ParseResult<'_, Self> {
89 let (buf, header) = ProviderInfoMetadataHeader::parse(buf)?;
90 let (rem, payload) = header.take_payload(buf)?;
91 let (empty, name) =
92 all_consuming(|p| parse_padded_string(header.name_len() as usize, p)).parse(payload)?;
93 assert!(empty.is_empty(), "all_consuming must not return any remaining buffer");
94 Ok((rem, Self { provider_id: header.provider_id(), name: name.into() }))
95 }
96}
97
98#[derive(Debug, PartialEq)]
99pub(super) struct ProviderSectionMetadataRecord {
100 pub provider_id: u32,
101}
102
103metadata_header! {
104 ProviderSectionMetadataHeader (PROVIDER_SECTION_METADATA_TYPE) {
105 u32, provider_id: 20, 51;
106 }
107}
108
109impl ProviderSectionMetadataRecord {
110 fn parse(buf: &[u8]) -> ParseResult<'_, Self> {
111 let (buf, header) = ProviderSectionMetadataHeader::parse(buf)?;
112 let (rem, payload) = header.take_payload(buf)?;
113 if !payload.is_empty() {
114 return Err(nom::Err::Failure(ParseError::InvalidSize));
115 }
116 Ok((rem, Self { provider_id: header.provider_id() }))
117 }
118}
119
120const PROVIDER_EVENT_BUFFER_FULL: u8 = 0;
121
122#[derive(Debug, PartialEq)]
123pub(super) struct ProviderEventMetadataRecord {
124 pub provider_id: u32,
125 pub event: ProviderEvent,
126}
127
128metadata_header! {
129 ProviderEventMetadataHeader (PROVIDER_EVENT_METADATA_TYPE) {
130 u32, provider_id: 20, 51;
131 u8, event_id: 52, 55;
132 }
133}
134
135impl ProviderEventMetadataRecord {
136 fn parse(buf: &[u8]) -> ParseResult<'_, Self> {
137 let (buf, header) = ProviderEventMetadataHeader::parse(buf)?;
138 let provider_id = header.provider_id();
139 let event = match header.event_id() {
140 PROVIDER_EVENT_BUFFER_FULL => ProviderEvent::BufferFull,
141 unknown => ProviderEvent::Unknown { raw_type: unknown },
142 };
143 let (rem, payload) = header.take_payload(buf)?;
144 if !payload.is_empty() {
145 return Err(nom::Err::Failure(ParseError::InvalidSize));
146 }
147 Ok((rem, Self { provider_id, event }))
148 }
149}
150
151#[derive(Clone, Debug, PartialEq)]
152pub enum ProviderEvent {
153 BufferFull,
154 Unknown { raw_type: u8 },
155}
156
157const MAGIC_NUMBER_TRACE_INFO_TYPE: u8 = 0;
158const MAGIC_NUMBER: u32 = 0x16547846;
159
160pub const FXT_MAGIC_BYTES: [u8; 8] = [0x10, 0x00, 0x04, 0x46, 0x78, 0x54, 0x16, 0x00];
162
163pub fn is_magic(bytes: &[u8]) -> bool {
165 bytes.starts_with(&FXT_MAGIC_BYTES)
166}
167
168#[derive(Debug, PartialEq)]
169pub(super) enum TraceInfoMetadataRecord {
170 MagicNumber,
171}
172
173impl TraceInfoMetadataRecord {
174 fn parse(buf: &[u8]) -> ParseResult<'_, Self> {
175 let (buf, header) = MagicNumberHeader::parse(buf)?;
178 if header.trace_info_type() != MAGIC_NUMBER_TRACE_INFO_TYPE {
179 return Err(nom::Err::Error(ParseError::WrongType {
180 context: "MagicNumber",
181 expected: MAGIC_NUMBER_TRACE_INFO_TYPE,
182 observed: header.trace_info_type(),
183 }));
184 }
185 if header.magic_number() != MAGIC_NUMBER {
186 return Err(nom::Err::Failure(ParseError::InvalidMagicNumber {
187 observed: header.magic_number(),
188 }));
189 }
190
191 let (rem, payload) = header.take_payload(buf)?;
192 if !payload.is_empty() {
193 return Err(nom::Err::Failure(ParseError::InvalidSize));
194 }
195
196 Ok((rem, Self::MagicNumber))
197 }
198}
199
200metadata_header! {
201 MagicNumberHeader (TRACE_INFO_METADATA_TYPE) {
202 u8, trace_info_type: 20, 23;
203 u32, magic_number: 24, 55;
204 }
205}
206
207#[cfg(test)]
208mod tests {
209 use super::*;
210 use crate::RawTraceRecord;
211 use crate::fxt_builder::FxtBuilder;
212
213 #[test]
214 fn basic_provider_info() {
215 let name = "hello";
216 let mut header = ProviderInfoMetadataHeader::empty();
217 header.set_metadata_type(PROVIDER_INFO_METADATA_TYPE);
218 header.set_provider_id(16);
219 header.set_name_len(name.len() as _);
220
221 assert_parses_to_record!(
222 FxtBuilder::new(header).atom(name).build(),
223 RawTraceRecord::Metadata(MetadataRecord::ProviderInfo(ProviderInfoMetadataRecord {
224 provider_id: 16,
225 name: "hello".into(),
226 })),
227 );
228 }
229
230 #[test]
231 fn basic_provider_section() {
232 let mut header = ProviderSectionMetadataHeader::empty();
233 header.set_metadata_type(PROVIDER_SECTION_METADATA_TYPE);
234 header.set_provider_id(16);
235
236 assert_parses_to_record!(
237 FxtBuilder::new(header).build(),
238 RawTraceRecord::Metadata(MetadataRecord::ProviderSection(
239 ProviderSectionMetadataRecord { provider_id: 16 }
240 )),
241 );
242 }
243
244 #[test]
245 fn basic_provider_event() {
246 let mut header = ProviderEventMetadataHeader::empty();
247 header.set_metadata_type(PROVIDER_EVENT_METADATA_TYPE);
248 header.set_provider_id(16);
249 header.set_event_id(PROVIDER_EVENT_BUFFER_FULL);
250
251 assert_parses_to_record!(
252 FxtBuilder::new(header).build(),
253 RawTraceRecord::Metadata(MetadataRecord::ProviderEvent(ProviderEventMetadataRecord {
254 provider_id: 16,
255 event: ProviderEvent::BufferFull,
256 })),
257 );
258 }
259
260 #[test]
261 fn magic_number_literal() {
262 let mut buf = 0x0016547846040010u64.to_le_bytes().to_vec(); buf.extend([1, 1, 1, 1]); let (trailing, parsed) = RawTraceRecord::parse(&buf).unwrap();
266 assert_eq!(
267 parsed.parsed,
268 RawTraceRecord::Metadata(MetadataRecord::TraceInfo(
269 TraceInfoMetadataRecord::MagicNumber
270 )),
271 );
272 assert_eq!(trailing, [1, 1, 1, 1]);
273 }
274
275 #[test]
276 fn is_magic_check() {
277 assert!(is_magic(&FXT_MAGIC_BYTES));
278 assert!(is_magic(&[0x10, 0x00, 0x04, 0x46, 0x78, 0x54, 0x16, 0x00, 0xff]));
279 assert!(!is_magic(&FXT_MAGIC_BYTES[..7]));
280 assert!(!is_magic(b"NOT_FXT!"));
281 assert!(!is_magic(&[]));
282 }
283}