uprobe.rs 6.4 KB

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