uprobe.rs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  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_bool_arg, pop_string_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. sleepable: bool,
  29. }
  30. impl UProbe {
  31. pub(crate) fn parse(kind: UProbeKind, attrs: TokenStream, item: TokenStream) -> Result<UProbe> {
  32. let item = syn::parse2(item)?;
  33. let mut args = syn::parse2(attrs)?;
  34. let path = pop_string_arg(&mut args, "path");
  35. let function = pop_string_arg(&mut args, "function");
  36. let offset = pop_string_arg(&mut args, "offset").map(|v| v.parse::<u64>().unwrap());
  37. let sleepable = pop_bool_arg(&mut args, "sleepable");
  38. err_on_unknown_args(&args)?;
  39. Ok(UProbe {
  40. kind,
  41. item,
  42. path,
  43. function,
  44. offset,
  45. sleepable,
  46. })
  47. }
  48. pub(crate) fn expand(&self) -> Result<TokenStream> {
  49. let prefix = if self.sleepable {
  50. format!("{}.s", self.kind)
  51. } else {
  52. format!("{}", self.kind)
  53. };
  54. let section_name: Cow<'_, _> = if self.path.is_some() && self.offset.is_some() {
  55. if self.function.is_none() {
  56. abort!(self.item.sig.ident, "expected `function` attribute");
  57. }
  58. let mut path = self.path.as_ref().unwrap().clone();
  59. if path.starts_with('/') {
  60. path.remove(0);
  61. }
  62. format!(
  63. "{}/{}:{}+{}",
  64. prefix,
  65. path,
  66. self.function.as_ref().unwrap(),
  67. self.offset.unwrap()
  68. )
  69. .into()
  70. } else if self.path.is_some() {
  71. if self.function.is_none() {
  72. abort!(self.item.sig.ident, "expected `function` attribute");
  73. }
  74. let mut path = self.path.as_ref().unwrap().clone();
  75. if path.starts_with('/') {
  76. path.remove(0);
  77. }
  78. format!("{}/{}:{}", prefix, path, self.function.as_ref().unwrap()).into()
  79. } else {
  80. prefix.to_string().into()
  81. };
  82. let fn_vis = &self.item.vis;
  83. let fn_name = self.item.sig.ident.clone();
  84. let item = &self.item;
  85. Ok(quote! {
  86. #[no_mangle]
  87. #[link_section = #section_name]
  88. #fn_vis fn #fn_name(ctx: *mut ::core::ffi::c_void) -> u32 {
  89. let _ = #fn_name(::aya_bpf::programs::ProbeContext::new(ctx));
  90. return 0;
  91. #item
  92. }
  93. })
  94. }
  95. }
  96. #[cfg(test)]
  97. mod tests {
  98. use syn::parse_quote;
  99. use super::*;
  100. #[test]
  101. fn uprobe() {
  102. let uprobe = UProbe::parse(
  103. UProbeKind::UProbe,
  104. parse_quote! {},
  105. parse_quote! {
  106. fn foo(ctx: ProbeContext) -> u32 {
  107. 0
  108. }
  109. },
  110. )
  111. .unwrap();
  112. assert_eq!(
  113. uprobe.expand().unwrap().to_string(),
  114. quote! {
  115. #[no_mangle]
  116. #[link_section = "uprobe"]
  117. fn foo(ctx: *mut ::core::ffi::c_void) -> u32 {
  118. let _ = foo(::aya_bpf::programs::ProbeContext::new(ctx));
  119. return 0;
  120. fn foo(ctx: ProbeContext) -> u32 {
  121. 0
  122. }
  123. }
  124. }
  125. .to_string()
  126. );
  127. }
  128. #[test]
  129. fn uprobe_sleepable() {
  130. let uprobe = UProbe::parse(
  131. UProbeKind::UProbe,
  132. parse_quote! {sleepable},
  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.s"]
  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 uprobe_with_path() {
  158. let uprobe = UProbe::parse(
  159. UProbeKind::UProbe,
  160. parse_quote! {
  161. path = "/self/proc/exe",
  162. function = "trigger_uprobe"
  163. },
  164. parse_quote! {
  165. fn foo(ctx: ProbeContext) -> u32 {
  166. 0
  167. }
  168. },
  169. )
  170. .unwrap();
  171. assert_eq!(
  172. uprobe.expand().unwrap().to_string(),
  173. quote! {
  174. #[no_mangle]
  175. #[link_section = "uprobe/self/proc/exe:trigger_uprobe"]
  176. fn foo(ctx: *mut ::core::ffi::c_void) -> u32 {
  177. let _ = foo(::aya_bpf::programs::ProbeContext::new(ctx));
  178. return 0;
  179. fn foo(ctx: ProbeContext) -> u32 {
  180. 0
  181. }
  182. }
  183. }
  184. .to_string()
  185. );
  186. }
  187. #[test]
  188. fn test_uprobe_with_path_and_offset() {
  189. let uprobe = UProbe::parse(
  190. UProbeKind::UProbe,
  191. parse_quote! {
  192. path = "/self/proc/exe", function = "foo", offset = "123"
  193. },
  194. parse_quote! {
  195. fn foo(ctx: ProbeContext) -> u32 {
  196. 0
  197. }
  198. },
  199. )
  200. .unwrap();
  201. assert_eq!(
  202. uprobe.expand().unwrap().to_string(),
  203. quote! {
  204. #[no_mangle]
  205. #[link_section = "uprobe/self/proc/exe:foo+123"]
  206. fn foo(ctx: *mut ::core::ffi::c_void) -> u32 {
  207. let _ = foo(::aya_bpf::programs::ProbeContext::new(ctx));
  208. return 0;
  209. fn foo(ctx: ProbeContext) -> u32 {
  210. 0
  211. }
  212. }
  213. }
  214. .to_string()
  215. );
  216. }
  217. #[test]
  218. fn test_uretprobe() {
  219. let uprobe = UProbe::parse(
  220. UProbeKind::URetProbe,
  221. parse_quote! {},
  222. parse_quote! {
  223. fn foo(ctx: ProbeContext) -> u32 {
  224. 0
  225. }
  226. },
  227. )
  228. .unwrap();
  229. assert_eq!(
  230. uprobe.expand().unwrap().to_string(),
  231. quote! {
  232. #[no_mangle]
  233. #[link_section = "uretprobe"]
  234. fn foo(ctx: *mut ::core::ffi::c_void) -> u32 {
  235. let _ = foo(::aya_bpf::programs::ProbeContext::new(ctx));
  236. return 0;
  237. fn foo(ctx: ProbeContext) -> u32 {
  238. 0
  239. }
  240. }
  241. }
  242. .to_string()
  243. );
  244. }
  245. }