kprobe.rs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  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_string_arg};
  6. #[allow(clippy::enum_variant_names)]
  7. #[derive(Debug, Copy, Clone)]
  8. pub(crate) enum KProbeKind {
  9. KProbe,
  10. KRetProbe,
  11. }
  12. impl std::fmt::Display for KProbeKind {
  13. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  14. use KProbeKind::*;
  15. match self {
  16. KProbe => write!(f, "kprobe"),
  17. KRetProbe => write!(f, "kretprobe"),
  18. }
  19. }
  20. }
  21. pub(crate) struct KProbe {
  22. kind: KProbeKind,
  23. function: Option<String>,
  24. offset: Option<u64>,
  25. item: ItemFn,
  26. }
  27. impl KProbe {
  28. pub(crate) fn parse(kind: KProbeKind, attrs: TokenStream, item: TokenStream) -> Result<KProbe> {
  29. let item = syn::parse2(item)?;
  30. let mut args = syn::parse2(attrs)?;
  31. let function = pop_string_arg(&mut args, "function");
  32. let offset = pop_string_arg(&mut args, "offset").map(|v| v.parse::<u64>().unwrap());
  33. err_on_unknown_args(&args)?;
  34. Ok(KProbe {
  35. kind,
  36. item,
  37. function,
  38. offset,
  39. })
  40. }
  41. pub(crate) fn expand(&self) -> Result<TokenStream> {
  42. let section_name: Cow<'_, _> = if self.function.is_some() && self.offset.is_some() {
  43. format!(
  44. "{}/{}+{}",
  45. self.kind,
  46. self.function.as_ref().unwrap(),
  47. self.offset.unwrap()
  48. )
  49. .into()
  50. } else if self.function.is_some() {
  51. format!("{}/{}", self.kind, self.function.as_ref().unwrap()).into()
  52. } else {
  53. format!("{}", self.kind).into()
  54. };
  55. let probe_type = if section_name.as_ref().starts_with("kprobe") {
  56. quote! { ProbeContext }
  57. } else {
  58. quote! { RetProbeContext }
  59. };
  60. let fn_vis = &self.item.vis;
  61. let fn_name = self.item.sig.ident.clone();
  62. let item = &self.item;
  63. Ok(quote! {
  64. #[no_mangle]
  65. #[link_section = #section_name]
  66. #fn_vis fn #fn_name(ctx: *mut ::core::ffi::c_void) -> u32 {
  67. let _ = #fn_name(::aya_ebpf::programs::#probe_type::new(ctx));
  68. return 0;
  69. #item
  70. }
  71. })
  72. }
  73. }
  74. #[cfg(test)]
  75. mod tests {
  76. use syn::parse_quote;
  77. use super::*;
  78. #[test]
  79. fn test_kprobe() {
  80. let kprobe = KProbe::parse(
  81. KProbeKind::KProbe,
  82. parse_quote! {},
  83. parse_quote! {
  84. fn foo(ctx: ProbeContext) -> u32 {
  85. 0
  86. }
  87. },
  88. )
  89. .unwrap();
  90. assert_eq!(
  91. kprobe.expand().unwrap().to_string(),
  92. quote! {
  93. #[no_mangle]
  94. #[link_section = "kprobe"]
  95. fn foo(ctx: *mut ::core::ffi::c_void) -> u32 {
  96. let _ = foo(::aya_ebpf::programs::ProbeContext::new(ctx));
  97. return 0;
  98. fn foo(ctx: ProbeContext) -> u32 {
  99. 0
  100. }
  101. }
  102. }
  103. .to_string()
  104. );
  105. }
  106. #[test]
  107. fn test_kprobe_with_function() {
  108. let kprobe = KProbe::parse(
  109. KProbeKind::KProbe,
  110. parse_quote! {
  111. function = "fib_lookup"
  112. },
  113. parse_quote! {
  114. fn foo(ctx: ProbeContext) -> u32 {
  115. 0
  116. }
  117. },
  118. )
  119. .unwrap();
  120. assert_eq!(
  121. kprobe.expand().unwrap().to_string(),
  122. quote! {
  123. #[no_mangle]
  124. #[link_section = "kprobe/fib_lookup"]
  125. fn foo(ctx: *mut ::core::ffi::c_void) -> u32 {
  126. let _ = foo(::aya_ebpf::programs::ProbeContext::new(ctx));
  127. return 0;
  128. fn foo(ctx: ProbeContext) -> u32 {
  129. 0
  130. }
  131. }
  132. }
  133. .to_string()
  134. );
  135. }
  136. #[test]
  137. fn test_kprobe_with_function_and_offset() {
  138. let kprobe = KProbe::parse(
  139. KProbeKind::KProbe,
  140. parse_quote! {
  141. function = "fib_lookup",
  142. offset = "10"
  143. },
  144. parse_quote! {
  145. fn foo(ctx: ProbeContext) -> u32 {
  146. 0
  147. }
  148. },
  149. )
  150. .unwrap();
  151. assert_eq!(
  152. kprobe.expand().unwrap().to_string(),
  153. quote! {
  154. #[no_mangle]
  155. #[link_section = "kprobe/fib_lookup+10"]
  156. fn foo(ctx: *mut ::core::ffi::c_void) -> u32 {
  157. let _ = foo(::aya_ebpf::programs::ProbeContext::new(ctx));
  158. return 0;
  159. fn foo(ctx: ProbeContext) -> u32 {
  160. 0
  161. }
  162. }
  163. }
  164. .to_string()
  165. );
  166. }
  167. #[test]
  168. fn test_kretprobe() {
  169. let kprobe = KProbe::parse(
  170. KProbeKind::KRetProbe,
  171. parse_quote! {},
  172. parse_quote! {
  173. fn foo(ctx: ProbeContext) -> u32 {
  174. 0
  175. }
  176. },
  177. )
  178. .unwrap();
  179. assert_eq!(
  180. kprobe.expand().unwrap().to_string(),
  181. quote! {
  182. #[no_mangle]
  183. #[link_section = "kretprobe"]
  184. fn foo(ctx: *mut ::core::ffi::c_void) -> u32 {
  185. let _ = foo(::aya_ebpf::programs::RetProbeContext::new(ctx));
  186. return 0;
  187. fn foo(ctx: ProbeContext) -> u32 {
  188. 0
  189. }
  190. }
  191. }
  192. .to_string()
  193. );
  194. }
  195. }