fxt/
metadata.rs

1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::string::parse_padded_string;
6use crate::{trace_header, ParseError, ParseResult, METADATA_RECORD_TYPE};
7use flyweights::FlyStr;
8use nom::combinator::all_consuming;
9use nom::Parser;
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
160#[derive(Debug, PartialEq)]
161pub(super) enum TraceInfoMetadataRecord {
162    MagicNumber,
163}
164
165impl TraceInfoMetadataRecord {
166    fn parse(buf: &[u8]) -> ParseResult<'_, Self> {
167        // The magic number record is the only trace info record currently specified, so we can
168        // parse it directly here without confusing it with other record types.
169        let (buf, header) = MagicNumberHeader::parse(buf)?;
170        if header.trace_info_type() != MAGIC_NUMBER_TRACE_INFO_TYPE {
171            return Err(nom::Err::Error(ParseError::WrongType {
172                context: "MagicNumber",
173                expected: MAGIC_NUMBER_TRACE_INFO_TYPE,
174                observed: header.trace_info_type(),
175            }));
176        }
177        if header.magic_number() != MAGIC_NUMBER {
178            return Err(nom::Err::Failure(ParseError::InvalidMagicNumber {
179                observed: header.magic_number(),
180            }));
181        }
182
183        let (rem, payload) = header.take_payload(buf)?;
184        if !payload.is_empty() {
185            return Err(nom::Err::Failure(ParseError::InvalidSize));
186        }
187
188        Ok((rem, Self::MagicNumber))
189    }
190}
191
192metadata_header! {
193    MagicNumberHeader (TRACE_INFO_METADATA_TYPE) {
194        u8, trace_info_type: 20, 23;
195        u32, magic_number: 24, 55;
196    }
197}
198
199#[cfg(test)]
200mod tests {
201    use super::*;
202    use crate::fxt_builder::FxtBuilder;
203    use crate::RawTraceRecord;
204
205    #[test]
206    fn basic_provider_info() {
207        let name = "hello";
208        let mut header = ProviderInfoMetadataHeader::empty();
209        header.set_metadata_type(PROVIDER_INFO_METADATA_TYPE);
210        header.set_provider_id(16);
211        header.set_name_len(name.len() as _);
212
213        assert_parses_to_record!(
214            FxtBuilder::new(header).atom(name).build(),
215            RawTraceRecord::Metadata(MetadataRecord::ProviderInfo(ProviderInfoMetadataRecord {
216                provider_id: 16,
217                name: "hello".into(),
218            })),
219        );
220    }
221
222    #[test]
223    fn basic_provider_section() {
224        let mut header = ProviderSectionMetadataHeader::empty();
225        header.set_metadata_type(PROVIDER_SECTION_METADATA_TYPE);
226        header.set_provider_id(16);
227
228        assert_parses_to_record!(
229            FxtBuilder::new(header).build(),
230            RawTraceRecord::Metadata(MetadataRecord::ProviderSection(
231                ProviderSectionMetadataRecord { provider_id: 16 }
232            )),
233        );
234    }
235
236    #[test]
237    fn basic_provider_event() {
238        let mut header = ProviderEventMetadataHeader::empty();
239        header.set_metadata_type(PROVIDER_EVENT_METADATA_TYPE);
240        header.set_provider_id(16);
241        header.set_event_id(PROVIDER_EVENT_BUFFER_FULL);
242
243        assert_parses_to_record!(
244            FxtBuilder::new(header).build(),
245            RawTraceRecord::Metadata(MetadataRecord::ProviderEvent(ProviderEventMetadataRecord {
246                provider_id: 16,
247                event: ProviderEvent::BufferFull,
248            })),
249        );
250    }
251
252    #[test]
253    fn magic_number_literal() {
254        let mut buf = 0x0016547846040010u64.to_le_bytes().to_vec(); // header
255        buf.extend([1, 1, 1, 1]); // trailing
256
257        let (trailing, parsed) = RawTraceRecord::parse(&buf).unwrap();
258        assert_eq!(
259            parsed.parsed,
260            RawTraceRecord::Metadata(MetadataRecord::TraceInfo(
261                TraceInfoMetadataRecord::MagicNumber
262            )),
263        );
264        assert_eq!(trailing, [1, 1, 1, 1]);
265    }
266}