cdefmt_parser/
parser.rs

1//! Contains logic related to finding logs in the elf and parsing them.
2
3use object::{AddressSize, Object, ObjectSection, ReadRef};
4
5use crate::{
6    dwarf::Dwarf,
7    metadata::{Metadata, SchemaVersion},
8    r#type::Type,
9    Error, Result,
10};
11
12/// Responsible for parsing logs from the elf.
13pub struct Parser<'data> {
14    logs_section: &'data [u8],
15    build_id: &'data [u8],
16    dwarf: Dwarf<'data>,
17    address_size: AddressSize,
18}
19
20impl<'data> Parser<'data> {
21    /// Creates a new Parser from elf data.
22    pub fn new<R: ReadRef<'data>>(data: R) -> Result<Self> {
23        let file = object::File::parse(data)?;
24        let dwarf = Dwarf::new(&file)?;
25        let build_id = file
26            .build_id()?
27            .ok_or(Error::Custom("Unable to find build ID in elf!"))?;
28
29        let address_size = file.architecture().address_size().ok_or(Error::Custom(
30            "Unsupported architecture, no address size information!",
31        ))?;
32
33        Ok(Parser {
34            logs_section: file
35                .section_by_name(".cdefmt")
36                .ok_or(Error::MissingSection)?
37                .data()?,
38            build_id,
39            dwarf,
40            address_size,
41        })
42    }
43
44    /// Returns a specific log's metadata.
45    pub fn get_log_metadata(&self, id: usize) -> Result<Metadata> {
46        if id >= self.logs_section.len() {
47            return Err(Error::OutOfBounds(id, self.logs_section.len()));
48        }
49
50        let json = &self.logs_section[id..]
51            .split(|b| *b == 0)
52            .next()
53            .ok_or(Error::NoNullTerm)?;
54        let json = std::str::from_utf8(json).map_err(|e| Error::Utf8(id, e))?;
55        let schema: SchemaVersion = serde_json::from_str(json)?;
56
57        let mut metadata = match schema.version {
58            1 => serde_json::from_str::<Metadata>(json),
59            _ => return Err(Error::SchemaVersion(schema.version)),
60        }?;
61
62        metadata.id = id;
63
64        Ok(metadata)
65    }
66
67    /// Returns the type of the log's arguments.
68    /// Return:
69    /// * Ok(Some(_)) => The type of the arguments.
70    /// * Ok(None)    => Unable to find the type in the elf's dwarf section.
71    /// * Err(_)      => Encountered some error while parsing the dwarf.
72    pub fn get_log_args_type(&self, metadata: &Metadata) -> Result<Option<Type>> {
73        let type_name = format!("cdefmt_log_args_t{}", metadata.counter);
74        self.dwarf.get_type(&metadata.file, &type_name)
75    }
76
77    pub fn build_id(&self) -> &'data [u8] {
78        self.build_id
79    }
80
81    pub fn address_size(&self) -> AddressSize {
82        self.address_size
83    }
84
85    pub fn endian(&self) -> gimli::RunTimeEndian {
86        self.dwarf.endian()
87    }
88}