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