1use 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 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}