1use object::{AddressSize, Object, ObjectSection, ObjectSymbol, ReadRef};
4
5use crate::{
6 dwarf::Dwarf,
7 metadata::{parse_metadata, Metadata},
8 r#type::Type,
9 Error, Result,
10};
11
12pub struct Parser<'elf> {
14 logs_section: &'elf [u8],
15 build_id: &'elf [u8],
16 dwarf: Dwarf<'elf>,
17 address_size: AddressSize,
18 metadata_addresses: Vec<u64>,
19}
20
21impl<'elf> Parser<'elf> {
22 pub fn new<R: ReadRef<'elf>>(data: R) -> Result<Self> {
24 let file = object::File::parse(data)?;
25 let dwarf = Dwarf::new(&file)?;
26 let build_id = file
27 .build_id()?
28 .ok_or(Error::Custom("Unable to find build ID in elf!"))?;
29
30 let address_size = file.architecture().address_size().ok_or(Error::Custom(
31 "Unsupported architecture, no address size information!",
32 ))?;
33
34 let metadata_addresses = file
35 .symbols()
36 .filter(|s| s.name().is_ok_and(|n| n.contains("cdefmt_log_metadata")))
37 .map(|s| s.address())
38 .collect::<Vec<_>>();
39
40 Ok(Parser {
41 logs_section: file
42 .section_by_name(".cdefmt")
43 .ok_or(Error::MissingSection)?
44 .data()?,
45 build_id,
46 dwarf,
47 address_size,
48 metadata_addresses,
49 })
50 }
51
52 pub fn get_log_metadata(&self, id: usize) -> Result<Metadata<'elf>> {
54 parse_metadata(self.logs_section, id, self.endian())
55 }
56
57 pub fn iter_logs<'parser>(&'parser self) -> LogIterator<'parser, 'elf> {
59 LogIterator {
60 parser: self,
61 symbol_addr_iterator: self.metadata_addresses.iter(),
62 }
63 }
64
65 pub fn get_log_args_type(&self, metadata: &Metadata) -> Result<Option<Type>> {
71 let type_name = format!("cdefmt_log_args_t{}", metadata.counter);
72 self.dwarf.get_type(metadata.file, &type_name)
73 }
74
75 pub fn build_id(&self) -> &'elf [u8] {
76 self.build_id
77 }
78
79 pub fn address_size(&self) -> AddressSize {
80 self.address_size
81 }
82
83 pub fn endian(&self) -> gimli::RunTimeEndian {
84 self.dwarf.endian()
85 }
86}
87
88pub struct LogIterator<'parser, 'elf>
89where
90 'elf: 'parser,
91{
92 parser: &'parser Parser<'elf>,
93 symbol_addr_iterator: std::slice::Iter<'parser, u64>,
94}
95
96impl<'elf> Iterator for LogIterator<'_, 'elf> {
97 type Item = Result<(Metadata<'elf>, Option<Type>)>;
98
99 fn next(&mut self) -> Option<Self::Item> {
100 let metadata = match self.symbol_addr_iterator.next() {
101 Some(&addr) => match self.parser.get_log_metadata(addr as usize) {
102 Ok(m) => m,
103 Err(e) => return Some(Err(e)),
104 },
105 None => return None,
106 };
107
108 let ty = match self.parser.get_log_args_type(&metadata) {
109 Ok(t) => t,
110 Err(e) => return Some(Err(e)),
111 };
112
113 Some(Ok((metadata, ty)))
114 }
115}