lib.rs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. #![no_std]
  2. use core::{mem, num, ptr};
  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. macro_rules! impl_formatter_for_types {
  32. ($trait:path : { $($type:ty),*}) => {
  33. $(
  34. impl $trait for $type {}
  35. )*
  36. };
  37. }
  38. // Any value impl `ToString`
  39. pub trait DefaultFormatter {}
  40. impl_formatter_for_types!(
  41. DefaultFormatter: {
  42. bool,
  43. i8, i16, i32, i64, isize,
  44. u8, u16, u32, u64, usize,
  45. f32, f64,
  46. char,
  47. str,
  48. &str
  49. }
  50. );
  51. pub trait LowerHexFormatter {}
  52. impl_formatter_for_types!(
  53. LowerHexFormatter: {
  54. i8, i16, i32, i64, isize,
  55. u8, u16, u32, u64, usize
  56. }
  57. );
  58. pub trait LowerHexDebugFormatter {}
  59. impl LowerHexDebugFormatter for &[u8] {}
  60. pub trait UpperHexFormatter {}
  61. impl_formatter_for_types!(
  62. UpperHexFormatter: {
  63. i8, i16, i32, i64, isize,
  64. u8, u16, u32, u64, usize
  65. }
  66. );
  67. pub trait UpperHexDebugFormatter {}
  68. impl UpperHexDebugFormatter for &[u8] {}
  69. pub trait Ipv4Formatter {}
  70. impl Ipv4Formatter for u32 {}
  71. pub trait Ipv6Formatter {}
  72. impl Ipv6Formatter for [u8; 16] {}
  73. impl Ipv6Formatter for [u16; 8] {}
  74. pub trait LowerMacFormatter {}
  75. impl LowerMacFormatter for [u8; 6] {}
  76. pub trait UpperMacFormatter {}
  77. impl UpperMacFormatter for [u8; 6] {}
  78. #[inline(always)]
  79. pub fn check_impl_default<T: DefaultFormatter>(_v: T) {}
  80. #[inline(always)]
  81. pub fn check_impl_lower_hex<T: LowerHexFormatter>(_v: T) {}
  82. #[inline(always)]
  83. pub fn check_impl_lower_hex_debug<T: LowerHexDebugFormatter>(_v: T) {}
  84. #[inline(always)]
  85. pub fn check_impl_upper_hex<T: UpperHexFormatter>(_v: T) {}
  86. #[inline(always)]
  87. pub fn check_impl_upper_hex_debug<T: UpperHexDebugFormatter>(_v: T) {}
  88. #[inline(always)]
  89. pub fn check_impl_ipv4<T: Ipv4Formatter>(_v: T) {}
  90. #[inline(always)]
  91. pub fn check_impl_ipv6<T: Ipv6Formatter>(_v: T) {}
  92. #[inline(always)]
  93. pub fn check_impl_lower_mac<T: LowerMacFormatter>(_v: T) {}
  94. #[inline(always)]
  95. pub fn check_impl_upper_mac<T: UpperMacFormatter>(_v: T) {}
  96. #[repr(u8)]
  97. #[derive(Copy, Clone, Debug)]
  98. pub enum RecordField {
  99. Target = 1,
  100. Level,
  101. Module,
  102. File,
  103. Line,
  104. NumArgs,
  105. }
  106. /// Types which are supported by aya-log and can be safely sent from eBPF
  107. /// programs to userspace.
  108. #[repr(u8)]
  109. #[derive(Copy, Clone, Debug)]
  110. pub enum Argument {
  111. DisplayHint,
  112. I8,
  113. I16,
  114. I32,
  115. I64,
  116. Isize,
  117. U8,
  118. U16,
  119. U32,
  120. U64,
  121. Usize,
  122. F32,
  123. F64,
  124. /// `[u8; 6]` array which represents a MAC address.
  125. ArrU8Len6,
  126. /// `[u8; 16]` array which represents an IPv6 address.
  127. ArrU8Len16,
  128. /// `[u16; 8]` array which represents an IPv6 address.
  129. ArrU16Len8,
  130. Bytes,
  131. Str,
  132. }
  133. /// All display hints
  134. #[repr(u8)]
  135. #[derive(Copy, Clone, Debug, PartialEq, Eq, IntoPrimitive)]
  136. pub enum DisplayHint {
  137. /// Default string representation.
  138. Default = 1,
  139. /// `:x`
  140. LowerHex,
  141. /// `:X`
  142. UpperHex,
  143. /// `:ipv4`
  144. Ipv4,
  145. /// `:ipv6`
  146. Ipv6,
  147. /// `:mac`
  148. LowerMac,
  149. /// `:MAC`
  150. UpperMac,
  151. }
  152. struct TagLenValue<T, V> {
  153. pub tag: T,
  154. pub value: V,
  155. }
  156. impl<T, V> TagLenValue<T, V>
  157. where
  158. V: IntoIterator<Item = u8>,
  159. <V as IntoIterator>::IntoIter: ExactSizeIterator,
  160. {
  161. pub(crate) fn write(self, mut buf: &mut [u8]) -> Result<usize, ()> {
  162. // Break the abstraction to please the verifier.
  163. if buf.len() > LOG_BUF_CAPACITY {
  164. buf = &mut buf[..LOG_BUF_CAPACITY];
  165. }
  166. let Self { tag, value } = self;
  167. let value = value.into_iter();
  168. let len = value.len();
  169. let wire_len: LogValueLength = value
  170. .len()
  171. .try_into()
  172. .map_err(|num::TryFromIntError { .. }| ())?;
  173. let size = mem::size_of_val(&tag) + mem::size_of_val(&wire_len) + len;
  174. if size > buf.len() {
  175. return Err(());
  176. }
  177. let tag_size = mem::size_of_val(&tag);
  178. unsafe { ptr::write_unaligned(buf.as_mut_ptr() as *mut _, tag) };
  179. buf = &mut buf[tag_size..];
  180. unsafe { ptr::write_unaligned(buf.as_mut_ptr() as *mut _, wire_len) };
  181. buf = &mut buf[mem::size_of_val(&wire_len)..];
  182. buf.iter_mut().zip(value).for_each(|(dst, src)| {
  183. *dst = src;
  184. });
  185. Ok(size)
  186. }
  187. }
  188. impl<T, V> TagLenValue<T, V> {
  189. #[inline(always)]
  190. pub(crate) fn new(tag: T, value: V) -> TagLenValue<T, V> {
  191. TagLenValue { tag, value }
  192. }
  193. }
  194. pub trait WriteToBuf {
  195. #[allow(clippy::result_unit_err)]
  196. fn write(self, buf: &mut [u8]) -> Result<usize, ()>;
  197. }
  198. macro_rules! impl_write_to_buf {
  199. ($type:ident, $arg_type:expr) => {
  200. impl WriteToBuf for $type {
  201. fn write(self, buf: &mut [u8]) -> Result<usize, ()> {
  202. TagLenValue::new($arg_type, self.to_ne_bytes()).write(buf)
  203. }
  204. }
  205. };
  206. }
  207. impl_write_to_buf!(i8, Argument::I8);
  208. impl_write_to_buf!(i16, Argument::I16);
  209. impl_write_to_buf!(i32, Argument::I32);
  210. impl_write_to_buf!(i64, Argument::I64);
  211. impl_write_to_buf!(isize, Argument::Isize);
  212. impl_write_to_buf!(u8, Argument::U8);
  213. impl_write_to_buf!(u16, Argument::U16);
  214. impl_write_to_buf!(u32, Argument::U32);
  215. impl_write_to_buf!(u64, Argument::U64);
  216. impl_write_to_buf!(usize, Argument::Usize);
  217. impl_write_to_buf!(f32, Argument::F32);
  218. impl_write_to_buf!(f64, Argument::F64);
  219. impl WriteToBuf for [u8; 16] {
  220. fn write(self, buf: &mut [u8]) -> Result<usize, ()> {
  221. TagLenValue::new(Argument::ArrU8Len16, self).write(buf)
  222. }
  223. }
  224. impl WriteToBuf for [u16; 8] {
  225. fn write(self, buf: &mut [u8]) -> Result<usize, ()> {
  226. let bytes = unsafe { core::mem::transmute::<_, [u8; 16]>(self) };
  227. TagLenValue::new(Argument::ArrU16Len8, bytes).write(buf)
  228. }
  229. }
  230. impl WriteToBuf for [u8; 6] {
  231. fn write(self, buf: &mut [u8]) -> Result<usize, ()> {
  232. TagLenValue::new(Argument::ArrU8Len6, self).write(buf)
  233. }
  234. }
  235. impl WriteToBuf for &[u8] {
  236. fn write(self, buf: &mut [u8]) -> Result<usize, ()> {
  237. TagLenValue::new(Argument::Bytes, self.iter().copied()).write(buf)
  238. }
  239. }
  240. impl WriteToBuf for &str {
  241. fn write(self, buf: &mut [u8]) -> Result<usize, ()> {
  242. TagLenValue::new(Argument::Str, self.as_bytes().iter().copied()).write(buf)
  243. }
  244. }
  245. impl WriteToBuf for DisplayHint {
  246. fn write(self, buf: &mut [u8]) -> Result<usize, ()> {
  247. let v: u8 = self.into();
  248. TagLenValue::new(Argument::DisplayHint, v.to_ne_bytes()).write(buf)
  249. }
  250. }
  251. #[allow(clippy::result_unit_err)]
  252. #[doc(hidden)]
  253. #[inline(always)]
  254. pub fn write_record_header(
  255. buf: &mut [u8],
  256. target: &str,
  257. level: Level,
  258. module: &str,
  259. file: &str,
  260. line: u32,
  261. num_args: usize,
  262. ) -> Result<usize, ()> {
  263. let level: u8 = level.into();
  264. let mut size = 0;
  265. size += TagLenValue::new(RecordField::Target, target.as_bytes().iter().copied())
  266. .write(&mut buf[size..])?;
  267. size += TagLenValue::new(RecordField::Level, level.to_ne_bytes()).write(&mut buf[size..])?;
  268. size += TagLenValue::new(RecordField::Module, module.as_bytes().iter().copied())
  269. .write(&mut buf[size..])?;
  270. size += TagLenValue::new(RecordField::File, file.as_bytes().iter().copied())
  271. .write(&mut buf[size..])?;
  272. size += TagLenValue::new(RecordField::Line, line.to_ne_bytes()).write(&mut buf[size..])?;
  273. size +=
  274. TagLenValue::new(RecordField::NumArgs, num_args.to_ne_bytes()).write(&mut buf[size..])?;
  275. Ok(size)
  276. }
  277. #[cfg(test)]
  278. mod test {
  279. use super::*;
  280. fn log_value_length_sufficient() {
  281. assert!(
  282. LOG_BUF_CAPACITY >= LogValueLength::MAX.into(),
  283. "{} < {}",
  284. LOG_BUF_CAPACITY,
  285. LogValueLength::MAX
  286. );
  287. }
  288. }