cdefmt_decoder/
decoder.rs1use std::collections::HashMap;
4
5use cdefmt_parser::{
6 metadata::Metadata,
7 r#type::{self, Type},
8 Parser,
9};
10use gimli::Reader;
11use object::ReadRef;
12
13use crate::{log::Log, var::Var, Error, Result};
14
15pub struct Decoder<'elf> {
17 parser: Parser<'elf>,
18 log_cache: HashMap<usize, (Metadata<'elf>, Option<Type>)>,
19}
20
21impl<'elf> Decoder<'elf> {
22 pub fn new<R: ReadRef<'elf>>(data: R) -> Result<Self> {
24 Ok(Decoder {
25 parser: Parser::new(data)?,
26 log_cache: Default::default(),
27 })
28 }
29
30 pub fn decode_log(&mut self, data: &[u8]) -> Result<Log<'elf>> {
32 let mut data = gimli::EndianSlice::new(data, self.parser.endian());
33 let id = data.read_address(self.parser.address_size().bytes())? as usize;
34
35 if let std::collections::hash_map::Entry::Vacant(e) = self.log_cache.entry(id) {
36 let metadata = self.parser.get_log_metadata(id)?;
38 let ty = self.parser.get_log_args_type(&metadata)?;
39 e.insert((metadata, ty));
40 };
41
42 let (metadata, ty) = self.log_cache.get(&id).unwrap();
44
45 let args = if let Some(ty) = ty {
46 Self::decode_log_args(ty, data)?
47 } else {
48 vec![]
49 };
50
51 let log = Log::new(metadata.clone(), args);
52
53 if id == 0 {
54 self.validate_init(&log)?
55 }
56
57 Ok(log)
58 }
59
60 pub fn precache_log_metadata(&mut self) -> Result<usize> {
65 self.log_cache = self
66 .parser
67 .iter_logs()
68 .map(|l| {
69 let (metadata, ty) = l?;
70 Ok((metadata.id, (metadata, ty)))
71 })
72 .collect::<Result<_>>()?;
73
74 Ok(self.log_cache.len())
75 }
76
77 pub fn get_endianness(&self) -> gimli::RunTimeEndian {
78 self.parser.endian()
79 }
80
81 fn decode_log_args<R: Reader>(ty: &Type, mut data: R) -> Result<Vec<Var>> {
83 let members = if let Type::Structure { members, .. } = ty {
84 members
85 } else {
86 return Err(Error::Custom("The log's args aren't a structure!"));
87 };
88
89 let members = &members[1..];
91
92 let mut decoded = members
94 .iter()
95 .filter(|m| !matches!(m.name.as_str(), "dynamic_data"))
101 .map(|m| Ok(Var::parse(&m.ty, &mut data)?.0))
102 .collect::<Result<Vec<_>>>()?;
103
104 for (i, member) in members.iter().enumerate() {
106 match member.name.as_str() {
107 n if n.contains("dynamic_array") => {
108 decoded[i] = Self::decode_dynamic_array(member, &decoded[i], &mut data)?
109 }
110 _ => continue,
111 }
112 }
113
114 Ok(decoded)
115 }
116
117 fn validate_init(&self, log: &Log) -> Result<()> {
118 let args = log.get_args();
119
120 if args.is_empty() {
121 return Err(Error::Custom("No build ID argument information!"));
122 }
123
124 if let Var::Array(build_id) = args.first().unwrap() {
125 let build_id = build_id
126 .iter()
127 .map(|b| match b {
128 Var::U8(b) => Ok(*b),
129 _ => Err(Error::Custom("Build ID data contains non u8 element!")),
130 })
131 .collect::<Result<Vec<_>>>()?;
132 if self.parser.build_id() != build_id {
133 Err(Error::Custom("Build ID mismatch!"))
134 } else {
135 Ok(())
136 }
137 } else {
138 Err(Error::Custom("Build ID missing or not an array"))
139 }
140 }
141
142 fn decode_dynamic_array<R: Reader>(
143 metadata: &r#type::StructureMember,
144 value: &Var,
145 data: &mut R,
146 ) -> Result<Var> {
147 let size = match value {
153 Var::Structure { members } => &members[0].value,
154 _ => return Err(Error::Custom("Dynamic array metadata is not a struct!")),
155 }
156 .as_u64();
157
158 let arr_ty = match &metadata.ty {
160 Type::Structure { members, .. } => &members[1].ty,
161 _ => return Err(Error::Custom("Dynamic array metadata is not a struct!")),
162 };
163
164 let ty = match arr_ty {
165 Type::Array { ty, .. } => ty,
166 _ => {
167 return Err(Error::Custom(
168 "Dynamic array type metadata is not an array!",
169 ))
170 }
171 };
172
173 let dyn_ty = Type::Array {
174 ty: ty.clone(),
175 lengths: vec![size / ty.size() as u64],
176 };
177
178 Ok(Var::parse(&dyn_ty, data)?.0)
179 }
180}