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(FxtBuilder::new(first_arg_header).atom(first_arg_value.to_le_bytes()).build())
260                .atom(FxtBuilder::new(second_arg_header).atom(second_arg_value).build())
261                .atom(FxtBuilder::new(third_arg_header).atom(third_arg_name).build())
262                .build(),
263            RawTraceRecord::UserspaceObj(RawUserspaceObjRecord {
264                process: ProcessRef::Index(NonZeroU8::new(12).unwrap()),
265                name: StringRef::Index(NonZeroU16::new(18).unwrap()),
266                pointer: 2048,
267                args: vec![
268                    RawArg {
269                        name: StringRef::Index(NonZeroU16::new(10).unwrap()),
270                        value: RawArgValue::Double(first_arg_value),
271                    },
272                    RawArg {
273                        name: StringRef::Index(NonZeroU16::new(11).unwrap()),
274                        value: RawArgValue::String(StringRef::Inline(second_arg_value)),
275                    },
276                    RawArg {
277                        name: StringRef::Inline(third_arg_name),
278                        value: RawArgValue::Unsigned32(23),
279                    },
280                ],
281            })
282        );
283    }
284
285    #[test]
286    fn kernel_obj_no_args() {
287        let mut header = KernelObjHeader::empty();
288        header.set_kernel_obj_type(zx_types::ZX_OBJ_TYPE_CHANNEL);
289        header.set_name_ref(19);
290        header.set_num_args(0);
291
292        assert_parses_to_record!(
293            FxtBuilder::new(header).atom(64u64.to_le_bytes()).build(),
294            RawTraceRecord::KernelObj(RawKernelObjRecord {
295                koid: 64,
296                ty: KernelObjType::Channel,
297                name: RawByteStringRef::Index(NonZeroU16::new(19).unwrap()),
298                args: vec![],
299            },),
300        );
301    }
302
303    #[test]
304    fn kernel_obj_with_args() {
305        let mut header = KernelObjHeader::empty();
306        header.set_kernel_obj_type(zx_types::ZX_OBJ_TYPE_FIFO);
307        header.set_name_ref(91);
308        header.set_num_args(3);
309
310        let koid = 128u64;
311
312        let mut first_arg_header = crate::args::BaseArgHeader::empty();
313        first_arg_header.set_name_ref(10);
314        first_arg_header.set_raw_type(crate::args::F64_ARG_TYPE);
315
316        let second_arg_value = "123-456-7890";
317        let mut second_arg_header = crate::args::StringHeader::empty();
318        second_arg_header.set_name_ref(11);
319        second_arg_header.set_value_ref(
320            fxt_layout::StringRefHeader::inline(second_arg_value.len() as u16).bits(),
321        );
322
323        let third_arg_name = "hello";
324        let mut third_arg_header = crate::args::U32Header::empty();
325        third_arg_header
326            .set_name_ref(fxt_layout::StringRefHeader::inline(third_arg_name.len() as u16).bits());
327        third_arg_header.set_value(23);
328
329        assert_parses_to_record!(
330            FxtBuilder::new(header)
331                .atom(koid.to_le_bytes())
332                .atom(FxtBuilder::new(first_arg_header).atom(1007.893f64.to_le_bytes()).build())
333                .atom(FxtBuilder::new(second_arg_header).atom(second_arg_value).build())
334                .atom(FxtBuilder::new(third_arg_header).atom(third_arg_name).build())
335                .build(),
336            RawTraceRecord::KernelObj(RawKernelObjRecord {
337                koid,
338                ty: KernelObjType::Fifo,
339                name: RawByteStringRef::Index(NonZeroU16::new(91).unwrap()),
340                args: vec![
341                    RawArg {
342                        name: StringRef::Index(NonZeroU16::new(10).unwrap()),
343                        value: RawArgValue::Double(1007.893)
344                    },
345                    RawArg {
346                        name: StringRef::Index(NonZeroU16::new(11).unwrap()),
347                        value: RawArgValue::String(StringRef::Inline(second_arg_value)),
348                    },
349                    RawArg { name: StringRef::Inline("hello"), value: RawArgValue::Unsigned32(23) },
350                ],
351            }),
352        );
353    }
354}