cdefmt_parser/
metadata.rs1use 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}