1use 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 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(); buf.extend([1, 1, 1, 1]); 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}