kprobe.rs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  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 fn_vis = &self.item.vis;
  56. let fn_name = self.item.sig.ident.clone();
  57. let item = &self.item;
  58. Ok(quote! {
  59. #[no_mangle]
  60. #[link_section = #section_name]
  61. #fn_vis fn #fn_name(ctx: *mut ::core::ffi::c_void) -> u32 {
  62. let _ = #fn_name(::aya_bpf::programs::ProbeContext::new(ctx));
  63. return 0;
  64. #item
  65. }
  66. })
  67. }
  68. }
  69. #[cfg(test)]
  70. mod tests {
  71. use syn::parse_quote;
  72. use super::*;
  73. #[test]
  74. fn test_kprobe() {
  75. let kprobe = KProbe::parse(
  76. KProbeKind::KProbe,
  77. parse_quote! {},
  78. parse_quote! {
  79. fn foo(ctx: ProbeContext) -> u32 {
  80. 0
  81. }
  82. },
  83. )
  84. .unwrap();
  85. assert_eq!(
  86. kprobe.expand().unwrap().to_string(),
  87. quote! {
  88. #[no_mangle]
  89. #[link_section = "kprobe"]
  90. fn foo(ctx: *mut ::core::ffi::c_void) -> u32 {
  91. let _ = foo(::aya_bpf::programs::ProbeContext::new(ctx));
  92. return 0;
  93. fn foo(ctx: ProbeContext) -> u32 {
  94. 0
  95. }
  96. }
  97. }
  98. .to_string()
  99. );
  100. }
  101. #[test]
  102. fn test_kprobe_with_function() {
  103. let kprobe = KProbe::parse(
  104. KProbeKind::KProbe,
  105. parse_quote! {
  106. function = "fib_lookup"
  107. },
  108. parse_quote! {
  109. fn foo(ctx: ProbeContext) -> u32 {
  110. 0
  111. }
  112. },
  113. )
  114. .unwrap();
  115. assert_eq!(
  116. kprobe.expand().unwrap().to_string(),
  117. quote! {
  118. #[no_mangle]
  119. #[link_section = "kprobe/fib_lookup"]
  120. fn foo(ctx: *mut ::core::ffi::c_void) -> u32 {
  121. let _ = foo(::aya_bpf::programs::ProbeContext::new(ctx));
  122. return 0;
  123. fn foo(ctx: ProbeContext) -> u32 {
  124. 0
  125. }
  126. }
  127. }
  128. .to_string()
  129. );
  130. }
  131. #[test]
  132. fn test_kprobe_with_function_and_offset() {
  133. let kprobe = KProbe::parse(
  134. KProbeKind::KProbe,
  135. parse_quote! {
  136. function = "fib_lookup",
  137. offset = "10"
  138. },
  139. parse_quote! {
  140. fn foo(ctx: ProbeContext) -> u32 {
  141. 0
  142. }
  143. },
  144. )
  145. .unwrap();
  146. assert_eq!(
  147. kprobe.expand().unwrap().to_string(),
  148. quote! {
  149. #[no_mangle]
  150. #[link_section = "kprobe/fib_lookup+10"]
  151. fn foo(ctx: *mut ::core::ffi::c_void) -> u32 {
  152. let _ = foo(::aya_bpf::programs::ProbeContext::new(ctx));
  153. return 0;
  154. fn foo(ctx: ProbeContext) -> u32 {
  155. 0
  156. }
  157. }
  158. }
  159. .to_string()
  160. );
  161. }
  162. #[test]
  163. fn test_kretprobe() {
  164. let kprobe = KProbe::parse(
  165. KProbeKind::KRetProbe,
  166. parse_quote! {},
  167. parse_quote! {
  168. fn foo(ctx: ProbeContext) -> u32 {
  169. 0
  170. }
  171. },
  172. )
  173. .unwrap();
  174. assert_eq!(
  175. kprobe.expand().unwrap().to_string(),
  176. quote! {
  177. #[no_mangle]
  178. #[link_section = "kretprobe"]
  179. fn foo(ctx: *mut ::core::ffi::c_void) -> u32 {
  180. let _ = foo(::aya_bpf::programs::ProbeContext::new(ctx));
  181. return 0;
  182. fn foo(ctx: ProbeContext) -> u32 {
  183. 0
  184. }
  185. }
  186. }
  187. .to_string()
  188. );
  189. }
  190. }