fexit.rs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. use std::borrow::Cow;
  2. use proc_macro2::TokenStream;
  3. use quote::quote;
  4. use syn::{ItemFn, Result};
  5. use crate::args::{err_on_unknown_args, pop_bool_arg, pop_string_arg};
  6. pub(crate) struct FExit {
  7. item: ItemFn,
  8. function: Option<String>,
  9. sleepable: bool,
  10. }
  11. impl FExit {
  12. pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<Self> {
  13. let item = syn::parse2(item)?;
  14. let mut args = syn::parse2(attrs)?;
  15. let function = pop_string_arg(&mut args, "function");
  16. let sleepable = pop_bool_arg(&mut args, "sleepable");
  17. err_on_unknown_args(&args)?;
  18. Ok(Self {
  19. item,
  20. function,
  21. sleepable,
  22. })
  23. }
  24. pub(crate) fn expand(&self) -> TokenStream {
  25. let Self {
  26. item,
  27. function,
  28. sleepable,
  29. } = self;
  30. let ItemFn {
  31. attrs: _,
  32. vis,
  33. sig,
  34. block: _,
  35. } = item;
  36. let section_prefix = if *sleepable { "fexit.s" } else { "fexit" };
  37. let section_name: Cow<'_, _> = if let Some(function) = function {
  38. format!("{}/{}", section_prefix, function).into()
  39. } else {
  40. section_prefix.into()
  41. };
  42. let fn_name = &sig.ident;
  43. quote! {
  44. #[no_mangle]
  45. #[link_section = #section_name]
  46. #vis fn #fn_name(ctx: *mut ::core::ffi::c_void) -> i32 {
  47. let _ = #fn_name(::aya_ebpf::programs::FExitContext::new(ctx));
  48. return 0;
  49. #item
  50. }
  51. }
  52. }
  53. }
  54. #[cfg(test)]
  55. mod tests {
  56. use syn::parse_quote;
  57. use super::*;
  58. #[test]
  59. fn test_fexit() {
  60. let prog = FExit::parse(
  61. parse_quote! {},
  62. parse_quote! {
  63. fn sys_clone(ctx: &mut FExitContext) -> i32 {
  64. 0
  65. }
  66. },
  67. )
  68. .unwrap();
  69. let expanded = prog.expand();
  70. let expected = quote! {
  71. #[no_mangle]
  72. #[link_section = "fexit"]
  73. fn sys_clone(ctx: *mut ::core::ffi::c_void) -> i32 {
  74. let _ = sys_clone(::aya_ebpf::programs::FExitContext::new(ctx));
  75. return 0;
  76. fn sys_clone(ctx: &mut FExitContext) -> i32 {
  77. 0
  78. }
  79. }
  80. };
  81. assert_eq!(expected.to_string(), expanded.to_string());
  82. }
  83. #[test]
  84. fn test_fexit_with_function() {
  85. let prog = FExit::parse(
  86. parse_quote! {
  87. function = "sys_clone"
  88. },
  89. parse_quote! {
  90. fn sys_clone(ctx: &mut FExitContext) -> i32 {
  91. 0
  92. }
  93. },
  94. )
  95. .unwrap();
  96. let expanded = prog.expand();
  97. let expected = quote! {
  98. #[no_mangle]
  99. #[link_section = "fexit/sys_clone"]
  100. fn sys_clone(ctx: *mut ::core::ffi::c_void) -> i32 {
  101. let _ = sys_clone(::aya_ebpf::programs::FExitContext::new(ctx));
  102. return 0;
  103. fn sys_clone(ctx: &mut FExitContext) -> i32 {
  104. 0
  105. }
  106. }
  107. };
  108. assert_eq!(expected.to_string(), expanded.to_string());
  109. }
  110. #[test]
  111. fn test_fexit_sleepable() {
  112. let prog = FExit::parse(
  113. parse_quote! {
  114. function = "sys_clone", sleepable
  115. },
  116. parse_quote! {
  117. fn sys_clone(ctx: &mut FExitContext) -> i32 {
  118. 0
  119. }
  120. },
  121. )
  122. .unwrap();
  123. let expanded = prog.expand();
  124. let expected = quote! {
  125. #[no_mangle]
  126. #[link_section = "fexit.s/sys_clone"]
  127. fn sys_clone(ctx: *mut ::core::ffi::c_void) -> i32 {
  128. let _ = sys_clone(::aya_ebpf::programs::FExitContext::new(ctx));
  129. return 0;
  130. fn sys_clone(ctx: &mut FExitContext) -> i32 {
  131. 0
  132. }
  133. }
  134. };
  135. assert_eq!(expected.to_string(), expanded.to_string());
  136. }
  137. }