1use std::{
4 borrow::Cow,
5 cmp::Ordering,
6 fmt::{Debug, Formatter},
7 mem::take,
8 ops::AddAssign,
9};
10
11use xmas_elf::{
12 program::Type,
13 sections::{SectionData, ShType},
14 ElfFile,
15};
16
17use crate::{
18 error::{ElfError, Error},
19 targets::Chip,
20};
21
22pub trait FirmwareImage<'a> {
24 fn entry(&self) -> u32;
26
27 fn segments(&'a self) -> Box<dyn Iterator<Item = CodeSegment<'a>> + 'a>;
29
30 fn segments_with_load_addresses(&'a self) -> Box<dyn Iterator<Item = CodeSegment<'a>> + 'a>;
32
33 fn rom_segments(&'a self, chip: Chip) -> Box<dyn Iterator<Item = CodeSegment<'a>> + 'a> {
35 Box::new(
36 self.segments()
37 .filter(move |segment| chip.into_target().addr_is_flash(segment.addr)),
38 )
39 }
40
41 fn ram_segments(&'a self, chip: Chip) -> Box<dyn Iterator<Item = CodeSegment<'a>> + 'a> {
43 Box::new(
44 self.segments()
45 .filter(move |segment| !chip.into_target().addr_is_flash(segment.addr)),
46 )
47 }
48}
49
50pub struct ElfFirmwareImage<'a> {
52 elf: ElfFile<'a>,
53}
54
55impl<'a> ElfFirmwareImage<'a> {
56 pub fn new(elf: ElfFile<'a>) -> Self {
57 Self { elf }
58 }
59}
60
61impl<'a> TryFrom<&'a [u8]> for ElfFirmwareImage<'a> {
62 type Error = Error;
63
64 fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
65 let elf = ElfFile::new(value).map_err(ElfError::from)?;
66
67 let image = ElfFirmwareImage::new(elf);
68
69 Ok(image)
70 }
71}
72
73impl<'a> FirmwareImage<'a> for ElfFirmwareImage<'a> {
74 fn entry(&self) -> u32 {
75 self.elf.header.pt2.entry_point() as u32
76 }
77
78 fn segments(&'a self) -> Box<dyn Iterator<Item = CodeSegment<'a>> + 'a> {
79 Box::new(
80 self.elf
81 .section_iter()
82 .filter(|header| {
83 header.size() > 0
84 && header.get_type() == Ok(ShType::ProgBits)
85 && header.offset() > 0
86 && header.address() > 0
87 })
88 .flat_map(move |header| {
89 let addr = header.address() as u32;
90 let data = match header.get_data(&self.elf) {
91 Ok(SectionData::Undefined(data)) => data,
92 _ => return None,
93 };
94 Some(CodeSegment::new(addr, data))
95 }),
96 )
97 }
98
99 fn segments_with_load_addresses(&'a self) -> Box<dyn Iterator<Item = CodeSegment<'a>> + 'a> {
100 Box::new(
101 self.elf
102 .program_iter()
103 .filter(|header| {
104 header.file_size() > 0
105 && header.get_type() == Ok(Type::Load)
106 && header.offset() > 0
107 })
108 .flat_map(move |header| {
109 let addr = header.physical_addr() as u32;
110 let from = header.offset() as usize;
111 let to = header.offset() as usize + header.file_size() as usize;
112 let data = &self.elf.input[from..to];
113 Some(CodeSegment::new(addr, data))
114 }),
115 )
116 }
117}
118
119#[derive(Eq, Clone, Default)]
120pub struct CodeSegment<'a> {
122 pub addr: u32,
124 data: Cow<'a, [u8]>,
125}
126
127impl<'a> CodeSegment<'a> {
128 pub fn new(addr: u32, data: &'a [u8]) -> Self {
129 let mut segment = CodeSegment {
130 addr,
131 data: Cow::Borrowed(data),
132 };
133 segment.pad_align(4);
134 segment
135 }
136
137 pub fn split_off(&mut self, count: usize) -> Self {
140 if count < self.data.len() {
141 let (head, tail) = match take(&mut self.data) {
142 Cow::Borrowed(data) => {
143 let (head, tail) = data.split_at(count);
144 (Cow::Borrowed(head), Cow::Borrowed(tail))
145 }
146 Cow::Owned(mut data) => {
147 let tail = data.split_off(count);
148 (Cow::Owned(data), Cow::Owned(tail))
149 }
150 };
151 let new = CodeSegment {
152 addr: self.addr,
153 data: head,
154 };
155 self.addr += count as u32;
156 self.data = tail;
157 new
158 } else {
159 let new = self.clone();
160 self.addr += self.size();
161 self.data = Cow::Borrowed(&[]);
162 new
163 }
164 }
165
166 pub fn size(&self) -> u32 {
168 self.data.len() as u32
169 }
170
171 pub fn data(&self) -> &[u8] {
173 self.data.as_ref()
174 }
175
176 pub fn pad_align(&mut self, align: usize) {
178 let padding = (align - self.data.len() % align) % align;
179 if padding > 0 {
180 let mut data = take(&mut self.data).into_owned();
181 data.extend_from_slice(&[0; 4][0..padding]);
182 self.data = Cow::Owned(data);
183 }
184 }
185}
186
187impl AddAssign<&'_ [u8]> for CodeSegment<'_> {
188 fn add_assign(&mut self, rhs: &'_ [u8]) {
189 let mut data = take(&mut self.data).into_owned();
190 data.extend_from_slice(rhs);
191 self.data = Cow::Owned(data);
192 }
193}
194
195impl AddAssign<&'_ CodeSegment<'_>> for CodeSegment<'_> {
196 fn add_assign(&mut self, rhs: &'_ CodeSegment<'_>) {
197 let mut data = take(&mut self.data).into_owned();
198 #[allow(clippy::suspicious_op_assign_impl)]
200 data.resize((rhs.addr - self.addr) as usize, 0);
201 data.extend_from_slice(rhs.data());
202 self.data = Cow::Owned(data);
203 }
204}
205
206impl Debug for CodeSegment<'_> {
207 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
208 f.debug_struct("CodeSegment")
209 .field("addr", &self.addr)
210 .field("size", &self.size())
211 .finish()
212 }
213}
214
215impl PartialEq for CodeSegment<'_> {
216 fn eq(&self, other: &Self) -> bool {
217 self.addr.eq(&other.addr)
218 }
219}
220
221impl PartialOrd for CodeSegment<'_> {
222 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
223 Some(self.cmp(other))
224 }
225}
226
227impl Ord for CodeSegment<'_> {
228 fn cmp(&self, other: &Self) -> Ordering {
229 self.addr.cmp(&other.addr)
230 }
231}
232
233#[derive(Clone)]
234pub struct RomSegment<'a> {
236 pub addr: u32,
238 pub data: Cow<'a, [u8]>,
240}
241
242impl<'a> RomSegment<'a> {
243 pub fn borrow<'b>(&'b self) -> RomSegment<'b>
244 where
245 'a: 'b,
246 {
247 RomSegment {
248 addr: self.addr,
249 data: Cow::Borrowed(self.data.as_ref()),
250 }
251 }
252}
253
254impl<'a> From<CodeSegment<'a>> for RomSegment<'a> {
255 fn from(segment: CodeSegment<'a>) -> Self {
256 RomSegment {
257 addr: segment.addr,
258 data: segment.data,
259 }
260 }
261}