1use convert_case::{Case, Casing};
2use proc_macro::TokenStream;
3use proc_macro2::Span;
4use proc_macro_crate::{crate_name, FoundCrate};
5use quote::{format_ident, quote, quote_spanned, ToTokens};
6use syn::{
7 braced, bracketed, parenthesized, parse::Parse, parse_macro_input, punctuated::Punctuated, spanned::Spanned, token,
8 Expr, GenericArgument, Ident, PathArguments, Token, Type,
9};
10
11#[allow(dead_code)]
12struct ModifiedArgsExpr {
13 plus: Token![+],
14 brace_token: token::Brace,
15 args: Punctuated<ArgField, Token![,]>,
16}
17
18impl Parse for ModifiedArgsExpr {
19 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
20 let content;
21 Ok(Self {
22 plus: input.parse()?,
23 brace_token: braced!(content in input),
24 args: content.parse_terminated(ArgField::parse, Token![,])?,
25 })
26 }
27}
28
29#[allow(dead_code)]
30struct Decoder {
31 at: Token![@],
32 func: Ident,
33 paren_token: token::Paren,
34 args: Punctuated<Expr, Token![,]>,
35}
36
37impl Decoder {
38 fn decoded(&self, arg_name: &Ident, arg_type: proc_macro2::TokenStream, span: Span) -> proc_macro2::TokenStream {
39 let mut counter = 0u32;
40 let func: &Ident = &self.func;
41 let (target_trait, is_result) = match func.to_string().as_str() {
42 "sized_by" => (format_ident!("InspectDynSizedFromPid"), false),
43 "counted_by" => (format_ident!("InspectCountedFromPid"), false),
44 "sized_by_result" => (format_ident!("InspectDynSizedFromPid"), true),
45 "counted_by_result" => (format_ident!("InspectCountedFromPid"), true),
46 _ => panic!("Unsupported decoder function: {:?}", func),
47 };
48 let args = &self.args;
49 if !is_result {
50 quote_spanned! {
51 span =>
52 let #arg_name = <#arg_type as #target_trait>::inspect_from(inspectee_pid, raw_args.#arg_name as AddressType, (#args) as usize);
53 }
54 } else {
55 counter += 1;
56 let tmp_name = format_ident!("tmp_{}", counter);
57 quote_spanned! {
58 span =>
59 let #arg_name = if let Ok(&#tmp_name) = (#args).as_ref() {
60 <#arg_type as #target_trait>::inspect_from(inspectee_pid, raw_args.#arg_name as AddressType, #tmp_name as usize)
61 } else {
62 Err(InspectError::DependencyInspectFailure { field: stringify!(#arg_name) })
63 };
64 }
65 }
66 }
67}
68
69impl Parse for Decoder {
70 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
71 let content;
72 Ok(Self {
73 at: input.parse()?,
74 func: input.parse()?,
75 paren_token: parenthesized!(content in input),
76 args: content.parse_terminated(Expr::parse, Token![,])?,
77 })
78 }
79}
80
81#[allow(dead_code)]
82struct ArgField {
83 ident: Ident,
84 colon_token: Token![:],
85 ty: Type,
86 decoder: Option<Decoder>,
87}
88
89impl Parse for ArgField {
90 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
91 let ident = input.parse()?;
92 let colon_token = input.parse()?;
93 let ty = input.parse()?;
94 let lookahead = input.lookahead1();
95 let decoder = if lookahead.peek(Token![@]) {
96 Some(input.parse()?)
97 } else {
98 None
99 };
100 Ok(Self {
101 ident,
102 colon_token,
103 ty,
104 decoder,
105 })
106 }
107}
108
109#[allow(dead_code)]
110struct SyscallEntry {
111 name: syn::Ident,
112 paren_token: token::Paren,
113 raw_args: Punctuated<ArgField, Token![,]>,
114 separator: Token![/],
115 brace_token: token::Brace,
116 args: Punctuated<ArgField, Token![,]>,
117 arrow: Token![->],
118 result: Ident,
119 modified_args: Option<ModifiedArgsExpr>,
120 for_token: Token![for],
121 bracket_token: token::Bracket,
122 archs: Punctuated<Arch, Token![,]>,
123 group_token: Token![~],
124 bracket_token_2: token::Bracket,
125 groups: Punctuated<Ident, Token![,]>,
126 span: Option<Span>,
127}
128
129impl Parse for SyscallEntry {
130 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
131 let content;
132 let raw_args;
133 let archs_content;
134 let groups_content;
135 let start;
136 let end;
137 Ok(SyscallEntry {
138 name: {
139 let name: Ident = input.parse()?;
140 start = name.span();
141 name
142 },
143 paren_token: parenthesized!(raw_args in input),
144 raw_args: raw_args.parse_terminated(ArgField::parse, Token![,])?,
145 separator: input.parse()?,
146 brace_token: braced!(content in input),
147 args: content.parse_terminated(ArgField::parse, Token![,])?,
148 arrow: input.parse()?,
149 result: input.parse()?,
150 modified_args: {
151 let lookahead = input.lookahead1();
152 if lookahead.peek(token::Plus) {
153 Some(input.parse()?)
154 } else {
155 None
156 }
157 },
158 group_token: input.parse()?,
159 bracket_token_2: bracketed!(groups_content in input),
160 groups: groups_content.parse_terminated(Ident::parse, Token![,])?,
161 for_token: input.parse()?,
162 bracket_token: bracketed!(archs_content in input),
163 archs: {
164 let archs = archs_content.parse_terminated(Arch::parse, Token![,])?;
165 end = archs.last().unwrap().span;
166 archs
167 },
168 span: end.and_then(|end| start.join(end)),
169 })
170 }
171}
172
173#[allow(dead_code)]
174struct Arch {
175 name: syn::Ident,
176 colon: Token![:],
177 number: syn::LitInt,
178 span: Option<Span>,
179}
180
181impl Parse for Arch {
182 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
183 let start;
184 let end;
185 Ok(Arch {
186 name: {
187 let name: Ident = input.parse()?;
188 start = name.span();
189 name
190 },
191 colon: input.parse()?,
192 number: {
193 let number: syn::LitInt = input.parse()?;
194 end = number.span();
195 number
196 },
197 span: start.join(end),
198 })
199 }
200}
201
202struct GenSyscallArgsStructResult {
203 args_struct: proc_macro2::TokenStream,
204 raw_args_struct: proc_macro2::TokenStream,
205 modified_args_struct: proc_macro2::TokenStream,
206 name: Ident,
207 args_struct_type: Ident,
208 raw_args_struct_type: Ident,
209 modified_args_struct_type: Ident,
210 archs: Vec<String>,
211 syscall_number: Ident,
212 syscall_const_name: Ident,
213}
214
215fn gen_syscall_args_struct(
216 syscall: &SyscallEntry,
217 crate_token: proc_macro2::TokenStream,
218) -> GenSyscallArgsStructResult {
219 let span = syscall.span.unwrap_or_else(Span::call_site);
220 let name = &syscall.name;
221 let args = &syscall.args;
222 let groups_idents = &syscall.groups.iter().collect::<Vec<_>>();
223 let groups = if groups_idents.is_empty() {
224 quote_spanned! { span =>
225 #crate_token::SyscallGroups::empty()
226 }
227 } else {
228 quote_spanned! { span =>
229 #(#crate_token::SyscallGroups::#groups_idents)|*
230 }
231 };
232 let arch_name_0 = syscall.archs.first().as_ref().unwrap().name.to_string();
233 let arch_number_0 = &syscall.archs.first().as_ref().unwrap().number;
234 let (mut arch_names, numbers): (Vec<_>, Vec<_>) = syscall
235 .archs
236 .iter()
237 .skip(1)
238 .map(|x| (x.name.to_string(), x.number.clone()))
239 .unzip();
240 let syscall_number = quote_spanned! { span =>
241 if cfg!(target_arch = #arch_name_0) {
242 #arch_number_0
243 }
244 #(
245 else if cfg!(target_arch = #arch_names) {
246 #numbers
247 }
248 )*
249 else {
250 unreachable!()
251 }
252 };
253 arch_names.insert(0, arch_name_0);
254 let mut camel_case_name = name.to_string().to_case(Case::UpperCamel);
255 let camel_case_ident = Ident::new(&camel_case_name, name.span());
256 camel_case_name.push_str("Args");
257 let camel_case_args_type = Ident::new(&camel_case_name, name.span());
258 camel_case_name.replace_range((camel_case_name.len() - 4).., "RawArgs");
259 let camel_case_raw_args_type = Ident::new(&camel_case_name, name.span());
260 camel_case_name.replace_range((camel_case_name.len() - 7).., "ModifiedArgs");
261 let camel_case_modified_args_type = Ident::new(&camel_case_name, name.span());
262 let mut inspects = vec![];
263 let mut arg_names = vec![];
264 let mut wrapped_arg_types = vec![];
265 for arg in args.iter() {
266 let arg_name = &arg.ident;
267 arg_names.push(arg_name.clone());
268 let arg_type = &arg.ty;
269 let (wrapped_arg_type, need_memory_inspection) = wrap_syscall_arg_type(arg_type, span);
270 wrapped_arg_types.push(wrapped_arg_type.clone());
271 if !need_memory_inspection {
272 let inspect = quote_spanned! { span =>
273 let #arg_name = raw_args.#arg_name as #wrapped_arg_type;
274 };
275 inspects.push(inspect);
276 } else if let Some(decoder) = &arg.decoder {
277 let decoded = decoder.decoded(arg_name, wrapped_arg_type, span);
278 inspects.push(decoded);
279 } else {
280 inspects.push(quote_spanned! { span =>
281 let #arg_name: #wrapped_arg_type = #crate_token::InspectFromPid::inspect_from(inspectee_pid, raw_args.#arg_name as #crate_token::AddressType);
282 });
283 }
284 }
285 let mut raw_arg_names = vec![];
286 let mut raw_arg_types = vec![];
287 let mut inspect_raw_args = vec![];
288 for (i, raw_arg) in syscall.raw_args.iter().enumerate() {
289 let arg_name = &raw_arg.ident;
290 raw_arg_names.push(arg_name.clone());
291 let arg_type = &raw_arg.ty;
292 raw_arg_types.push(arg_type.clone());
293 let literal_i = syn::LitInt::new(&i.to_string(), arg_type.span());
294 inspect_raw_args.push(quote_spanned! { span =>
295 let #arg_name = syscall_arg!(regs, #literal_i) as #arg_type;
296 });
297 }
298 let mut modified_arg_names = vec![];
299 let mut modified_arg_names_err = vec![];
300 let mut modified_arg_types = vec![];
301 let mut inspect_modified_args = vec![];
302 let syscall_result_type = &syscall.result;
303 modified_arg_names.push(format_ident!("syscall_result"));
304 modified_arg_types.push(quote_spanned! { span => #syscall_result_type });
305 let (inspect_syscall_result, is_syscall_failed) = if syscall_result_type != "Unit" {
306 (
307 quote_spanned! {
308 span =>
309 let syscall_result = syscall_res_from_regs!(regs) as #syscall_result_type;
310 },
311 quote_spanned! { span => (syscall_result as isize) < 0 },
312 )
313 } else {
314 (quote_spanned! { span => let syscall_result = (); }, quote_spanned! { span => false })
315 };
316 if let Some(modified_args) = &syscall.modified_args {
317 for modified_arg in modified_args.args.iter() {
318 let arg_name = &modified_arg.ident;
319 modified_arg_names.push(arg_name.clone());
320 modified_arg_names_err.push(quote_spanned! { span =>
321 #arg_name: Err(InspectError::SyscallFailure)
322 });
323 let arg_type = &modified_arg.ty;
324 let (wrapped_arg_type, need_memory_inspection) = wrap_syscall_arg_type(arg_type, span);
325 modified_arg_types.push(wrapped_arg_type.clone());
326 if !need_memory_inspection {
327 let inspect = quote_spanned! { span =>
328 let #arg_name = raw_args.#arg_name as #wrapped_arg_type;
329 };
330 inspect_modified_args.push(inspect);
331 } else if let Some(decoder) = &modified_arg.decoder {
332 let decoded = decoder.decoded(arg_name, wrapped_arg_type, span);
333 inspect_modified_args.push(decoded);
334 } else {
335 inspect_modified_args.push(quote_spanned! { span =>
336 let #arg_name: #wrapped_arg_type = #crate_token::InspectFromPid::inspect_from(inspectee_pid, raw_args.#arg_name as #crate_token::AddressType);
337 });
338 }
339 }
340 }
341 let syscall_const_name = format_ident!("SYS_{}", name);
342 GenSyscallArgsStructResult {
343 syscall_number: syscall_const_name.clone(),
344 raw_args_struct: quote_spanned! { span =>
345 #[cfg(any(#(target_arch = #arch_names),*))]
346 pub const #syscall_const_name: isize = #syscall_number;
347
348 #[cfg(any(#(target_arch = #arch_names),*))]
349 #[derive(Debug, Clone, Copy, PartialEq)]
350 pub struct #camel_case_raw_args_type {
351 #(pub #raw_arg_names: #raw_arg_types),*
352 }
353
354 #[cfg(any(#(target_arch = #arch_names),*))]
355 impl #camel_case_raw_args_type {
356 fn from_regs(regs: &#crate_token::arch::PtraceRegisters) -> Self {
357 use #crate_token::arch::syscall_arg;
358 #(#inspect_raw_args)*
359 Self {
360 #(#raw_arg_names),*
361 }
362 }
363 }
364
365 #[cfg(any(#(target_arch = #arch_names),*))]
366 impl #crate_token::SyscallNumber for #camel_case_raw_args_type {
367 #[inline(always)]
368 fn syscall_number(&self) -> isize {
369 #syscall_const_name
370 }
371 }
372
373 #[cfg(any(#(target_arch = #arch_names),*))]
374 impl #crate_token::SyscallGroupsGetter for #camel_case_raw_args_type {
375 #[inline(always)]
376 fn syscall_groups(&self) -> ::enumflags2::BitFlags<#crate_token::SyscallGroups> {
377 use ::enumflags2::BitFlag;
378 {
379 #groups
380 }.into()
381 }
382 }
383
384 #[cfg(any(#(target_arch = #arch_names),*))]
385 impl #crate_token::SyscallStopInspect for #camel_case_raw_args_type {
386 type Args = #camel_case_args_type;
387 type Result = #camel_case_modified_args_type;
388 fn inspect_sysenter(self, inspectee_pid: Pid) -> Self::Args {
389 let raw_args = self;
390 #(#inspects)*
391 Self::Args {
392 #(#arg_names),*
393 }
394 }
395 fn inspect_sysexit(self, inspectee_pid: Pid, regs: &PtraceRegisters) -> Self::Result {
396 let raw_args = self;
397 #inspect_syscall_result
398 if #is_syscall_failed {
399 Self::Result {
400 syscall_result,
401 #(#modified_arg_names_err),*
402 }
403 } else {
404 #(#inspect_modified_args)*
405 Self::Result {
406 #(#modified_arg_names),*
407 }
408 }
409 }
410 }
411 },
412 args_struct: quote_spanned! { span =>
413 #[cfg(any(#(target_arch = #arch_names),*))]
414 #[derive(Debug, Clone, PartialEq)]
415 pub struct #camel_case_args_type {
416 #(pub #arg_names: #wrapped_arg_types),*
417 }
418
419 #[cfg(any(#(target_arch = #arch_names),*))]
420 impl #crate_token::SyscallNumber for #camel_case_args_type {
421 #[inline(always)]
422 fn syscall_number(&self) -> isize {
423 #syscall_const_name
424 }
425 }
426
427 #[cfg(any(#(target_arch = #arch_names),*))]
428 impl #crate_token::SyscallGroupsGetter for #camel_case_args_type {
429 #[inline(always)]
430 fn syscall_groups(&self) -> ::enumflags2::BitFlags<#crate_token::SyscallGroups> {
431 use ::enumflags2::BitFlag;
432 {
433 #groups
434 }.into()
435 }
436 }
437
438 #[cfg(any(#(target_arch = #arch_names),*))]
439 impl From<#camel_case_args_type> for #crate_token::SyscallArgs {
440 fn from(args: #camel_case_args_type) -> Self {
441 #crate_token::SyscallArgs::#camel_case_ident(args)
442 }
443 }
444 },
445 modified_args_struct: quote_spanned! { span =>
446 #[cfg(any(#(target_arch = #arch_names),*))]
447 #[derive(Debug, Clone, PartialEq)]
448 pub struct #camel_case_modified_args_type {
449 #(pub #modified_arg_names: #modified_arg_types),*
450 }
451
452 #[cfg(any(#(target_arch = #arch_names),*))]
453 impl #crate_token::SyscallNumber for #camel_case_modified_args_type {
454 #[inline(always)]
455 fn syscall_number(&self) -> isize {
456 #syscall_const_name
457 }
458 }
459
460 #[cfg(any(#(target_arch = #arch_names),*))]
461 impl #crate_token::SyscallGroupsGetter for #camel_case_modified_args_type {
462 #[inline(always)]
463 fn syscall_groups(&self) -> ::enumflags2::BitFlags<#crate_token::SyscallGroups> {
464 use ::enumflags2::BitFlag;
465 {
466 #groups
467 }.into()
468 }
469 }
470
471 #[cfg(any(#(target_arch = #arch_names),*))]
472 impl From<#camel_case_modified_args_type> for #crate_token::SyscallModifiedArgs {
473 fn from(args: #camel_case_modified_args_type) -> Self {
474 #crate_token::SyscallModifiedArgs::#camel_case_ident(args)
475 }
476 }
477
478 },
479 name: camel_case_ident,
480 args_struct_type: camel_case_args_type,
481 raw_args_struct_type: camel_case_raw_args_type,
482 modified_args_struct_type: camel_case_modified_args_type,
483 archs: arch_names.clone(),
484 syscall_const_name,
485 }
486}
487
488#[proc_macro]
489pub fn gen_syscalls(input: TokenStream) -> TokenStream {
490 let input = parse_macro_input!(input with Punctuated::<SyscallEntry, syn::Token![,]>::parse_terminated);
491 let mut arg_structs = vec![];
492 let mut raw_arg_structs = vec![];
493 let mut modified_arg_structs = vec![];
494 let mut names = vec![];
495 let mut raw_arg_struct_types = vec![];
496 let mut arg_struct_types = vec![];
497 let mut modified_arg_struct_types = vec![];
498 let mut supported_archs = vec![];
499 let mut syscall_numbers = vec![];
500 let crate_token = get_crate("ptrace-syscalls");
501 let mut syscall_names_dedup = vec![];
502 let mut supported_archs_dedup = vec![];
503 let mut syscall_consts = vec![];
504 for syscall in &input {
505 let GenSyscallArgsStructResult {
506 args_struct,
507 name,
508 args_struct_type,
509 archs,
510 syscall_number,
511 raw_args_struct,
512 raw_args_struct_type,
513 modified_args_struct,
514 modified_args_struct_type,
515 syscall_const_name,
516 } = gen_syscall_args_struct(syscall, crate_token.clone());
517 arg_structs.push(args_struct);
518 raw_arg_structs.push(raw_args_struct);
519 modified_arg_structs.push(modified_args_struct);
520 arg_struct_types.push(args_struct_type);
521 raw_arg_struct_types.push(raw_args_struct_type);
522 modified_arg_struct_types.push(modified_args_struct_type);
523 names.push(name.clone());
524 supported_archs.push(archs.clone());
525 syscall_numbers.push(syscall_number.clone());
526 syscall_consts.push(syscall_const_name);
527 if syscall_names_dedup.last() != Some(&syscall.name) {
528 syscall_names_dedup.push(syscall.name.clone());
529 supported_archs_dedup.push(archs.clone());
530 } else {
531 supported_archs_dedup.last_mut().unwrap().extend(archs);
532 }
533 }
534 TokenStream::from(quote::quote! {
535 #(#raw_arg_structs)*
536 #(#arg_structs)*
537 #(#modified_arg_structs)*
538 #[non_exhaustive]
539 #[derive(Debug, Clone, Copy, PartialEq)]
540 pub enum SyscallRawArgs {
541 #(
542 #[cfg(any(#(target_arch = #supported_archs),*))]
543 #names(#raw_arg_struct_types),
544 )*
545 Unknown(#crate_token::UnknownArgs),
546 }
547
548 #[non_exhaustive]
549 #[derive(Debug, Clone, PartialEq)]
550 pub enum SyscallArgs {
551 #(
552 #[cfg(any(#(target_arch = #supported_archs),*))]
553 #names(#arg_struct_types),
554 )*
555 Unknown(#crate_token::UnknownArgs),
556 }
557
558 #[non_exhaustive]
559 #[derive(Debug, Clone, PartialEq)]
560 pub enum SyscallModifiedArgs {
561 #(
562 #[cfg(any(#(target_arch = #supported_archs),*))]
563 #names(#modified_arg_struct_types),
564 )*
565 Unknown(#crate_token::UnknownArgs),
566 }
567
568 impl #crate_token::SyscallNumber for SyscallRawArgs {
569 #[inline(always)]
570 fn syscall_number(&self) -> isize {
571 match self {
572 #(
573 #[cfg(any(#(target_arch = #supported_archs),*))]
574 Self::#names(args) => args.syscall_number(),
575 )*
576 Self::Unknown(args) => args.syscall_number(),
577 }
578 }
579 }
580
581 impl #crate_token::SyscallGroupsGetter for SyscallRawArgs {
582 #[inline(always)]
583 fn syscall_groups(&self) -> ::enumflags2::BitFlags<#crate_token::SyscallGroups> {
584 match self {
585 #(
586 #[cfg(any(#(target_arch = #supported_archs),*))]
587 Self::#names(args) => args.syscall_groups(),
588 )*
589 Self::Unknown(args) => args.syscall_groups(),
590 }
591 }
592 }
593
594 impl #crate_token::SyscallNumber for SyscallArgs {
595 #[inline(always)]
596 fn syscall_number(&self) -> isize {
597 match self {
598 #(
599 #[cfg(any(#(target_arch = #supported_archs),*))]
600 Self::#names(args) => args.syscall_number(),
601 )*
602 Self::Unknown(args) => args.syscall_number(),
603 }
604 }
605 }
606
607 impl #crate_token::SyscallGroupsGetter for SyscallArgs {
608 #[inline(always)]
609 fn syscall_groups(&self) -> ::enumflags2::BitFlags<#crate_token::SyscallGroups> {
610 match self {
611 #(
612 #[cfg(any(#(target_arch = #supported_archs),*))]
613 Self::#names(args) => args.syscall_groups(),
614 )*
615 Self::Unknown(args) => args.syscall_groups(),
616 }
617 }
618 }
619
620 impl SyscallRawArgs {
621 fn from_regs(regs: &#crate_token::arch::PtraceRegisters) -> Self {
622 use #crate_token::arch::syscall_no_from_regs;
623 match syscall_no_from_regs!(regs) as isize {
624 #(
625 #[cfg(any(#(target_arch = #supported_archs),*))]
626 #syscall_numbers => {
627 Self::#names(#raw_arg_struct_types::from_regs(regs))
628 },
629 )*
630 _ => {
631 Self::Unknown(UnknownArgs::from_regs(regs))
632 }
633 }
634 }
635 }
636
637 impl SyscallStopInspect for SyscallRawArgs {
638 type Args = SyscallArgs;
639 type Result = SyscallModifiedArgs;
640
641 fn inspect_sysenter(self, inspectee_pid: Pid) -> Self::Args {
642 match self {
643 #(
644 #[cfg(any(#(target_arch = #supported_archs),*))]
645 Self::#names(raw_args) => {
646 SyscallArgs::#names(raw_args.inspect_sysenter(inspectee_pid))
647 },
648 )*
649 Self::Unknown(unknown) => {
650 SyscallArgs::Unknown(unknown)
651 }
652 }
653 }
654
655 fn inspect_sysexit(self, inspectee_pid: Pid, regs: &PtraceRegisters) -> Self::Result {
656 match self {
657 #(
658 #[cfg(any(#(target_arch = #supported_archs),*))]
659 Self::#names(raw_args) => {
660 SyscallModifiedArgs::#names(raw_args.inspect_sysexit(inspectee_pid, regs))
661 },
662 )*
663 Self::Unknown(unknown) => {
664 SyscallModifiedArgs::Unknown(unknown)
665 }
666 }
667 }
668 }
669
670 })
709}
710
711fn get_crate(name: &str) -> proc_macro2::TokenStream {
712 let found_crate = crate_name(name).unwrap_or_else(|_| panic!("`{}` not found in `Cargo.toml`", name));
713
714 match found_crate {
715 FoundCrate::Itself => quote!(crate),
716 FoundCrate::Name(name) => {
717 let ident = format_ident!("{}", &name);
718 quote!( #ident )
719 }
720 }
721}
722
723fn wrap_syscall_arg_type(ty: &Type, span: Span) -> (proc_macro2::TokenStream, bool) {
725 match ty {
726 Type::Array(ty) => {
727 let element_ty = &ty.elem;
728 (quote_spanned!(span =>Result<#ty, InspectError<Vec<#element_ty>>>), true)
729 }
730 Type::Path(ty) => {
731 assert_eq!(ty.path.segments.len(), 1);
732 let ty = &ty.path.segments[0];
733 let ty_str = ty.to_token_stream().to_string();
734 match ty_str.as_str() {
735 "Unit" => (quote_spanned!(span => ()), false),
736 "RawFd" | "socklen_t" | "c_int" | "c_uint" | "c_ulong" | "c_long" | "i16" | "i32" | "i64" | "u64" | "usize"
738 | "isize" | "size_t" | "key_serial_t" | "AddressType" | "mode_t" | "uid_t" | "pid_t" | "gid_t" | "off_t"
739 | "u32" | "clockid_t" | "id_t" | "key_t" | "mqd_t" | "aio_context_t" | "dev_t" | "nfds_t" | "loff_t"
740 | "qid_t" | "idtype_t" | "time_t" | "timer_t" => (ty.to_token_stream(), false),
741 "sockaddr"
743 | "CString"
744 | "PathBuf"
745 | "iovec"
746 | "timex"
747 | "cap_user_header"
748 | "cap_user_data"
749 | "timespec"
750 | "clone_args"
751 | "epoll_event"
752 | "sigset_t"
753 | "stat"
754 | "statfs"
755 | "futex_waitv"
756 | "user_desc"
757 | "itimerval"
758 | "rlimit"
759 | "rusage"
760 | "timeval"
761 | "__aio_sigset"
762 | "timezone"
763 | "iocb"
764 | "io_event"
765 | "io_uring_params"
766 | "open_how"
767 | "landlock_ruleset_attr"
768 | "mq_attr"
769 | "sigevent"
770 | "msqid_ds"
771 | "pollfd"
772 | "__mount_arg"
773 | "msghdr"
774 | "riscv_hwprobe"
775 | "siginfo_t"
776 | "sched_attr"
777 | "sched_param"
778 | "stack_t"
779 | "mnt_id_req"
780 | "statx"
781 | "sysinfo"
782 | "itimerspec"
783 | "tms"
784 | "utsname"
785 | "ustat"
786 | "shmid_ds"
787 | "cachestat"
788 | "cachestat_range" => (quote_spanned!(span => InspectResult<#ty>), true),
789 _ => {
790 if ty.ident == "Option" {
791 let PathArguments::AngleBracketed(arg) = &ty.arguments else {
792 panic!("Unsupported syscall arg type: {:?}", ty_str);
793 };
794 let argstr = arg.args.to_token_stream().to_string();
795 match argstr.as_str() {
796 "PathBuf" | "timespec" | "Vec < CString >" | "CString" | "Vec < c_ulong >" | "Vec < c_uint >"
797 | "Vec < gid_t >" | "timezone" | "mq_attr" | "siginfo_t" | "sigset_t" | "iovec" | "rlimit64"
798 | "fd_set" | "sockaddr" | "sigaction" | "timeval" | "itimerval" | "stack_t" | "timer_t" | "time_t"
799 | "sigevent" | "itimerspec" | "utimbuf" | "rusage" => (quote_spanned!(span => InspectResult<#ty>), true),
800 "[timespec; 2]" | "[timeval; 2]" | "[timespec ; 2]" | "[timeval ; 2]" => {
801 let GenericArgument::Type(inner) = arg.args.first().unwrap() else {
802 panic!("Unsupported inner syscall arg type: {:?}", argstr);
803 };
804 let Type::Array(inner) = inner else {
805 panic!("Unsupported inner syscall arg type: {:?}", argstr)
806 };
807 let element_ty = &inner.elem;
808 (quote_spanned!(span => Result<#ty, InspectError<Vec<#element_ty>>>), true)
809 }
810 _ => panic!("Unsupported inner syscall arg type: {:?}", argstr),
811 }
812 } else if ty.ident == "Vec" {
813 let PathArguments::AngleBracketed(arg) = &ty.arguments else {
814 panic!("Unsupported inner syscall arg type: {:?}", ty_str);
815 };
816 let arg = arg.args.to_token_stream().to_string();
817 match arg.as_str() {
818 "c_int" | "u8" | "CString" | "epoll_event" | "futex_waitv" | "c_ulong" | "linux_dirent" | "io_event"
819 | "linux_dirent64" | "gid_t" | "AddressType" | "kexec_segment" | "c_uchar" | "u64" | "mount_attr"
820 | "pollfd" | "iovec" | "riscv_hwprobe" | "mmsghdr" | "sembuf" => {
821 (quote_spanned!(span => InspectResult<#ty>), true)
822 }
823 _ => panic!("Unsupported inner syscall arg type: {:?}", arg),
824 }
825 } else if ty.ident == "InspectResult" {
826 (quote_spanned!(span => #ty), true)
827 } else if ty.ident == "Arc" {
828 let PathArguments::AngleBracketed(arg) = &ty.arguments else {
829 panic!("Unsupported inner syscall arg type: {:?}", ty_str);
830 };
831 let arg = arg.args.to_token_stream().to_string();
832 match arg.as_str() {
833 "rseq" | "statmount" | "msgbuf" | "file_handle" | "xattr_args" | "mount_attr" => {
834 (quote_spanned!(span => InspectResult<#ty>), true)
835 }
836 _ => panic!("Unsupported inner syscall arg type: {:?}", arg),
837 }
838 } else {
839 panic!("Unsupported syscall arg type: {:?}", ty_str);
840 }
841 }
842 }
843 }
844 _ => panic!("Multi segment path is not supported here"),
845 }
846}