lib.rs 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. #![no_std]
  2. use core::{mem, num, ptr, slice};
  3. use num_enum::IntoPrimitive;
  4. pub const LOG_BUF_CAPACITY: usize = 8192;
  5. pub const LOG_FIELDS: usize = 6;
  6. pub type LogValueLength = u16;
  7. #[repr(u8)]
  8. #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, IntoPrimitive)]
  9. pub enum Level {
  10. /// The "error" level.
  11. ///
  12. /// Designates very serious errors.
  13. Error = 1,
  14. /// The "warn" level.
  15. ///
  16. /// Designates hazardous situations.
  17. Warn,
  18. /// The "info" level.
  19. ///
  20. /// Designates useful information.
  21. Info,
  22. /// The "debug" level.
  23. ///
  24. /// Designates lower priority information.
  25. Debug,
  26. /// The "trace" level.
  27. ///
  28. /// Designates very low priority, often extremely verbose, information.
  29. Trace,
  30. }
  31. #[repr(u8)]
  32. #[derive(Copy, Clone, Debug)]
  33. pub enum RecordField {
  34. Target = 1,
  35. Level,
  36. Module,
  37. File,
  38. Line,
  39. NumArgs,
  40. }
  41. /// Types which are supported by aya-log and can be safely sent from eBPF
  42. /// programs to userspace.
  43. #[repr(u8)]
  44. #[derive(Copy, Clone, Debug)]
  45. pub enum Argument {
  46. DisplayHint,
  47. I8,
  48. I16,
  49. I32,
  50. I64,
  51. Isize,
  52. U8,
  53. U16,
  54. U32,
  55. U64,
  56. Usize,
  57. F32,
  58. F64,
  59. /// `[u8; 6]` array which represents a MAC address.
  60. ArrU8Len6,
  61. /// `[u8; 16]` array which represents an IPv6 address.
  62. ArrU8Len16,
  63. /// `[u16; 8]` array which represents an IPv6 address.
  64. ArrU16Len8,
  65. Str,
  66. }
  67. /// All display hints
  68. #[repr(u8)]
  69. #[derive(Copy, Clone, Debug, PartialEq, Eq, IntoPrimitive)]
  70. pub enum DisplayHint {
  71. /// Default string representation.
  72. Default = 1,
  73. /// `:x`
  74. LowerHex,
  75. /// `:X`
  76. UpperHex,
  77. /// `:ipv4`
  78. Ipv4,
  79. /// `:ipv6`
  80. Ipv6,
  81. /// `:mac`
  82. LowerMac,
  83. /// `:MAC`
  84. UpperMac,
  85. }
  86. struct TagLenValue<'a, T> {
  87. tag: T,
  88. value: &'a [u8],
  89. }
  90. impl<'a, T> TagLenValue<'a, T>
  91. where
  92. T: Copy,
  93. {
  94. #[inline(always)]
  95. pub(crate) fn new(tag: T, value: &'a [u8]) -> TagLenValue<'a, T> {
  96. TagLenValue { tag, value }
  97. }
  98. pub(crate) fn write(&self, mut buf: &mut [u8]) -> Result<usize, ()> {
  99. // Break the abstraction to please the verifier.
  100. if buf.len() > LOG_BUF_CAPACITY {
  101. buf = &mut buf[..LOG_BUF_CAPACITY];
  102. }
  103. let Self { tag, value } = self;
  104. let len = value.len();
  105. let wire_len: LogValueLength = value
  106. .len()
  107. .try_into()
  108. .map_err(|num::TryFromIntError { .. }| ())?;
  109. let size = mem::size_of_val(tag) + mem::size_of_val(&wire_len) + len;
  110. if size > buf.len() {
  111. return Err(());
  112. }
  113. unsafe { ptr::write_unaligned(buf.as_mut_ptr() as *mut _, *tag) };
  114. buf = &mut buf[mem::size_of_val(tag)..];
  115. unsafe { ptr::write_unaligned(buf.as_mut_ptr() as *mut _, wire_len) };
  116. buf = &mut buf[mem::size_of_val(&wire_len)..];
  117. unsafe { ptr::copy_nonoverlapping(value.as_ptr(), buf.as_mut_ptr(), len) };
  118. Ok(size)
  119. }
  120. }
  121. pub trait WriteToBuf {
  122. #[allow(clippy::result_unit_err)]
  123. fn write(&self, buf: &mut [u8]) -> Result<usize, ()>;
  124. }
  125. macro_rules! impl_write_to_buf {
  126. ($type:ident, $arg_type:expr) => {
  127. impl WriteToBuf for $type {
  128. fn write(&self, buf: &mut [u8]) -> Result<usize, ()> {
  129. TagLenValue::<Argument>::new($arg_type, &self.to_ne_bytes()).write(buf)
  130. }
  131. }
  132. };
  133. }
  134. impl_write_to_buf!(i8, Argument::I8);
  135. impl_write_to_buf!(i16, Argument::I16);
  136. impl_write_to_buf!(i32, Argument::I32);
  137. impl_write_to_buf!(i64, Argument::I64);
  138. impl_write_to_buf!(isize, Argument::Isize);
  139. impl_write_to_buf!(u8, Argument::U8);
  140. impl_write_to_buf!(u16, Argument::U16);
  141. impl_write_to_buf!(u32, Argument::U32);
  142. impl_write_to_buf!(u64, Argument::U64);
  143. impl_write_to_buf!(usize, Argument::Usize);
  144. impl_write_to_buf!(f32, Argument::F32);
  145. impl_write_to_buf!(f64, Argument::F64);
  146. impl WriteToBuf for [u8; 16] {
  147. fn write(&self, buf: &mut [u8]) -> Result<usize, ()> {
  148. TagLenValue::<Argument>::new(Argument::ArrU8Len16, self).write(buf)
  149. }
  150. }
  151. impl WriteToBuf for [u16; 8] {
  152. fn write(&self, buf: &mut [u8]) -> Result<usize, ()> {
  153. let ptr = self.as_ptr().cast::<u8>();
  154. let bytes = unsafe { slice::from_raw_parts(ptr, 16) };
  155. TagLenValue::<Argument>::new(Argument::ArrU16Len8, bytes).write(buf)
  156. }
  157. }
  158. impl WriteToBuf for [u8; 6] {
  159. fn write(&self, buf: &mut [u8]) -> Result<usize, ()> {
  160. TagLenValue::<Argument>::new(Argument::ArrU8Len6, self).write(buf)
  161. }
  162. }
  163. impl WriteToBuf for str {
  164. fn write(&self, buf: &mut [u8]) -> Result<usize, ()> {
  165. TagLenValue::<Argument>::new(Argument::Str, self.as_bytes()).write(buf)
  166. }
  167. }
  168. impl WriteToBuf for DisplayHint {
  169. fn write(&self, buf: &mut [u8]) -> Result<usize, ()> {
  170. let v: u8 = (*self).into();
  171. TagLenValue::<Argument>::new(Argument::DisplayHint, &v.to_ne_bytes()).write(buf)
  172. }
  173. }
  174. #[allow(clippy::result_unit_err)]
  175. #[doc(hidden)]
  176. #[inline(always)]
  177. pub fn write_record_header(
  178. buf: &mut [u8],
  179. target: &str,
  180. level: Level,
  181. module: &str,
  182. file: &str,
  183. line: u32,
  184. num_args: usize,
  185. ) -> Result<usize, ()> {
  186. let level: u8 = level.into();
  187. let mut size = 0;
  188. for attr in [
  189. TagLenValue::<RecordField>::new(RecordField::Target, target.as_bytes()),
  190. TagLenValue::<RecordField>::new(RecordField::Level, &level.to_ne_bytes()),
  191. TagLenValue::<RecordField>::new(RecordField::Module, module.as_bytes()),
  192. TagLenValue::<RecordField>::new(RecordField::File, file.as_bytes()),
  193. TagLenValue::<RecordField>::new(RecordField::Line, &line.to_ne_bytes()),
  194. TagLenValue::<RecordField>::new(RecordField::NumArgs, &num_args.to_ne_bytes()),
  195. ] {
  196. size += attr.write(&mut buf[size..])?;
  197. }
  198. Ok(size)
  199. }
  200. #[cfg(test)]
  201. mod test {
  202. use super::*;
  203. fn log_value_length_sufficient() {
  204. assert!(
  205. LOG_BUF_CAPACITY >= LogValueLength::MAX.into(),
  206. "{} < {}",
  207. LOG_BUF_CAPACITY,
  208. LogValueLength::MAX
  209. );
  210. }
  211. }