4
0

lib.rs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. #![no_std]
  2. use core::{cmp, mem, ptr};
  3. pub const LOG_BUF_CAPACITY: usize = 8192;
  4. pub const LOG_FIELDS: usize = 7;
  5. #[repr(usize)]
  6. #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
  7. pub enum Level {
  8. /// The "error" level.
  9. ///
  10. /// Designates very serious errors.
  11. Error = 1,
  12. /// The "warn" level.
  13. ///
  14. /// Designates hazardous situations.
  15. Warn,
  16. /// The "info" level.
  17. ///
  18. /// Designates useful information.
  19. Info,
  20. /// The "debug" level.
  21. ///
  22. /// Designates lower priority information.
  23. Debug,
  24. /// The "trace" level.
  25. ///
  26. /// Designates very low priority, often extremely verbose, information.
  27. Trace,
  28. }
  29. #[repr(usize)]
  30. #[derive(Copy, Clone, Debug)]
  31. pub enum RecordField {
  32. Target = 1,
  33. Level,
  34. Module,
  35. File,
  36. Line,
  37. NumArgs,
  38. Log,
  39. }
  40. #[repr(usize)]
  41. #[derive(Copy, Clone, Debug)]
  42. pub enum ArgType {
  43. I8,
  44. I16,
  45. I32,
  46. I64,
  47. I128,
  48. Isize,
  49. U8,
  50. U16,
  51. U32,
  52. U64,
  53. U128,
  54. Usize,
  55. F32,
  56. F64,
  57. Str,
  58. }
  59. #[cfg(feature = "userspace")]
  60. mod userspace {
  61. use super::*;
  62. unsafe impl aya::Pod for RecordField {}
  63. unsafe impl aya::Pod for ArgType {}
  64. }
  65. struct TagLenValue<'a, T> {
  66. tag: T,
  67. value: &'a [u8],
  68. }
  69. impl<'a, T> TagLenValue<'a, T>
  70. where
  71. T: Copy,
  72. {
  73. #[inline(always)]
  74. pub(crate) fn new(tag: T, value: &'a [u8]) -> TagLenValue<'a, T> {
  75. TagLenValue { tag, value }
  76. }
  77. pub(crate) fn write(&self, mut buf: &mut [u8]) -> Result<usize, ()> {
  78. let size = mem::size_of::<T>() + mem::size_of::<usize>() + self.value.len();
  79. let remaining = cmp::min(buf.len(), LOG_BUF_CAPACITY);
  80. // Check if the size doesn't exceed the buffer bounds.
  81. if size > remaining {
  82. return Err(());
  83. }
  84. unsafe { ptr::write_unaligned(buf.as_mut_ptr() as *mut _, self.tag) };
  85. buf = &mut buf[mem::size_of::<T>()..];
  86. unsafe { ptr::write_unaligned(buf.as_mut_ptr() as *mut _, self.value.len()) };
  87. buf = &mut buf[mem::size_of::<usize>()..];
  88. let len = cmp::min(buf.len(), self.value.len());
  89. // The verifier isn't happy with `len` being unbounded, so compare it
  90. // with `LOG_BUF_CAPACITY`.
  91. if len > LOG_BUF_CAPACITY {
  92. return Err(());
  93. }
  94. buf[..len].copy_from_slice(&self.value[..len]);
  95. Ok(size)
  96. }
  97. }
  98. pub trait WriteToBuf {
  99. #[allow(clippy::result_unit_err)]
  100. fn write(&self, buf: &mut [u8]) -> Result<usize, ()>;
  101. }
  102. macro_rules! impl_write_to_buf {
  103. ($type:ident, $arg_type:expr) => {
  104. impl WriteToBuf for $type {
  105. fn write(&self, buf: &mut [u8]) -> Result<usize, ()> {
  106. TagLenValue::<ArgType>::new($arg_type, &self.to_ne_bytes()).write(buf)
  107. }
  108. }
  109. };
  110. }
  111. impl_write_to_buf!(i8, ArgType::I8);
  112. impl_write_to_buf!(i16, ArgType::I16);
  113. impl_write_to_buf!(i32, ArgType::I32);
  114. impl_write_to_buf!(i64, ArgType::I64);
  115. impl_write_to_buf!(i128, ArgType::I128);
  116. impl_write_to_buf!(isize, ArgType::Isize);
  117. impl_write_to_buf!(u8, ArgType::U8);
  118. impl_write_to_buf!(u16, ArgType::U16);
  119. impl_write_to_buf!(u32, ArgType::U32);
  120. impl_write_to_buf!(u64, ArgType::U64);
  121. impl_write_to_buf!(u128, ArgType::U128);
  122. impl_write_to_buf!(usize, ArgType::Usize);
  123. impl_write_to_buf!(f32, ArgType::F32);
  124. impl_write_to_buf!(f64, ArgType::F64);
  125. impl WriteToBuf for str {
  126. fn write(&self, buf: &mut [u8]) -> Result<usize, ()> {
  127. TagLenValue::<ArgType>::new(ArgType::Str, self.as_bytes()).write(buf)
  128. }
  129. }
  130. #[allow(clippy::result_unit_err)]
  131. #[doc(hidden)]
  132. #[inline(always)]
  133. pub fn write_record_header(
  134. buf: &mut [u8],
  135. target: &str,
  136. level: Level,
  137. module: &str,
  138. file: &str,
  139. line: u32,
  140. num_args: usize,
  141. ) -> Result<usize, ()> {
  142. let mut size = 0;
  143. for attr in [
  144. TagLenValue::<RecordField>::new(RecordField::Target, target.as_bytes()),
  145. TagLenValue::<RecordField>::new(RecordField::Level, &(level as usize).to_ne_bytes()),
  146. TagLenValue::<RecordField>::new(RecordField::Module, module.as_bytes()),
  147. TagLenValue::<RecordField>::new(RecordField::File, file.as_bytes()),
  148. TagLenValue::<RecordField>::new(RecordField::Line, &line.to_ne_bytes()),
  149. TagLenValue::<RecordField>::new(RecordField::NumArgs, &num_args.to_ne_bytes()),
  150. ] {
  151. size += attr.write(&mut buf[size..])?;
  152. }
  153. Ok(size)
  154. }
  155. #[allow(clippy::result_unit_err)]
  156. #[doc(hidden)]
  157. pub fn write_record_message(buf: &mut [u8], msg: &str) -> Result<usize, ()> {
  158. TagLenValue::<RecordField>::new(RecordField::Log, msg.as_bytes()).write(buf)
  159. }