use crate::tag_type::{Tag, TagIter, TagType};
use core::fmt::{Debug, Formatter};
use core::str::Utf8Error;
#[derive(Clone, Copy)]
#[repr(C, packed)] pub struct ModuleTag {
typ: TagType,
size: u32,
mod_start: u32,
mod_end: u32,
cmdline_str: u8,
}
impl ModuleTag {
pub fn cmdline(&self) -> Result<&str, Utf8Error> {
use core::{mem, slice, str};
let strlen = self.size as usize - mem::size_of::<ModuleTag>();
let bytes = unsafe { slice::from_raw_parts((&self.cmdline_str) as *const u8, strlen) };
str::from_utf8(bytes)
}
pub fn start_address(&self) -> u32 {
self.mod_start
}
pub fn end_address(&self) -> u32 {
self.mod_end
}
pub fn module_size(&self) -> u32 {
self.mod_end - self.mod_start
}
}
impl Debug for ModuleTag {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.debug_struct("ModuleTag")
.field("type", &{ self.typ })
.field("size (tag)", &{ self.size })
.field("size (module)", &self.module_size())
.field("mod_start", &(self.mod_start as *const usize))
.field("mod_end", &(self.mod_end as *const usize))
.field("cmdline", &self.cmdline())
.finish()
}
}
pub fn module_iter(iter: TagIter) -> ModuleIter {
ModuleIter { iter }
}
#[derive(Clone)]
pub struct ModuleIter<'a> {
iter: TagIter<'a>,
}
impl<'a> Iterator for ModuleIter<'a> {
type Item = &'a ModuleTag;
fn next(&mut self) -> Option<&'a ModuleTag> {
self.iter
.find(|x| x.typ == TagType::Module)
.map(|tag| unsafe { &*(tag as *const Tag as *const ModuleTag) })
}
}
impl<'a> Debug for ModuleIter<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
let mut list = f.debug_list();
self.clone().for_each(|tag| {
list.entry(&tag);
});
list.finish()
}
}
#[cfg(test)]
mod tests {
use crate::TagType;
const MSG: &str = "hello";
fn get_bytes() -> std::vec::Vec<u8> {
let size = (4 + 4 + 4 + 4 + MSG.as_bytes().len() + 1) as u32;
[
&((TagType::Module as u32).to_ne_bytes()),
&size.to_ne_bytes(),
&0_u32.to_ne_bytes(),
&0_u32.to_ne_bytes(),
MSG.as_bytes(),
&[0],
]
.iter()
.flat_map(|bytes| bytes.iter())
.copied()
.collect()
}
#[test]
fn test_parse_str() {
let tag = get_bytes();
let tag = unsafe { tag.as_ptr().cast::<super::ModuleTag>().as_ref().unwrap() };
assert_eq!({ tag.typ }, TagType::Module);
assert_eq!(tag.cmdline().expect("must be valid UTF-8"), MSG);
}
}