4
0

kprobe.rs 5.9 KB

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