1use crate::args::{Arg, RawArg, RawArgValue};
6use crate::fxt_builder::{FxtBuilder, SerializeError};
7use crate::init::Ticks;
8use crate::session::ResolveCtx;
9use crate::string::StringRef;
10use crate::thread::{ProcessKoid, ProcessRef, ThreadKoid, ThreadRef};
11use crate::{EVENT_RECORD_TYPE, ParseResult, Provider, trace_header};
12use flyweights::FlyStr;
13use nom::Parser;
14use nom::number::complete::le_u64;
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 pub(crate) event_type: u8,
90 pub(crate) ticks: Ticks,
91 pub(crate) process: ProcessRef,
92 pub(crate) thread: ThreadRef,
93 pub(crate) category: StringRef<'a>,
94 pub name: StringRef<'a>,
95 pub args: Vec<RawArg<'a>>,
96 pub(crate) 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) => fxt_layout::StringRefHeader::indexed(id.into()).bits(),
127 StringRef::Inline(category_stream) => {
128 fxt_layout::StringRefHeader::inline(category_stream.len() as u16).bits()
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) => fxt_layout::StringRefHeader::indexed(id.into()).bits(),
136 StringRef::Inline(name_stream) => {
137 fxt_layout::StringRefHeader::inline(name_stream.len() as u16).bits()
138 }
139 StringRef::Empty => 0u16,
140 };
141 header.set_name_ref(name_ref);
142 header
143 }
144
145 pub fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
146 let mut event_record = FxtBuilder::new(self.make_header());
147
148 event_record = event_record.atom(self.ticks.0.to_le_bytes());
149
150 if let ProcessRef::Inline(process_koid) = self.process {
151 event_record = event_record.atom(process_koid.0.to_le_bytes());
152 }
153
154 if let ThreadRef::Inline(thread_koid) = self.thread {
155 event_record = event_record.atom(thread_koid.0.to_le_bytes());
156 }
157
158 if let StringRef::Inline(category_stream) = self.category {
159 event_record = event_record.atom(category_stream);
160 }
161
162 if let StringRef::Inline(name_stream) = self.name {
163 event_record = event_record.atom(name_stream);
164 }
165
166 for arg in &self.args {
167 event_record = event_record.atom(arg.serialize()?);
168 }
169
170 match &self.payload {
171 EventPayload::Instant | EventPayload::DurationBegin | EventPayload::DurationEnd => {}
172
173 EventPayload::Counter { id }
174 | EventPayload::AsyncBegin { id }
175 | EventPayload::AsyncInstant { id }
176 | EventPayload::AsyncEnd { id }
177 | EventPayload::FlowBegin { id }
178 | EventPayload::FlowStep { id }
179 | EventPayload::FlowEnd { id } => {
180 event_record = event_record.atom(id.to_le_bytes());
181 }
182
183 EventPayload::DurationComplete { end_timestamp } => {
184 event_record = event_record.atom(end_timestamp.0.to_le_bytes());
185 }
186
187 EventPayload::Unknown { raw_type: _, bytes } => {
188 event_record = event_record.atom(bytes);
189 }
190 }
191 Ok(event_record.build())
192 }
193
194 pub fn set_flow_step_payload(&mut self, id: u64) {
195 self.event_type = FLOW_STEP_EVENT_TYPE;
196 self.payload = EventPayload::FlowStep { id };
197 }
198}
199
200trace_header! {
201 EventHeader (EVENT_RECORD_TYPE) {
202 u8, event_type: 16, 19;
203 u8, num_args: 20, 23;
204 u8, thread_ref: 24, 31;
205 u16, category_ref: 32, 47;
206 u16, name_ref: 48, 63;
207 }
208}
209
210#[derive(Clone, Debug, PartialEq)]
211pub enum EventPayload<Time> {
212 Instant,
213 Counter { id: u64 },
214 DurationBegin,
215 DurationEnd,
216 DurationComplete { end_timestamp: Time },
217 AsyncBegin { id: u64 },
218 AsyncInstant { id: u64 },
219 AsyncEnd { id: u64 },
220 FlowBegin { id: u64 },
221 FlowStep { id: u64 },
222 FlowEnd { id: u64 },
223 Unknown { raw_type: u8, bytes: Vec<u8> },
224}
225
226impl EventPayload<Ticks> {
227 pub(crate) fn resolve(self, ctx: &ResolveCtx) -> EventPayload<i64> {
228 match self {
229 EventPayload::Instant => EventPayload::Instant,
230 EventPayload::Counter { id } => EventPayload::Counter { id },
231 EventPayload::DurationBegin => EventPayload::DurationBegin,
232 EventPayload::DurationEnd => EventPayload::DurationEnd,
233 EventPayload::DurationComplete { end_timestamp } => {
234 EventPayload::DurationComplete { end_timestamp: ctx.resolve_ticks(end_timestamp) }
235 }
236 EventPayload::AsyncBegin { id } => EventPayload::AsyncBegin { id },
237 EventPayload::AsyncInstant { id } => EventPayload::AsyncInstant { id },
238 EventPayload::AsyncEnd { id } => EventPayload::AsyncEnd { id },
239 EventPayload::FlowBegin { id } => EventPayload::FlowBegin { id },
240 EventPayload::FlowStep { id } => EventPayload::FlowStep { id },
241 EventPayload::FlowEnd { id } => EventPayload::FlowEnd { id },
242 EventPayload::Unknown { raw_type, bytes } => EventPayload::Unknown { raw_type, bytes },
243 }
244 }
245}
246
247impl EventPayload<Ticks> {
248 fn parse(event_type: u8, buf: &[u8]) -> ParseResult<'_, Self> {
249 use nom::combinator::map;
250 match event_type {
251 INSTANT_EVENT_TYPE => Ok((buf, EventPayload::Instant)),
252 COUNTER_EVENT_TYPE => map(le_u64, |id| EventPayload::Counter { id }).parse(buf),
253 DURATION_BEGIN_EVENT_TYPE => Ok((buf, EventPayload::DurationBegin)),
254 DURATION_END_EVENT_TYPE => Ok((buf, EventPayload::DurationEnd)),
255 DURATION_COMPLETE_EVENT_TYPE => {
256 map(Ticks::parse, |end_timestamp| EventPayload::DurationComplete { end_timestamp })
257 .parse(buf)
258 }
259 ASYNC_BEGIN_EVENT_TYPE => map(le_u64, |id| EventPayload::AsyncBegin { id }).parse(buf),
260 ASYNC_INSTANT_EVENT_TYPE => {
261 map(le_u64, |id| EventPayload::AsyncInstant { id }).parse(buf)
262 }
263 ASYNC_END_EVENT_TYPE => map(le_u64, |id| EventPayload::AsyncEnd { id }).parse(buf),
264 FLOW_BEGIN_EVENT_TYPE => map(le_u64, |id| EventPayload::FlowBegin { id }).parse(buf),
265 FLOW_STEP_EVENT_TYPE => map(le_u64, |id| EventPayload::FlowStep { id }).parse(buf),
266 FLOW_END_EVENT_TYPE => map(le_u64, |id| EventPayload::FlowEnd { id }).parse(buf),
267 unknown => {
268 Ok((&[][..], EventPayload::Unknown { raw_type: unknown, bytes: buf.to_vec() }))
269 }
270 }
271 }
272}
273
274#[cfg(test)]
275mod tests {
276 use super::*;
277 use crate::RawTraceRecord;
278 use std::num::{NonZeroU8, NonZeroU16};
279
280 #[test]
281 fn event_no_args() {
282 let mut header = EventHeader::empty();
283 header.set_thread_ref(11);
284 header.set_category_ref(27);
285 header.set_name_ref(93);
286 header.set_num_args(0);
287 header.set_event_type(INSTANT_EVENT_TYPE);
288
289 let event_record_bytes = FxtBuilder::new(header).atom(2048u64.to_le_bytes()).build();
290 let raw_event_record = RawEventRecord {
291 event_type: INSTANT_EVENT_TYPE,
292 ticks: Ticks(2048),
293 process: ProcessRef::Index(NonZeroU8::new(11).unwrap()),
294 thread: ThreadRef::Index(NonZeroU8::new(11).unwrap()),
295 category: StringRef::Index(NonZeroU16::new(27).unwrap()),
296 name: StringRef::Index(NonZeroU16::new(93).unwrap()),
297 args: vec![],
298 payload: EventPayload::Instant,
299 };
300
301 assert_eq!(raw_event_record.serialize().unwrap(), event_record_bytes);
302 assert_parses_to_record!(event_record_bytes, RawTraceRecord::Event(raw_event_record));
303 }
304
305 #[test]
306 fn event_with_args() {
307 let mut header = EventHeader::empty();
308 header.set_event_type(DURATION_COMPLETE_EVENT_TYPE);
309 header.set_category_ref(
310 fxt_layout::StringRefHeader::inline("event_category".len() as u16).bits(),
311 );
312 header.set_name_ref(fxt_layout::StringRefHeader::inline("event_name".len() as u16).bits());
313 header.set_num_args(2);
314
315 let first_arg_name = "arg1";
316 let first_arg_value = "val1";
317 let mut first_arg_header = crate::args::StringHeader::empty();
318 first_arg_header
319 .set_name_ref(fxt_layout::StringRefHeader::inline(first_arg_name.len() as u16).bits());
320 first_arg_header.set_value_ref(
321 fxt_layout::StringRefHeader::inline(first_arg_value.len() as u16).bits(),
322 );
323
324 let second_arg_name = "arg2";
325 let mut second_arg_header = crate::args::BaseArgHeader::empty();
326 second_arg_header.set_raw_type(crate::args::PTR_ARG_TYPE);
327 second_arg_header
328 .set_name_ref(fxt_layout::StringRefHeader::inline(second_arg_name.len() as u16).bits());
329
330 let event_record_bytes = FxtBuilder::new(header)
331 .atom(2048u64.to_le_bytes())
333 .atom(345u64.to_le_bytes())
335 .atom(678u64.to_le_bytes())
337 .atom("event_category")
339 .atom("event_name")
341 .atom(
343 FxtBuilder::new(first_arg_header)
344 .atom(first_arg_name)
345 .atom(first_arg_value)
346 .build(),
347 )
348 .atom(
350 FxtBuilder::new(second_arg_header)
351 .atom(second_arg_name)
352 .atom(123456u64.to_le_bytes())
353 .build(),
354 )
355 .atom(4096u64.to_le_bytes())
357 .build();
358
359 let raw_event_record = RawEventRecord {
360 event_type: DURATION_COMPLETE_EVENT_TYPE,
361 ticks: Ticks(2048),
362 process: ProcessRef::Inline(ProcessKoid(345)),
363 thread: ThreadRef::Inline(ThreadKoid(678)),
364 category: StringRef::Inline("event_category"),
365 name: StringRef::Inline("event_name"),
366 args: vec![
367 RawArg {
368 name: StringRef::Inline(first_arg_name),
369 value: crate::args::RawArgValue::String(StringRef::Inline(first_arg_value)),
370 },
371 RawArg {
372 name: StringRef::Inline(second_arg_name),
373 value: crate::args::RawArgValue::Pointer(123456),
374 },
375 ],
376 payload: EventPayload::DurationComplete { end_timestamp: Ticks(4096) },
377 };
378
379 assert_eq!(raw_event_record.serialize().unwrap(), event_record_bytes);
380 assert_parses_to_record!(event_record_bytes, RawTraceRecord::Event(raw_event_record));
381 }
382
383 #[test]
384 fn symbolize_event() {
385 let ordinal: u64 = 123456;
386 let method_name = "fidl_method";
387 let raw_event_record = RawEventRecord {
388 event_type: INSTANT_EVENT_TYPE,
389 ticks: Ticks(2048),
390 process: ProcessRef::Inline(ProcessKoid(345)),
391 thread: ThreadRef::Inline(ThreadKoid(678)),
392 category: StringRef::Inline("event_category"),
393 name: StringRef::Inline("event_name"),
394 args: vec![
395 RawArg {
396 name: StringRef::Inline("arg1"),
397 value: crate::args::RawArgValue::Pointer(123456),
398 },
399 RawArg {
400 name: StringRef::Index(NonZeroU16::new(8).unwrap()),
401 value: crate::args::RawArgValue::Unsigned64(ordinal),
402 },
403 ],
404 payload: EventPayload::DurationComplete { end_timestamp: Ticks(4096) },
405 };
406
407 assert_eq!(
408 symbolize(ordinal, method_name, &raw_event_record),
409 RawEventRecord {
410 event_type: INSTANT_EVENT_TYPE,
411 ticks: Ticks(2048),
412 process: ProcessRef::Inline(ProcessKoid(345)),
413 thread: ThreadRef::Inline(ThreadKoid(678)),
414 category: StringRef::Inline("event_category"),
415 name: StringRef::Inline("event_name"),
416 args: vec![
417 RawArg {
418 name: StringRef::Inline("arg1"),
419 value: crate::args::RawArgValue::Pointer(123456),
420 },
421 RawArg {
422 name: StringRef::Inline("method"),
423 value: crate::args::RawArgValue::String(StringRef::Inline(method_name)),
424 }
425 ],
426 payload: EventPayload::DurationComplete { end_timestamp: Ticks(4096) },
427 }
428 );
429 }
430}