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(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}