args.rs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. use crate::cty::c_void;
  2. // aarch64 uses user_pt_regs instead of pt_regs
  3. #[cfg(not(bpf_target_arch = "aarch64"))]
  4. use crate::bindings::pt_regs;
  5. #[cfg(bpf_target_arch = "aarch64")]
  6. use crate::bindings::user_pt_regs as pt_regs;
  7. /// A trait that indicates a valid type for an argument which can be coerced from a BTF
  8. /// context.
  9. ///
  10. /// Users should not implement this trait.
  11. ///
  12. /// SAFETY: This trait is _only_ safe to implement on primitive types that can fit into
  13. /// a `u64`. For example, integers and raw pointers may be coerced from a BTF context.
  14. pub unsafe trait FromBtfArgument: Sized {
  15. /// Coerces a `T` from the `n`th argument from a BTF context where `n` starts
  16. /// at 0 and increases by 1 for each successive argument.
  17. ///
  18. /// SAFETY: This function is deeply unsafe, as we are reading raw pointers into kernel
  19. /// memory. In particular, the value of `n` must not exceed the number of function
  20. /// arguments. Moreover, `ctx` must be a valid pointer to a BTF context, and `T` must
  21. /// be the right type for the given argument.
  22. unsafe fn from_argument(ctx: *const c_void, n: usize) -> Self;
  23. }
  24. unsafe impl<T> FromBtfArgument for *const T {
  25. unsafe fn from_argument(ctx: *const c_void, n: usize) -> *const T {
  26. // BTF arguments are exposed as an array of `usize` where `usize` can
  27. // either be treated as a pointer or a primitive type
  28. *(ctx as *const usize).add(n) as _
  29. }
  30. }
  31. /// Helper macro to implement [`FromBtfArgument`] for a primitive type.
  32. macro_rules! unsafe_impl_from_btf_argument {
  33. ($type:ident) => {
  34. unsafe impl FromBtfArgument for $type {
  35. unsafe fn from_argument(ctx: *const c_void, n: usize) -> Self {
  36. // BTF arguments are exposed as an array of `usize` where `usize` can
  37. // either be treated as a pointer or a primitive type
  38. *(ctx as *const usize).add(n) as _
  39. }
  40. }
  41. };
  42. }
  43. unsafe_impl_from_btf_argument!(u8);
  44. unsafe_impl_from_btf_argument!(u16);
  45. unsafe_impl_from_btf_argument!(u32);
  46. unsafe_impl_from_btf_argument!(u64);
  47. unsafe_impl_from_btf_argument!(i8);
  48. unsafe_impl_from_btf_argument!(i16);
  49. unsafe_impl_from_btf_argument!(i32);
  50. unsafe_impl_from_btf_argument!(i64);
  51. unsafe_impl_from_btf_argument!(usize);
  52. unsafe_impl_from_btf_argument!(isize);
  53. pub struct PtRegs {
  54. regs: *mut pt_regs,
  55. }
  56. /// A portable wrapper around pt_regs and user_pt_regs.
  57. impl PtRegs {
  58. pub fn new(regs: *mut pt_regs) -> Self {
  59. PtRegs { regs }
  60. }
  61. /// Returns the value of the register used to pass arg `n`.
  62. pub fn arg<T: FromPtRegs>(&self, n: usize) -> Option<T> {
  63. T::from_argument(unsafe { &*self.regs }, n)
  64. }
  65. /// Returns the value of the register used to pass the return value.
  66. pub fn ret<T: FromPtRegs>(&self) -> Option<T> {
  67. T::from_retval(unsafe { &*self.regs })
  68. }
  69. /// Returns a pointer to the wrapped value.
  70. pub fn as_ptr(&self) -> *mut pt_regs {
  71. self.regs
  72. }
  73. }
  74. /// A trait that indicates a valid type for an argument which can be coerced from
  75. /// a pt_regs context.
  76. ///
  77. /// Any implementation of this trait is strictly architecture-specific and depends on the
  78. /// layout of the underlying pt_regs struct and the target processor's calling
  79. /// conventions. Users should not implement this trait.
  80. pub trait FromPtRegs: Sized {
  81. /// Coerces a `T` from the `n`th argument of a pt_regs context where `n` starts
  82. /// at 0 and increases by 1 for each successive argument.
  83. fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self>;
  84. /// Coerces a `T` from the return value of a pt_regs context.
  85. fn from_retval(ctx: &pt_regs) -> Option<Self>;
  86. }
  87. #[cfg(bpf_target_arch = "x86_64")]
  88. impl<T> FromPtRegs for *const T {
  89. fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
  90. match n {
  91. 0 => Some(ctx.rdi as *const _),
  92. 1 => Some(ctx.rsi as *const _),
  93. 2 => Some(ctx.rdx as *const _),
  94. 3 => Some(ctx.rcx as *const _),
  95. 4 => Some(ctx.r8 as *const _),
  96. 5 => Some(ctx.r9 as *const _),
  97. _ => None,
  98. }
  99. }
  100. fn from_retval(ctx: &pt_regs) -> Option<Self> {
  101. Some(ctx.rax as *const _)
  102. }
  103. }
  104. #[cfg(bpf_target_arch = "armv7")]
  105. impl<T> FromPtRegs for *const T {
  106. fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
  107. if n <= 6 {
  108. Some(ctx.uregs.regs[n] as *const _)
  109. } else {
  110. None
  111. }
  112. }
  113. fn from_retval(ctx: &pt_regs) -> Option<Self> {
  114. Some(ctx.uregs.regs[0] as *const _)
  115. }
  116. }
  117. #[cfg(bpf_target_arch = "aarch64")]
  118. impl<T> FromPtRegs for *const T {
  119. fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
  120. if n <= 7 {
  121. Some(ctx.regs.regs[n] as *const _)
  122. } else {
  123. None
  124. }
  125. }
  126. fn from_retval(ctx: &pt_regs) -> Option<Self> {
  127. Some(ctx.regs.regs[0] as *const _)
  128. }
  129. }
  130. #[cfg(bpf_target_arch = "x86_64")]
  131. impl<T> FromPtRegs for *mut T {
  132. fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
  133. match n {
  134. 0 => Some(ctx.rdi as *mut _),
  135. 1 => Some(ctx.rsi as *mut _),
  136. 2 => Some(ctx.rdx as *mut _),
  137. 3 => Some(ctx.rcx as *mut _),
  138. 4 => Some(ctx.r8 as *mut _),
  139. 5 => Some(ctx.r9 as *mut _),
  140. _ => None,
  141. }
  142. }
  143. fn from_retval(ctx: &pt_regs) -> Option<Self> {
  144. Some(ctx.rax as *mut _)
  145. }
  146. }
  147. #[cfg(bpf_target_arch = "armv7")]
  148. impl<T> FromPtRegs for *mut T {
  149. fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
  150. if n <= 6 {
  151. Some(ctx.uregs.regs[n] as *mut _)
  152. } else {
  153. None
  154. }
  155. }
  156. fn from_retval(ctx: &pt_regs) -> Option<Self> {
  157. Some(ctx.uregs.regs[0] as *mut _)
  158. }
  159. }
  160. #[cfg(bpf_target_arch = "aarch64")]
  161. impl<T> FromPtRegs for *mut T {
  162. fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
  163. if n <= 7 {
  164. Some(ctx.regs.regs[n] as *mut _)
  165. } else {
  166. None
  167. }
  168. }
  169. fn from_retval(ctx: &pt_regs) -> Option<Self> {
  170. Some(ctx.regs.regs[0] as *mut _)
  171. }
  172. }
  173. /// Helper macro to implement [`FromPtRegs`] for a primitive type.
  174. macro_rules! impl_from_pt_regs {
  175. ($type:ident) => {
  176. #[cfg(bpf_target_arch = "x86_64")]
  177. impl FromPtRegs for $type {
  178. fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
  179. match n {
  180. 0 => Some(ctx.rdi as *const $type as _),
  181. 1 => Some(ctx.rsi as *const $type as _),
  182. 2 => Some(ctx.rdx as *const $type as _),
  183. 3 => Some(ctx.rcx as *const $type as _),
  184. 4 => Some(ctx.r8 as *const $type as _),
  185. 5 => Some(ctx.r9 as *const $type as _),
  186. _ => None,
  187. }
  188. }
  189. fn from_retval(ctx: &pt_regs) -> Option<Self> {
  190. Some(ctx.rax as *const $type as _)
  191. }
  192. }
  193. #[cfg(bpf_target_arch = "armv7")]
  194. impl FromPtRegs for $type {
  195. fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
  196. if n <= 6 {
  197. Some(ctx.uregs.regs[n] as *const $type as _)
  198. } else {
  199. None
  200. }
  201. }
  202. fn from_retval(ctx: &pt_regs) -> Option<Self> {
  203. Some(ctx.uregs.regs[0] as *const $type as _)
  204. }
  205. }
  206. #[cfg(bpf_target_arch = "aarch64")]
  207. impl FromPtRegs for $type {
  208. fn from_argument(ctx: &pt_regs, n: usize) -> Option<Self> {
  209. if n <= 7 {
  210. Some(ctx.regs.regs[n] as *const $type as _)
  211. } else {
  212. None
  213. }
  214. }
  215. fn from_retval(ctx: &pt_regs) -> Option<Self> {
  216. Some(ctx.regs.regs[0] as *const $type as _)
  217. }
  218. }
  219. };
  220. }
  221. impl_from_pt_regs!(u8);
  222. impl_from_pt_regs!(u16);
  223. impl_from_pt_regs!(u32);
  224. impl_from_pt_regs!(u64);
  225. impl_from_pt_regs!(i8);
  226. impl_from_pt_regs!(i16);
  227. impl_from_pt_regs!(i32);
  228. impl_from_pt_regs!(i64);
  229. impl_from_pt_regs!(usize);
  230. impl_from_pt_regs!(isize);