1use object::{AddressSize, Object, ObjectSection, ReadRef};
4
5use crate::{
6 dwarf::Dwarf,
7 metadata::{Metadata, SchemaVersion},
8 r#type::Type,
9 Error, Result,
10};
11
12pub 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 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 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 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}