fxt/
objects.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::args::{Arg, RawArg};
6use crate::session::ResolveCtx;
7use crate::string::StringRef;
8use crate::thread::{ProcessKoid, ProcessRef};
9use crate::{
10    trace_header, ParseResult, Provider, KERNEL_OBJ_RECORD_TYPE, USERSPACE_OBJ_RECORD_TYPE,
11};
12use flyweights::FlyStr;
13use nom::combinator::all_consuming;
14use nom::number::complete::le_u64;
15use nom::Parser;
16
17#[derive(Clone, Debug, PartialEq)]
18pub struct UserspaceObjRecord {
19    pub provider: Option<Provider>,
20    pub pointer: u64,
21    pub process: ProcessKoid,
22    pub name: FlyStr,
23    pub args: Vec<Arg>,
24}
25
26impl UserspaceObjRecord {
27    pub(super) fn resolve(ctx: &mut ResolveCtx, raw: RawUserspaceObjRecord<'_>) -> Self {
28        Self {
29            provider: ctx.current_provider(),
30            pointer: raw.pointer,
31            process: ctx.resolve_process(raw.process),
32            name: ctx.resolve_str(raw.name),
33            args: Arg::resolve_n(ctx, raw.args),
34        }
35    }
36}
37
38#[derive(Debug, PartialEq)]
39pub(super) struct RawUserspaceObjRecord<'a> {
40    pointer: u64,
41    process: ProcessRef,
42    name: StringRef<'a>,
43    args: Vec<RawArg<'a>>,
44}
45
46impl<'a> RawUserspaceObjRecord<'a> {
47    pub(super) fn parse(buf: &'a [u8]) -> ParseResult<'a, Self> {
48        let (buf, header) = UserspaceObjHeader::parse(buf)?;
49        let (rem, payload) = header.take_payload(buf)?;
50        let (payload, pointer) = le_u64(payload)?;
51        let (payload, process) = ProcessRef::parse(header.process_ref(), payload)?;
52        let (payload, name) = StringRef::parse(header.name_ref(), payload)?;
53        let (empty, args) =
54            all_consuming(|p| RawArg::parse_n(header.num_args(), p)).parse(payload)?;
55        assert!(empty.is_empty(), "all_consuming must not return any remaining buffer");
56        Ok((rem, Self { pointer, process, name, args }))
57    }
58}
59
60trace_header! {
61    UserspaceObjHeader (USERSPACE_OBJ_RECORD_TYPE) {
62        u8, process_ref: 16, 23;
63        u16, name_ref: 24, 39;
64        u8, num_args: 40, 43;
65    }
66}
67
68#[derive(Clone, Debug, PartialEq)]
69pub struct KernelObjRecord {
70    pub provider: Option<Provider>,
71    pub koid: u64,
72    pub ty: KernelObjType,
73    pub name: FlyStr,
74    pub args: Vec<Arg>,
75}
76
77impl KernelObjRecord {
78    /// By convention kobj records have a "process" arg which lists the process koid.
79    pub fn process(&self) -> Option<ProcessKoid> {
80        for arg in &self.args {
81            if arg.name == "process" {
82                if let Some(k) = arg.value.kernel_obj() {
83                    return Some(ProcessKoid(k));
84                }
85            }
86        }
87        None
88    }
89
90    pub(super) fn resolve(ctx: &mut ResolveCtx, raw: RawKernelObjRecord<'_>) -> Self {
91        Self {
92            provider: ctx.current_provider(),
93            koid: raw.koid,
94            ty: raw.ty,
95            name: ctx.resolve_str(raw.name),
96            args: Arg::resolve_n(ctx, raw.args),
97        }
98    }
99}
100
101#[derive(Debug, PartialEq)]
102pub(crate) struct RawKernelObjRecord<'a> {
103    koid: u64,
104    ty: KernelObjType,
105    name: StringRef<'a>,
106    args: Vec<RawArg<'a>>,
107}
108
109impl<'a> RawKernelObjRecord<'a> {
110    pub(super) fn parse(buf: &'a [u8]) -> ParseResult<'a, Self> {
111        let (buf, header) = KernelObjHeader::parse(buf)?;
112        let ty = KernelObjType::from(header.kernel_obj_type());
113        let (rem, payload) = header.take_payload(buf)?;
114        let (payload, koid) = le_u64(payload)?;
115        let (payload, name) = StringRef::parse(header.name_ref(), payload)?;
116        let (empty, args) =
117            all_consuming(|p| RawArg::parse_n(header.num_args(), p)).parse(payload)?;
118        assert!(empty.is_empty(), "all_consuming must not return any remaining buffer");
119        Ok((rem, Self { koid, name, args, ty }))
120    }
121}
122
123trace_header! {
124    KernelObjHeader (KERNEL_OBJ_RECORD_TYPE) {
125        u32, kernel_obj_type: 16, 23;
126        u16, name_ref: 24, 39;
127        u8, num_args: 40, 43;
128    }
129}
130
131#[derive(Clone, Copy, Debug, PartialEq)]
132pub enum KernelObjType {
133    None,
134    Process,
135    Thread,
136    Vmo,
137    Channel,
138    Event,
139    Port,
140    Interrupt,
141    PciDevice,
142    DebugLog,
143    Socket,
144    Resource,
145    EventPair,
146    Job,
147    Vmar,
148    Fifo,
149    Guest,
150    Vcpu,
151    Timer,
152    Iommu,
153    Bti,
154    Profile,
155    Pmt,
156    SuspendToken,
157    Pager,
158    Exception,
159    Clock,
160    Stream,
161    Msi,
162    Iob,
163    Unknown(u32),
164}
165
166impl From<u32> for KernelObjType {
167    fn from(raw: u32) -> Self {
168        use zx_types::*;
169        match raw {
170            ZX_OBJ_TYPE_NONE => Self::None,
171            ZX_OBJ_TYPE_PROCESS => Self::Process,
172            ZX_OBJ_TYPE_THREAD => Self::Thread,
173            ZX_OBJ_TYPE_VMO => Self::Vmo,
174            ZX_OBJ_TYPE_CHANNEL => Self::Channel,
175            ZX_OBJ_TYPE_EVENT => Self::Event,
176            ZX_OBJ_TYPE_PORT => Self::Port,
177            ZX_OBJ_TYPE_INTERRUPT => Self::Interrupt,
178            ZX_OBJ_TYPE_PCI_DEVICE => Self::PciDevice,
179            ZX_OBJ_TYPE_DEBUGLOG => Self::DebugLog,
180            ZX_OBJ_TYPE_SOCKET => Self::Socket,
181            ZX_OBJ_TYPE_RESOURCE => Self::Resource,
182            ZX_OBJ_TYPE_EVENTPAIR => Self::EventPair,
183            ZX_OBJ_TYPE_JOB => Self::Job,
184            ZX_OBJ_TYPE_VMAR => Self::Vmar,
185            ZX_OBJ_TYPE_FIFO => Self::Fifo,
186            ZX_OBJ_TYPE_GUEST => Self::Guest,
187            ZX_OBJ_TYPE_VCPU => Self::Vcpu,
188            ZX_OBJ_TYPE_TIMER => Self::Timer,
189            ZX_OBJ_TYPE_IOMMU => Self::Iommu,
190            ZX_OBJ_TYPE_BTI => Self::Bti,
191            ZX_OBJ_TYPE_PROFILE => Self::Profile,
192            ZX_OBJ_TYPE_PMT => Self::Pmt,
193            ZX_OBJ_TYPE_SUSPEND_TOKEN => Self::SuspendToken,
194            ZX_OBJ_TYPE_PAGER => Self::Pager,
195            ZX_OBJ_TYPE_EXCEPTION => Self::Exception,
196            ZX_OBJ_TYPE_CLOCK => Self::Clock,
197            ZX_OBJ_TYPE_STREAM => Self::Stream,
198            ZX_OBJ_TYPE_MSI => Self::Msi,
199            ZX_OBJ_TYPE_IOB => Self::Iob,
200            unknown => Self::Unknown(unknown),
201        }
202    }
203}
204
205#[cfg(test)]
206mod tests {
207    use super::*;
208    use crate::args::RawArgValue;
209    use crate::fxt_builder::FxtBuilder;
210    use crate::string::STRING_REF_INLINE_BIT;
211    use crate::RawTraceRecord;
212    use std::num::{NonZeroU16, NonZeroU8};
213
214    #[test]
215    fn userspace_obj_no_args() {
216        let mut header = UserspaceObjHeader::empty();
217        header.set_process_ref(12);
218        header.set_name_ref(18);
219        header.set_num_args(0);
220
221        assert_parses_to_record!(
222            FxtBuilder::new(header).atom(1024u64.to_le_bytes()).build(),
223            RawTraceRecord::UserspaceObj(RawUserspaceObjRecord {
224                process: ProcessRef::Index(NonZeroU8::new(12).unwrap()),
225                name: StringRef::Index(NonZeroU16::new(18).unwrap()),
226                pointer: 1024,
227                args: vec![],
228            },),
229        );
230    }
231
232    #[test]
233    fn userspace_obj_with_args() {
234        let mut header = UserspaceObjHeader::empty();
235        header.set_process_ref(12);
236        header.set_name_ref(18);
237        header.set_num_args(3);
238
239        let mut first_arg_header = crate::args::BaseArgHeader::empty();
240        let first_arg_value = 1007.893f64;
241        first_arg_header.set_name_ref(10);
242        first_arg_header.set_raw_type(crate::args::F64_ARG_TYPE);
243
244        let second_arg_value = "123-456-7890";
245        let mut second_arg_header = crate::args::StringHeader::empty();
246        second_arg_header.set_name_ref(11);
247        second_arg_header.set_value_ref(second_arg_value.len() as u16 | STRING_REF_INLINE_BIT);
248
249        let third_arg_name = "hello";
250        let mut third_arg_header = crate::args::U32Header::empty();
251        third_arg_header.set_name_ref(third_arg_name.len() as u16 | STRING_REF_INLINE_BIT);
252        third_arg_header.set_value(23);
253
254        assert_parses_to_record!(
255            FxtBuilder::new(header)
256                .atom(2048u64.to_le_bytes())
257                .atom(FxtBuilder::new(first_arg_header).atom(first_arg_value.to_le_bytes()).build())
258                .atom(FxtBuilder::new(second_arg_header).atom(second_arg_value).build())
259                .atom(FxtBuilder::new(third_arg_header).atom(third_arg_name).build())
260                .build(),
261            RawTraceRecord::UserspaceObj(RawUserspaceObjRecord {
262                process: ProcessRef::Index(NonZeroU8::new(12).unwrap()),
263                name: StringRef::Index(NonZeroU16::new(18).unwrap()),
264                pointer: 2048,
265                args: vec![
266                    RawArg {
267                        name: StringRef::Index(NonZeroU16::new(10).unwrap()),
268                        value: RawArgValue::Double(first_arg_value),
269                    },
270                    RawArg {
271                        name: StringRef::Index(NonZeroU16::new(11).unwrap()),
272                        value: RawArgValue::String(StringRef::Inline(second_arg_value)),
273                    },
274                    RawArg {
275                        name: StringRef::Inline(third_arg_name),
276                        value: RawArgValue::Unsigned32(23),
277                    },
278                ],
279            })
280        );
281    }
282
283    #[test]
284    fn kernel_obj_no_args() {
285        let mut header = KernelObjHeader::empty();
286        header.set_kernel_obj_type(zx_types::ZX_OBJ_TYPE_CHANNEL);
287        header.set_name_ref(19);
288        header.set_num_args(0);
289
290        assert_parses_to_record!(
291            FxtBuilder::new(header).atom(64u64.to_le_bytes()).build(),
292            RawTraceRecord::KernelObj(RawKernelObjRecord {
293                koid: 64,
294                ty: KernelObjType::Channel,
295                name: StringRef::Index(NonZeroU16::new(19).unwrap()),
296                args: vec![],
297            },),
298        );
299    }
300
301    #[test]
302    fn kernel_obj_with_args() {
303        let mut header = KernelObjHeader::empty();
304        header.set_kernel_obj_type(zx_types::ZX_OBJ_TYPE_FIFO);
305        header.set_name_ref(91);
306        header.set_num_args(3);
307
308        let koid = 128u64;
309
310        let mut first_arg_header = crate::args::BaseArgHeader::empty();
311        first_arg_header.set_name_ref(10);
312        first_arg_header.set_raw_type(crate::args::F64_ARG_TYPE);
313
314        let second_arg_value = "123-456-7890";
315        let mut second_arg_header = crate::args::StringHeader::empty();
316        second_arg_header.set_name_ref(11);
317        second_arg_header.set_value_ref(second_arg_value.len() as u16 | STRING_REF_INLINE_BIT);
318
319        let third_arg_name = "hello";
320        let mut third_arg_header = crate::args::U32Header::empty();
321        third_arg_header.set_name_ref(third_arg_name.len() as u16 | STRING_REF_INLINE_BIT);
322        third_arg_header.set_value(23);
323
324        assert_parses_to_record!(
325            FxtBuilder::new(header)
326                .atom(koid.to_le_bytes())
327                .atom(FxtBuilder::new(first_arg_header).atom(1007.893f64.to_le_bytes()).build())
328                .atom(FxtBuilder::new(second_arg_header).atom(second_arg_value).build())
329                .atom(FxtBuilder::new(third_arg_header).atom(third_arg_name).build())
330                .build(),
331            RawTraceRecord::KernelObj(RawKernelObjRecord {
332                koid,
333                ty: KernelObjType::Fifo,
334                name: StringRef::Index(NonZeroU16::new(91).unwrap()),
335                args: vec![
336                    RawArg {
337                        name: StringRef::Index(NonZeroU16::new(10).unwrap()),
338                        value: RawArgValue::Double(1007.893)
339                    },
340                    RawArg {
341                        name: StringRef::Index(NonZeroU16::new(11).unwrap()),
342                        value: RawArgValue::String(StringRef::Inline(second_arg_value)),
343                    },
344                    RawArg { name: StringRef::Inline("hello"), value: RawArgValue::Unsigned32(23) },
345                ],
346            }),
347        );
348    }
349}