@ -5,7 +5,7 @@ use proc_macro_error::abort;
use quote ::quote ;
use quote ::quote ;
use syn ::{ ItemFn , Result } ;
use syn ::{ ItemFn , Result } ;
use crate ::args ::{ err_on_unknown_args , pop_ arg} ;
use crate ::args ::{ err_on_unknown_args , pop_ bool_arg, pop_string_ arg} ;
#[ allow(clippy::enum_variant_names) ]
#[ allow(clippy::enum_variant_names) ]
#[ derive(Debug, Copy, Clone) ]
#[ derive(Debug, Copy, Clone) ]
@ -30,32 +30,34 @@ pub(crate) struct UProbe {
function : Option < String > ,
function : Option < String > ,
offset : Option < u64 > ,
offset : Option < u64 > ,
item : ItemFn ,
item : ItemFn ,
sleepable : bool ,
}
}
impl UProbe {
impl UProbe {
pub ( crate ) fn parse ( kind : UProbeKind , attrs : TokenStream , item : TokenStream ) -> Result < UProbe > {
pub ( crate ) fn parse ( kind : UProbeKind , attrs : TokenStream , item : TokenStream ) -> Result < UProbe > {
let mut path = None ;
let mut function = None ;
let mut offset = None ;
if ! attrs . is_empty ( ) {
let mut args = syn ::parse2 ( attrs ) ? ;
path = pop_arg ( & mut args , "path" ) ;
function = pop_arg ( & mut args , "function" ) ;
offset = pop_arg ( & mut args , "offset" ) . map ( | v | v . parse ::< u64 > ( ) . unwrap ( ) ) ;
err_on_unknown_args ( & args ) ? ;
}
let item = syn ::parse2 ( item ) ? ;
let item = syn ::parse2 ( item ) ? ;
let mut args = syn ::parse2 ( attrs ) ? ;
let path = pop_string_arg ( & mut args , "path" ) ;
let function = pop_string_arg ( & mut args , "function" ) ;
let offset = pop_string_arg ( & mut args , "offset" ) . map ( | v | v . parse ::< u64 > ( ) . unwrap ( ) ) ;
let sleepable = pop_bool_arg ( & mut args , "sleepable" ) ;
err_on_unknown_args ( & args ) ? ;
Ok ( UProbe {
Ok ( UProbe {
kind ,
kind ,
item ,
item ,
path ,
path ,
function ,
function ,
offset ,
offset ,
sleepable ,
} )
} )
}
}
pub ( crate ) fn expand ( & self ) -> Result < TokenStream > {
pub ( crate ) fn expand ( & self ) -> Result < TokenStream > {
let prefix = if self . sleepable {
format! ( "{}.s" , self . kind )
} else {
format! ( "{}" , self . kind )
} ;
let section_name : Cow < ' _ , _ > = if self . path . is_some ( ) & & self . offset . is_some ( ) {
let section_name : Cow < ' _ , _ > = if self . path . is_some ( ) & & self . offset . is_some ( ) {
if self . function . is_none ( ) {
if self . function . is_none ( ) {
abort ! ( self . item . sig . ident , "expected `function` attribute" ) ;
abort ! ( self . item . sig . ident , "expected `function` attribute" ) ;
@ -66,7 +68,7 @@ impl UProbe {
}
}
format! (
format! (
"{}/{}:{}+{}" ,
"{}/{}:{}+{}" ,
self . kind ,
prefix ,
path ,
path ,
self . function . as_ref ( ) . unwrap ( ) ,
self . function . as_ref ( ) . unwrap ( ) ,
self . offset . unwrap ( )
self . offset . unwrap ( )
@ -80,9 +82,9 @@ impl UProbe {
if path . starts_with ( '/' ) {
if path . starts_with ( '/' ) {
path . remove ( 0 ) ;
path . remove ( 0 ) ;
}
}
format! ( "{}/{}:{}" , self . kind , path , self . function . as_ref ( ) . unwrap ( ) ) . into ( )
format! ( "{}/{}:{}" , prefix , path , self . function . as_ref ( ) . unwrap ( ) ) . into ( )
} else {
} else {
format! ( "{}" , self . kind ) . into ( )
prefix . to_string ( ) . into ( )
} ;
} ;
let fn_vis = & self . item . vis ;
let fn_vis = & self . item . vis ;
let fn_name = self . item . sig . ident . clone ( ) ;
let fn_name = self . item . sig . ident . clone ( ) ;
@ -135,6 +137,36 @@ mod tests {
) ;
) ;
}
}
#[ test ]
fn uprobe_sleepable ( ) {
let uprobe = UProbe ::parse (
UProbeKind ::UProbe ,
parse_quote ! { sleepable } ,
parse_quote ! {
fn foo ( ctx : ProbeContext ) -> u32 {
0
}
} ,
)
. unwrap ( ) ;
assert_eq! (
uprobe . expand ( ) . unwrap ( ) . to_string ( ) ,
quote ! {
#[ no_mangle ]
#[ link_section = " uprobe.s " ]
fn foo ( ctx : * mut ::core ::ffi ::c_void ) -> u32 {
let _ = foo ( ::aya_bpf ::programs ::ProbeContext ::new ( ctx ) ) ;
return 0 ;
fn foo ( ctx : ProbeContext ) -> u32 {
0
}
}
}
. to_string ( )
) ;
}
#[ test ]
#[ test ]
fn uprobe_with_path ( ) {
fn uprobe_with_path ( ) {
let uprobe = UProbe ::parse (
let uprobe = UProbe ::parse (