1use crate::args::{Arg, RawArg, RawArgValue};
6use crate::fxt_builder::FxtBuilder;
7use crate::init::Ticks;
8use crate::session::ResolveCtx;
9use crate::string::{StringRef, STRING_REF_INLINE_BIT};
10use crate::thread::{ProcessKoid, ProcessRef, ThreadKoid, ThreadRef};
11use crate::{trace_header, ParseResult, Provider, EVENT_RECORD_TYPE};
12use flyweights::FlyStr;
13use nom::number::complete::le_u64;
14use nom::Parser;
15
16pub(crate) const INSTANT_EVENT_TYPE: u8 = 0;
17pub(crate) const COUNTER_EVENT_TYPE: u8 = 1;
18pub(crate) const DURATION_BEGIN_EVENT_TYPE: u8 = 2;
19pub(crate) const DURATION_END_EVENT_TYPE: u8 = 3;
20pub(crate) const DURATION_COMPLETE_EVENT_TYPE: u8 = 4;
21pub(crate) const ASYNC_BEGIN_EVENT_TYPE: u8 = 5;
22pub(crate) const ASYNC_INSTANT_EVENT_TYPE: u8 = 6;
23pub(crate) const ASYNC_END_EVENT_TYPE: u8 = 7;
24pub(crate) const FLOW_BEGIN_EVENT_TYPE: u8 = 8;
25pub(crate) const FLOW_STEP_EVENT_TYPE: u8 = 9;
26pub(crate) const FLOW_END_EVENT_TYPE: u8 = 10;
27
28pub fn symbolize<'a>(
29 ordinal: u64,
30 method: &'a str,
31 raw_record: &RawEventRecord<'a>,
32) -> RawEventRecord<'a> {
33 let mut new_args = vec![];
34 for arg in &raw_record.args {
35 if let &RawArgValue::Unsigned64(arg_value) = &arg.value {
36 if arg_value == ordinal {
37 let symbolized_arg = RawArg {
38 name: StringRef::Inline("method"),
39 value: RawArgValue::String(StringRef::Inline(method)),
40 };
41 new_args.push(symbolized_arg);
42 continue;
43 }
44 }
45 new_args.push(arg.clone());
46 }
47
48 RawEventRecord {
49 event_type: raw_record.event_type,
50 ticks: raw_record.ticks.clone(),
51 process: raw_record.process.clone(),
52 thread: raw_record.thread.clone(),
53 category: raw_record.category.clone(),
54 name: raw_record.name.clone(),
55 args: new_args,
56 payload: raw_record.payload.clone(),
57 }
58}
59
60#[derive(Clone, Debug, PartialEq)]
61pub struct EventRecord {
62 pub provider: Option<Provider>,
63 pub timestamp: i64,
64 pub process: ProcessKoid,
65 pub thread: ThreadKoid,
66 pub category: FlyStr,
67 pub name: FlyStr,
68 pub args: Vec<Arg>,
69 pub payload: EventPayload<i64>,
70}
71
72impl EventRecord {
73 pub(super) fn resolve(ctx: &mut ResolveCtx, raw: RawEventRecord<'_>) -> Self {
74 Self {
75 provider: ctx.current_provider(),
76 timestamp: ctx.resolve_ticks(raw.ticks),
77 process: ctx.resolve_process(raw.process),
78 thread: ctx.resolve_thread(raw.thread),
79 category: ctx.resolve_str(raw.category),
80 name: ctx.resolve_str(raw.name),
81 args: Arg::resolve_n(ctx, raw.args),
82 payload: raw.payload.resolve(ctx),
83 }
84 }
85}
86
87#[derive(Debug, PartialEq)]
88pub struct RawEventRecord<'a> {
89 event_type: u8,
90 ticks: Ticks,
91 process: ProcessRef,
92 thread: ThreadRef,
93 category: StringRef<'a>,
94 pub name: StringRef<'a>,
95 pub args: Vec<RawArg<'a>>,
96 payload: EventPayload<Ticks>,
97}
98
99impl<'a> RawEventRecord<'a> {
100 pub fn parse(buf: &'a [u8]) -> ParseResult<'a, Self> {
101 let (buf, header) = EventHeader::parse(buf)?;
102 let (rem, payload) = header.take_payload(buf)?;
103 let event_type = header.event_type();
104 let (payload, ticks) = Ticks::parse(payload)?;
105 let (payload, process) = ProcessRef::parse(header.thread_ref(), payload)?;
106 let (payload, thread) = ThreadRef::parse(header.thread_ref(), payload)?;
107 let (payload, category) = StringRef::parse(header.category_ref(), payload)?;
108 let (payload, name) = StringRef::parse(header.name_ref(), payload)?;
109 let (payload, args) = RawArg::parse_n(header.num_args(), payload)?;
110
111 let (_empty, payload) = EventPayload::parse(event_type, payload)?;
114 Ok((rem, Self { event_type, ticks, process, thread, category, name, args, payload }))
115 }
116
117 pub fn make_header(&self) -> EventHeader {
118 let mut header = EventHeader::empty();
119 header.set_event_type(self.event_type);
120 header.set_num_args(self.args.len() as u8);
121
122 if let ProcessRef::Index(id) = self.process {
123 header.set_thread_ref(id.into());
124 }
125 let category_ref: u16 = match self.category {
126 StringRef::Index(id) => id.into(),
127 StringRef::Inline(category_stream) => {
128 category_stream.len() as u16 | STRING_REF_INLINE_BIT
129 }
130 StringRef::Empty => 0u16,
131 };
132 header.set_category_ref(category_ref);
133
134 let name_ref: u16 = match self.name {
135 StringRef::Index(id) => id.into(),
136 StringRef::Inline(name_stream) => name_stream.len() as u16 | STRING_REF_INLINE_BIT,
137 StringRef::Empty => 0u16,
138 };
139 header.set_name_ref(name_ref);
140 header
141 }
142
143 pub fn serialize(&self) -> Result<Vec<u8>, String> {
144 let mut event_record = FxtBuilder::new(self.make_header());
145
146 event_record = event_record.atom(self.ticks.0.to_le_bytes());
147
148 if let ProcessRef::Inline(process_koid) = self.process {
149 event_record = event_record.atom(process_koid.0.to_le_bytes());
150 }
151
152 if let ThreadRef::Inline(thread_koid) = self.thread {
153 event_record = event_record.atom(thread_koid.0.to_le_bytes());
154 }
155
156 if let StringRef::Inline(category_stream) = self.category {
157 event_record = event_record.atom(category_stream);
158 }
159
160 if let StringRef::Inline(name_stream) = self.name {
161 event_record = event_record.atom(name_stream);
162 }
163
164 for arg in &self.args {
165 event_record = event_record.atom(arg.serialize()?);
166 }
167
168 match &self.payload {
169 EventPayload::Instant | EventPayload::DurationBegin | EventPayload::DurationEnd => {}
170
171 EventPayload::Counter { id }
172 | EventPayload::AsyncBegin { id }
173 | EventPayload::AsyncInstant { id }
174 | EventPayload::AsyncEnd { id }
175 | EventPayload::FlowBegin { id }
176 | EventPayload::FlowStep { id }
177 | EventPayload::FlowEnd { id } => {
178 event_record = event_record.atom(id.to_le_bytes());
179 }
180
181 EventPayload::DurationComplete { end_timestamp } => {
182 event_record = event_record.atom(end_timestamp.0.to_le_bytes());
183 }
184
185 EventPayload::Unknown { raw_type: _, bytes } => {
186 event_record = event_record.atom(bytes);
187 }
188 }
189 Ok(event_record.build())
190 }
191
192 pub fn set_flow_step_payload(&mut self, id: u64) {
193 self.event_type = FLOW_STEP_EVENT_TYPE;
194 self.payload = EventPayload::FlowStep { id };
195 }
196}
197
198trace_header! {
199 EventHeader (EVENT_RECORD_TYPE) {
200 u8, event_type: 16, 19;
201 u8, num_args: 20, 23;
202 u8, thread_ref: 24, 31;
203 u16, category_ref: 32, 47;
204 u16, name_ref: 48, 63;
205 }
206}
207
208#[derive(Clone, Debug, PartialEq)]
209pub enum EventPayload<Time> {
210 Instant,
211 Counter { id: u64 },
212 DurationBegin,
213 DurationEnd,
214 DurationComplete { end_timestamp: Time },
215 AsyncBegin { id: u64 },
216 AsyncInstant { id: u64 },
217 AsyncEnd { id: u64 },
218 FlowBegin { id: u64 },
219 FlowStep { id: u64 },
220 FlowEnd { id: u64 },
221 Unknown { raw_type: u8, bytes: Vec<u8> },
222}
223
224impl EventPayload<Ticks> {
225 pub(crate) fn resolve(self, ctx: &ResolveCtx) -> EventPayload<i64> {
226 match self {
227 EventPayload::Instant => EventPayload::Instant,
228 EventPayload::Counter { id } => EventPayload::Counter { id },
229 EventPayload::DurationBegin => EventPayload::DurationBegin,
230 EventPayload::DurationEnd => EventPayload::DurationEnd,
231 EventPayload::DurationComplete { end_timestamp } => {
232 EventPayload::DurationComplete { end_timestamp: ctx.resolve_ticks(end_timestamp) }
233 }
234 EventPayload::AsyncBegin { id } => EventPayload::AsyncBegin { id },
235 EventPayload::AsyncInstant { id } => EventPayload::AsyncInstant { id },
236 EventPayload::AsyncEnd { id } => EventPayload::AsyncEnd { id },
237 EventPayload::FlowBegin { id } => EventPayload::FlowBegin { id },
238 EventPayload::FlowStep { id } => EventPayload::FlowStep { id },
239 EventPayload::FlowEnd { id } => EventPayload::FlowEnd { id },
240 EventPayload::Unknown { raw_type, bytes } => EventPayload::Unknown { raw_type, bytes },
241 }
242 }
243}
244
245impl EventPayload<Ticks> {
246 fn parse(event_type: u8, buf: &[u8]) -> ParseResult<'_, Self> {
247 use nom::combinator::map;
248 match event_type {
249 INSTANT_EVENT_TYPE => Ok((buf, EventPayload::Instant)),
250 COUNTER_EVENT_TYPE => map(le_u64, |id| EventPayload::Counter { id }).parse(buf),
251 DURATION_BEGIN_EVENT_TYPE => Ok((buf, EventPayload::DurationBegin)),
252 DURATION_END_EVENT_TYPE => Ok((buf, EventPayload::DurationEnd)),
253 DURATION_COMPLETE_EVENT_TYPE => {
254 map(Ticks::parse, |end_timestamp| EventPayload::DurationComplete { end_timestamp })
255 .parse(buf)
256 }
257 ASYNC_BEGIN_EVENT_TYPE => map(le_u64, |id| EventPayload::AsyncBegin { id }).parse(buf),
258 ASYNC_INSTANT_EVENT_TYPE => {
259 map(le_u64, |id| EventPayload::AsyncInstant { id }).parse(buf)
260 }
261 ASYNC_END_EVENT_TYPE => map(le_u64, |id| EventPayload::AsyncEnd { id }).parse(buf),
262 FLOW_BEGIN_EVENT_TYPE => map(le_u64, |id| EventPayload::FlowBegin { id }).parse(buf),
263 FLOW_STEP_EVENT_TYPE => map(le_u64, |id| EventPayload::FlowStep { id }).parse(buf),
264 FLOW_END_EVENT_TYPE => map(le_u64, |id| EventPayload::FlowEnd { id }).parse(buf),
265 unknown => {
266 Ok((&[][..], EventPayload::Unknown { raw_type: unknown, bytes: buf.to_vec() }))
267 }
268 }
269 }
270}
271
272#[cfg(test)]
273mod tests {
274 use super::*;
275 use crate::RawTraceRecord;
276 use std::num::{NonZeroU16, NonZeroU8};
277
278 #[test]
279 fn event_no_args() {
280 let mut header = EventHeader::empty();
281 header.set_thread_ref(11);
282 header.set_category_ref(27);
283 header.set_name_ref(93);
284 header.set_num_args(0);
285 header.set_event_type(INSTANT_EVENT_TYPE);
286
287 let event_record_bytes = FxtBuilder::new(header).atom(2048u64.to_le_bytes()).build();
288 let raw_event_record = RawEventRecord {
289 event_type: INSTANT_EVENT_TYPE,
290 ticks: Ticks(2048),
291 process: ProcessRef::Index(NonZeroU8::new(11).unwrap()),
292 thread: ThreadRef::Index(NonZeroU8::new(11).unwrap()),
293 category: StringRef::Index(NonZeroU16::new(27).unwrap()),
294 name: StringRef::Index(NonZeroU16::new(93).unwrap()),
295 args: vec![],
296 payload: EventPayload::Instant,
297 };
298
299 assert_eq!(raw_event_record.serialize().unwrap(), event_record_bytes);
300 assert_parses_to_record!(event_record_bytes, RawTraceRecord::Event(raw_event_record));
301 }
302
303 #[test]
304 fn event_with_args() {
305 let mut header = EventHeader::empty();
306 header.set_event_type(DURATION_COMPLETE_EVENT_TYPE);
307 header.set_category_ref("event_category".len() as u16 | STRING_REF_INLINE_BIT);
308 header.set_name_ref("event_name".len() as u16 | STRING_REF_INLINE_BIT);
309 header.set_num_args(2);
310
311 let first_arg_name = "arg1";
312 let first_arg_value = "val1";
313 let mut first_arg_header = crate::args::StringHeader::empty();
314 first_arg_header.set_name_ref(first_arg_name.len() as u16 | STRING_REF_INLINE_BIT);
315 first_arg_header.set_value_ref(first_arg_value.len() as u16 | STRING_REF_INLINE_BIT);
316
317 let second_arg_name = "arg2";
318 let mut second_arg_header = crate::args::BaseArgHeader::empty();
319 second_arg_header.set_raw_type(crate::args::PTR_ARG_TYPE);
320 second_arg_header.set_name_ref(second_arg_name.len() as u16 | STRING_REF_INLINE_BIT);
321
322 let event_record_bytes = FxtBuilder::new(header)
323 .atom(2048u64.to_le_bytes())
325 .atom(345u64.to_le_bytes())
327 .atom(678u64.to_le_bytes())
329 .atom("event_category")
331 .atom("event_name")
333 .atom(
335 FxtBuilder::new(first_arg_header)
336 .atom(first_arg_name)
337 .atom(first_arg_value)
338 .build(),
339 )
340 .atom(
342 FxtBuilder::new(second_arg_header)
343 .atom(second_arg_name)
344 .atom(123456u64.to_le_bytes())
345 .build(),
346 )
347 .atom(4096u64.to_le_bytes())
349 .build();
350
351 let raw_event_record = RawEventRecord {
352 event_type: DURATION_COMPLETE_EVENT_TYPE,
353 ticks: Ticks(2048),
354 process: ProcessRef::Inline(ProcessKoid(345)),
355 thread: ThreadRef::Inline(ThreadKoid(678)),
356 category: StringRef::Inline("event_category"),
357 name: StringRef::Inline("event_name"),
358 args: vec![
359 RawArg {
360 name: StringRef::Inline(first_arg_name),
361 value: crate::args::RawArgValue::String(StringRef::Inline(first_arg_value)),
362 },
363 RawArg {
364 name: StringRef::Inline(second_arg_name),
365 value: crate::args::RawArgValue::Pointer(123456),
366 },
367 ],
368 payload: EventPayload::DurationComplete { end_timestamp: Ticks(4096) },
369 };
370
371 assert_eq!(raw_event_record.serialize().unwrap(), event_record_bytes);
372 assert_parses_to_record!(event_record_bytes, RawTraceRecord::Event(raw_event_record));
373 }
374
375 #[test]
376 fn symbolize_event() {
377 let ordinal: u64 = 123456;
378 let method_name = "fidl_method";
379 let raw_event_record = RawEventRecord {
380 event_type: INSTANT_EVENT_TYPE,
381 ticks: Ticks(2048),
382 process: ProcessRef::Inline(ProcessKoid(345)),
383 thread: ThreadRef::Inline(ThreadKoid(678)),
384 category: StringRef::Inline("event_category"),
385 name: StringRef::Inline("event_name"),
386 args: vec![
387 RawArg {
388 name: StringRef::Inline("arg1"),
389 value: crate::args::RawArgValue::Pointer(123456),
390 },
391 RawArg {
392 name: StringRef::Index(NonZeroU16::new(8).unwrap()),
393 value: crate::args::RawArgValue::Unsigned64(ordinal),
394 },
395 ],
396 payload: EventPayload::DurationComplete { end_timestamp: Ticks(4096) },
397 };
398
399 assert_eq!(
400 symbolize(ordinal, method_name, &raw_event_record),
401 RawEventRecord {
402 event_type: INSTANT_EVENT_TYPE,
403 ticks: Ticks(2048),
404 process: ProcessRef::Inline(ProcessKoid(345)),
405 thread: ThreadRef::Inline(ThreadKoid(678)),
406 category: StringRef::Inline("event_category"),
407 name: StringRef::Inline("event_name"),
408 args: vec![
409 RawArg {
410 name: StringRef::Inline("arg1"),
411 value: crate::args::RawArgValue::Pointer(123456),
412 },
413 RawArg {
414 name: StringRef::Inline("method"),
415 value: crate::args::RawArgValue::String(StringRef::Inline(method_name)),
416 }
417 ],
418 payload: EventPayload::DurationComplete { end_timestamp: Ticks(4096) },
419 }
420 );
421 }
422}