Skip to main content

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::{RawByteStringRef, StringRef};
8use crate::thread::{ProcessKoid, ProcessRef};
9use crate::{
10    KERNEL_OBJ_RECORD_TYPE, ParseResult, Provider, USERSPACE_OBJ_RECORD_TYPE, trace_header,
11};
12use flyweights::{FlyByteStr, FlyStr};
13use nom::Parser;
14use nom::combinator::all_consuming;
15use nom::number::complete::le_u64;
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: FlyByteStr,
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_bstr(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: RawByteStringRef<'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) = RawByteStringRef::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::RawTraceRecord;
209    use crate::args::RawArgValue;
210    use crate::fxt_builder::FxtBuilder;
211    use std::num::{NonZeroU8, NonZeroU16};
212
213    #[test]
214    fn userspace_obj_no_args() {
215        let mut header = UserspaceObjHeader::empty();
216        header.set_process_ref(12);
217        header.set_name_ref(18);
218        header.set_num_args(0);
219
220        assert_parses_to_record!(
221            FxtBuilder::new(header).atom(1024u64.to_le_bytes()).build(),
222            RawTraceRecord::UserspaceObj(RawUserspaceObjRecord {
223                process: ProcessRef::Index(NonZeroU8::new(12).unwrap()),
224                name: StringRef::Index(NonZeroU16::new(18).unwrap()),
225                pointer: 1024,
226                args: vec![],
227            },),
228        );
229    }
230
231    #[test]
232    fn userspace_obj_with_args() {
233        let mut header = UserspaceObjHeader::empty();
234        header.set_process_ref(12);
235        header.set_name_ref(18);
236        header.set_num_args(3);
237
238        let mut first_arg_header = crate::args::BaseArgHeader::empty();
239        let first_arg_value = 1007.893f64;
240        first_arg_header.set_name_ref(10);
241        first_arg_header.set_raw_type(crate::args::F64_ARG_TYPE);
242
243        let second_arg_value = "123-456-7890";
244        let mut second_arg_header = crate::args::StringHeader::empty();
245        second_arg_header.set_name_ref(11);
246        second_arg_header.set_value_ref(
247            fxt_layout::StringRefHeader::inline(second_arg_value.len() as u16).bits(),
248        );
249
250        let third_arg_name = "hello";
251        let mut third_arg_header = crate::args::U32Header::empty();
252        third_arg_header
253            .set_name_ref(fxt_layout::StringRefHeader::inline(third_arg_name.len() as u16).bits());
254        third_arg_header.set_value(23);
255
256        assert_parses_to_record!(
257            FxtBuilder::new(header)
258                .atom(2048u64.to_le_bytes())
259                .atom_words(
260                    FxtBuilder::new(first_arg_header).atom(first_arg_value.to_le_bytes()).build()
261                )
262                .atom_words(FxtBuilder::new(second_arg_header).atom(second_arg_value).build())
263                .atom_words(FxtBuilder::new(third_arg_header).atom(third_arg_name).build())
264                .build(),
265            RawTraceRecord::UserspaceObj(RawUserspaceObjRecord {
266                process: ProcessRef::Index(NonZeroU8::new(12).unwrap()),
267                name: StringRef::Index(NonZeroU16::new(18).unwrap()),
268                pointer: 2048,
269                args: vec![
270                    RawArg {
271                        name: StringRef::Index(NonZeroU16::new(10).unwrap()),
272                        value: RawArgValue::Double(first_arg_value),
273                    },
274                    RawArg {
275                        name: StringRef::Index(NonZeroU16::new(11).unwrap()),
276                        value: RawArgValue::String(StringRef::Inline(second_arg_value)),
277                    },
278                    RawArg {
279                        name: StringRef::Inline(third_arg_name),
280                        value: RawArgValue::Unsigned32(23),
281                    },
282                ],
283            })
284        );
285    }
286
287    #[test]
288    fn kernel_obj_no_args() {
289        let mut header = KernelObjHeader::empty();
290        header.set_kernel_obj_type(zx_types::ZX_OBJ_TYPE_CHANNEL);
291        header.set_name_ref(19);
292        header.set_num_args(0);
293
294        assert_parses_to_record!(
295            FxtBuilder::new(header).atom(64u64.to_le_bytes()).build(),
296            RawTraceRecord::KernelObj(RawKernelObjRecord {
297                koid: 64,
298                ty: KernelObjType::Channel,
299                name: RawByteStringRef::Index(NonZeroU16::new(19).unwrap()),
300                args: vec![],
301            },),
302        );
303    }
304
305    #[test]
306    fn kernel_obj_with_args() {
307        let mut header = KernelObjHeader::empty();
308        header.set_kernel_obj_type(zx_types::ZX_OBJ_TYPE_FIFO);
309        header.set_name_ref(91);
310        header.set_num_args(3);
311
312        let koid = 128u64;
313
314        let mut first_arg_header = crate::args::BaseArgHeader::empty();
315        first_arg_header.set_name_ref(10);
316        first_arg_header.set_raw_type(crate::args::F64_ARG_TYPE);
317
318        let second_arg_value = "123-456-7890";
319        let mut second_arg_header = crate::args::StringHeader::empty();
320        second_arg_header.set_name_ref(11);
321        second_arg_header.set_value_ref(
322            fxt_layout::StringRefHeader::inline(second_arg_value.len() as u16).bits(),
323        );
324
325        let third_arg_name = "hello";
326        let mut third_arg_header = crate::args::U32Header::empty();
327        third_arg_header
328            .set_name_ref(fxt_layout::StringRefHeader::inline(third_arg_name.len() as u16).bits());
329        third_arg_header.set_value(23);
330
331        assert_parses_to_record!(
332            FxtBuilder::new(header)
333                .atom(koid.to_le_bytes())
334                .atom_words(
335                    FxtBuilder::new(first_arg_header).atom(1007.893f64.to_le_bytes()).build()
336                )
337                .atom_words(FxtBuilder::new(second_arg_header).atom(second_arg_value).build())
338                .atom_words(FxtBuilder::new(third_arg_header).atom(third_arg_name).build())
339                .build(),
340            RawTraceRecord::KernelObj(RawKernelObjRecord {
341                koid,
342                ty: KernelObjType::Fifo,
343                name: RawByteStringRef::Index(NonZeroU16::new(91).unwrap()),
344                args: vec![
345                    RawArg {
346                        name: StringRef::Index(NonZeroU16::new(10).unwrap()),
347                        value: RawArgValue::Double(1007.893)
348                    },
349                    RawArg {
350                        name: StringRef::Index(NonZeroU16::new(11).unwrap()),
351                        value: RawArgValue::String(StringRef::Inline(second_arg_value)),
352                    },
353                    RawArg { name: StringRef::Inline("hello"), value: RawArgValue::Unsigned32(23) },
354                ],
355            }),
356        );
357    }
358}