Skip to main content

cdefmt_parser/
metadata.rs

1//! Representation of log metadata extracted from the target elf's .cdefmt section.
2
3use core::{fmt, str};
4
5use gimli::{EndianSlice, Reader, RunTimeEndian};
6
7use crate::{Error, Result};
8
9#[derive(Clone, Copy, Debug)]
10#[repr(u8)]
11pub enum Level {
12    Error = 0,
13    Warning = 1,
14    Info = 2,
15    Debug = 3,
16    Verbose = 4,
17}
18
19impl fmt::Display for Level {
20    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21        f.pad(&format!("{:?}", self))
22    }
23}
24
25#[derive(Clone, Debug)]
26pub struct Metadata<'elf> {
27    pub id: usize,
28    pub counter: u32,
29    pub line: usize,
30    pub file: &'elf str,
31    pub fmt: &'elf str,
32    pub names: Vec<&'elf str>,
33    pub level: Level,
34}
35
36fn parse_metadata_impl<'elf>(
37    id: usize,
38    endian_slice: &mut EndianSlice<'elf, RunTimeEndian>,
39) -> Result<(Metadata<'elf>, usize)> {
40    let mut offset = 0;
41
42    let version = endian_slice.read_u32()?;
43    offset += 4;
44
45    if version != 1 {
46        return Err(Error::SchemaVersion(version).into());
47    }
48
49    let counter = endian_slice.read_u32()?;
50    let line = endian_slice.read_u32()? as usize;
51    offset += 4 * 2;
52
53    let file_len = endian_slice.read_u32()? as usize;
54    let fmt_len = endian_slice.read_u32()? as usize;
55    let names_len = endian_slice.read_u32()? as usize;
56    offset += 4 * 3;
57
58    let level = endian_slice.read_u8()?;
59    offset += 1;
60
61    let file = endian_slice.split(file_len)?;
62    let file = str::from_utf8(&file.slice()[..file_len - 1]).map_err(|e| Error::Utf8(id, e))?;
63    offset += file_len;
64
65    let fmt = endian_slice.split(fmt_len)?;
66    let fmt = str::from_utf8(&fmt.slice()[..fmt_len - 1]).map_err(|e| Error::Utf8(id, e))?;
67    offset += fmt_len;
68
69    let names = (0..names_len)
70        .map(|_| {
71            let name_len = endian_slice.read_u32()? as usize;
72            offset += 4;
73            let name = endian_slice.split(name_len)?;
74            offset += name_len;
75            str::from_utf8(&name.slice()[..name_len - 1]).map_err(|e| Error::Utf8(id, e).into())
76        })
77        .collect::<Result<Vec<_>>>()?;
78
79    Ok((
80        Metadata {
81            id,
82            counter,
83            line,
84            file,
85            fmt,
86            names,
87            level: unsafe { std::mem::transmute::<u8, Level>(level) },
88        },
89        offset,
90    ))
91}
92
93pub(crate) fn parse_metadata(
94    cdefmt_section: &[u8],
95    id: usize,
96    endian: RunTimeEndian,
97) -> Result<Metadata<'_>> {
98    let mut endian_slice = EndianSlice::new(cdefmt_section, endian);
99
100    endian_slice
101        .skip(id)
102        .map_err(|_| Error::OutOfBounds(id, cdefmt_section.len()))?;
103
104    Ok(parse_metadata_impl(id, &mut endian_slice)?.0)
105}