1use std::{
2 backtrace::Backtrace,
3 collections::{BTreeMap, HashMap},
4 fmt::Display,
5 num::ParseIntError,
6 ops::Range,
7};
8
9use serde::Serialize;
10use snafu::Snafu;
11
12use crate::{
13 analysis::functions::Function,
14 util::{bytes::FromSlice, parse::parse_u32},
15};
16
17use super::{iter_attributes, module::Module, ParseContext};
18
19pub const DTCM_SECTION: &str = ".dtcm";
20
21#[derive(Clone, Copy)]
22pub struct SectionIndex(pub usize);
23
24#[derive(Clone)]
25pub struct Section {
26 name: String,
27 kind: SectionKind,
28 start_address: u32,
29 end_address: u32,
30 alignment: u32,
31 functions: BTreeMap<u32, Function>,
32}
33
34#[derive(Debug, Snafu)]
35pub enum SectionError {
36 #[snafu(display(
37 "Section {name} must not end ({end_address:#010x}) before it starts ({start_address:#010x}):\n{backtrace}"
38 ))]
39 EndBeforeStart { name: String, start_address: u32, end_address: u32, backtrace: Backtrace },
40 #[snafu(display("Section {name} aligment ({alignment}) must be a power of two:\n{backtrace}"))]
41 AlignmentPowerOfTwo { name: String, alignment: u32, backtrace: Backtrace },
42 #[snafu(display("Section {name} starts at a misaligned address {start_address:#010x}; the provided alignment was {alignment}:\n{backtrace}"))]
43 MisalignedStart { name: String, start_address: u32, alignment: u32, backtrace: Backtrace },
44}
45
46#[derive(Debug, Snafu)]
47pub enum SectionParseError {
48 #[snafu(transparent)]
49 SectionKind { source: SectionKindError },
50 #[snafu(display("{context}: failed to parse start address '{value}': {error}\n{backtrace}"))]
51 ParseStartAddress { context: ParseContext, value: String, error: ParseIntError, backtrace: Backtrace },
52 #[snafu(display("{context}: failed to parse end address '{value}': {error}\n{backtrace}"))]
53 ParseEndAddress { context: ParseContext, value: String, error: ParseIntError, backtrace: Backtrace },
54 #[snafu(display("{context}: failed to parse alignment '{value}': {error}\n{backtrace}"))]
55 ParseAlignment { context: ParseContext, value: String, error: ParseIntError, backtrace: Backtrace },
56 #[snafu(display(
57 "{context}: expected section attribute 'kind', 'start', 'end' or 'align' but got '{key}':\n{backtrace}"
58 ))]
59 UnknownAttribute { context: ParseContext, key: String, backtrace: Backtrace },
60 #[snafu(display("{context}: missing '{attribute}' attribute:\n{backtrace}"))]
61 MissingAttribute { context: ParseContext, attribute: String, backtrace: Backtrace },
62 #[snafu(display("{context}: {error}"))]
63 Section { context: ParseContext, error: SectionError },
64}
65
66#[derive(Debug, Snafu)]
67pub enum SectionInheritParseError {
68 #[snafu(display("{context}: section {name} does not exist in this file's header:\n{backtrace}"))]
69 NotInHeader { context: ParseContext, name: String, backtrace: Backtrace },
70 #[snafu(display("{context}: attribute '{attribute}' should be omitted as it is inherited from this file's header"))]
71 InheritedAttribute { context: ParseContext, attribute: String, backtrace: Backtrace },
72 #[snafu(transparent)]
73 SectionParse { source: SectionParseError },
74}
75
76#[derive(Debug, Snafu)]
77pub enum SectionCodeError {
78 #[snafu(display("section starts before base address:\n{backtrace}"))]
79 StartsBeforeBaseAddress { backtrace: Backtrace },
80 #[snafu(display("section ends after code ends:\n{backtrace}"))]
81 EndsOutsideModule { backtrace: Backtrace },
82}
83
84pub struct SectionOptions {
85 pub name: String,
86 pub kind: SectionKind,
87 pub start_address: u32,
88 pub end_address: u32,
89 pub alignment: u32,
90 pub functions: Option<BTreeMap<u32, Function>>,
91}
92
93impl Section {
94 pub fn new(options: SectionOptions) -> Result<Self, SectionError> {
95 let SectionOptions { name, kind, start_address, end_address, alignment, functions } = options;
96
97 if end_address < start_address {
98 return EndBeforeStartSnafu { name, start_address, end_address }.fail();
99 }
100 if !alignment.is_power_of_two() {
101 return AlignmentPowerOfTwoSnafu { name, alignment }.fail();
102 }
103 let misalign_mask = alignment - 1;
104 if (start_address & misalign_mask) != 0 {
105 return MisalignedStartSnafu { name, start_address, alignment }.fail();
106 }
107
108 let functions = functions.unwrap_or_else(BTreeMap::new);
109
110 Ok(Self { name, kind, start_address, end_address, alignment, functions })
111 }
112
113 pub fn inherit(other: &Section, start_address: u32, end_address: u32) -> Result<Self, SectionError> {
114 if end_address < start_address {
115 return EndBeforeStartSnafu { name: other.name.clone(), start_address, end_address }.fail();
116 }
117 Ok(Self {
118 name: other.name.clone(),
119 kind: other.kind,
120 start_address,
121 end_address,
122 alignment: other.alignment,
123 functions: BTreeMap::new(),
124 })
125 }
126
127 pub(crate) fn parse(line: &str, context: &ParseContext) -> Result<Option<Self>, SectionParseError> {
128 let mut words = line.split_whitespace();
129 let Some(name) = words.next() else { return Ok(None) };
130
131 let mut kind = None;
132 let mut start = None;
133 let mut end = None;
134 let mut align = None;
135 for (key, value) in iter_attributes(words) {
136 match key {
137 "kind" => kind = Some(SectionKind::parse(value, context)?),
138 "start" => {
139 start = Some(parse_u32(value).map_err(|error| ParseStartAddressSnafu { context, value, error }.build())?)
140 }
141 "end" => end = Some(parse_u32(value).map_err(|error| ParseEndAddressSnafu { context, value, error }.build())?),
142 "align" => {
143 align = Some(parse_u32(value).map_err(|error| ParseAlignmentSnafu { context, value, error }.build())?)
144 }
145 _ => return UnknownAttributeSnafu { context: context.clone(), key }.fail(),
146 }
147 }
148
149 let kind = kind.ok_or_else(|| MissingAttributeSnafu { context, attribute: "kind" }.build())?;
150 let start_address = start.ok_or_else(|| MissingAttributeSnafu { context, attribute: "start" }.build())?;
151 let end_address = end.ok_or_else(|| MissingAttributeSnafu { context, attribute: "end" }.build())?;
152 let alignment = align.ok_or_else(|| MissingAttributeSnafu { context, attribute: "align" }.build())?;
153
154 Ok(Some(
155 Section::new(SectionOptions {
156 name: name.to_string(),
157 kind,
158 start_address,
159 end_address,
160 alignment,
161 functions: None,
162 })
163 .map_err(|error| SectionSnafu { context, error }.build())?,
164 ))
165 }
166
167 pub(crate) fn parse_inherit(
168 line: &str,
169 context: &ParseContext,
170 sections: &Sections,
171 ) -> Result<Option<Self>, SectionInheritParseError> {
172 let mut words = line.split_whitespace();
173 let Some(name) = words.next() else { return Ok(None) };
174
175 let inherit_section = if name != DTCM_SECTION {
176 Some(
177 sections
178 .by_name(name)
179 .map(|(_, section)| section)
180 .ok_or_else(|| NotInHeaderSnafu { context, name }.build())?,
181 )
182 } else {
183 None
184 };
185
186 let mut start = None;
187 let mut end = None;
188 for (key, value) in iter_attributes(words) {
189 match key {
190 "kind" => return InheritedAttributeSnafu { context, attribute: "kind" }.fail(),
191 "start" => {
192 start = Some(parse_u32(value).map_err(|error| ParseStartAddressSnafu { context, value, error }.build())?)
193 }
194 "end" => end = Some(parse_u32(value).map_err(|error| ParseEndAddressSnafu { context, value, error }.build())?),
195 "align" => return InheritedAttributeSnafu { context, attribute: "align" }.fail(),
196 _ => return UnknownAttributeSnafu { context, key }.fail()?,
197 }
198 }
199
200 let start = start.ok_or_else(|| MissingAttributeSnafu { context, attribute: "start" }.build())?;
201 let end = end.ok_or_else(|| MissingAttributeSnafu { context, attribute: "end" }.build())?;
202
203 if name == DTCM_SECTION {
204 Ok(Some(Section {
205 name: name.to_string(),
206 kind: SectionKind::Bss,
207 start_address: start,
208 end_address: end,
209 alignment: 4,
210 functions: BTreeMap::new(),
211 }))
212 } else {
213 let inherit_section = inherit_section.unwrap();
214 Ok(Some(Section::inherit(inherit_section, start, end).map_err(|error| SectionSnafu { context, error }.build())?))
215 }
216 }
217
218 pub fn code_from_module<'a>(&'a self, module: &'a Module) -> Result<Option<&'a [u8]>, SectionCodeError> {
219 self.code(module.code(), module.base_address())
220 }
221
222 pub fn code<'a>(&'a self, code: &'a [u8], base_address: u32) -> Result<Option<&'a [u8]>, SectionCodeError> {
223 if self.kind() == SectionKind::Bss {
224 return Ok(None);
225 }
226 if self.start_address() < base_address {
227 return StartsBeforeBaseAddressSnafu.fail();
228 }
229 let start = self.start_address() - base_address;
230 let end = self.end_address() - base_address;
231 if end > code.len() as u32 {
232 return EndsOutsideModuleSnafu.fail();
233 }
234 Ok(Some(&code[start as usize..end as usize]))
235 }
236
237 pub fn size(&self) -> u32 {
238 self.end_address - self.start_address
239 }
240
241 pub fn iter_words<'a>(&'a self, code: &'a [u8], range: Option<Range<u32>>) -> impl Iterator<Item = Word> + 'a {
244 let range = range.unwrap_or(self.address_range());
245 let start = range.start.next_multiple_of(4);
246 let end = range.end & !3;
247
248 (start..end).step_by(4).map(move |address| {
249 let offset = address - self.start_address();
250 let bytes = &code[offset as usize..];
251 Word { address, value: u32::from_le_slice(bytes) }
252 })
253 }
254
255 pub fn name(&self) -> &str {
256 &self.name
257 }
258
259 pub fn kind(&self) -> SectionKind {
260 self.kind
261 }
262
263 pub fn start_address(&self) -> u32 {
264 self.start_address
265 }
266
267 pub fn end_address(&self) -> u32 {
268 self.end_address
269 }
270
271 pub fn address_range(&self) -> Range<u32> {
272 self.start_address..self.end_address
273 }
274
275 pub fn alignment(&self) -> u32 {
276 self.alignment
277 }
278
279 pub fn overlaps_with(&self, other: &Section) -> bool {
280 self.start_address < other.end_address && other.start_address < self.end_address
281 }
282
283 pub fn functions(&self) -> &BTreeMap<u32, Function> {
284 &self.functions
285 }
286
287 pub fn functions_mut(&mut self) -> &mut BTreeMap<u32, Function> {
288 &mut self.functions
289 }
290
291 pub fn add_function(&mut self, function: Function) {
292 self.functions.insert(function.start_address(), function);
293 }
294}
295
296impl Display for Section {
297 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
298 write!(
299 f,
300 "{:11} start:{:#010x} end:{:#010x} kind:{} align:{}",
301 self.name, self.start_address, self.end_address, self.kind, self.alignment
302 )?;
303
304 Ok(())
305 }
306}
307
308#[derive(PartialEq, Eq, Clone, Copy, Serialize)]
309pub enum SectionKind {
310 Code,
311 Data,
312 Rodata,
313 Bss,
314 }
317
318#[derive(Debug, Snafu)]
319pub enum SectionKindError {
320 #[snafu(display("{context}: unknown section kind '{value}', must be one of: code, data, bss"))]
321 UnknownKind { context: ParseContext, value: String, backtrace: Backtrace },
322}
323
324impl SectionKind {
325 pub fn parse(value: &str, context: &ParseContext) -> Result<Self, SectionKindError> {
326 match value {
327 "code" => Ok(Self::Code),
328 "data" => Ok(Self::Data),
329 "rodata" => Ok(Self::Rodata),
330 "bss" => Ok(Self::Bss),
331 _ => UnknownKindSnafu { context, value }.fail(),
332 }
333 }
334
335 pub fn is_initialized(self) -> bool {
336 match self {
337 SectionKind::Code => true,
338 SectionKind::Data => true,
339 SectionKind::Rodata => true,
340 SectionKind::Bss => false,
341 }
342 }
343
344 pub fn is_writeable(self) -> bool {
345 match self {
346 SectionKind::Code => false,
347 SectionKind::Data => true,
348 SectionKind::Rodata => false,
349 SectionKind::Bss => true,
350 }
351 }
352
353 pub fn is_executable(self) -> bool {
354 match self {
355 SectionKind::Code => true,
356 SectionKind::Data => false,
357 SectionKind::Rodata => false,
358 SectionKind::Bss => false,
359 }
360 }
361}
362
363impl Display for SectionKind {
364 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
365 match self {
366 Self::Code => write!(f, "code"),
367 Self::Data => write!(f, "data"),
368 Self::Rodata => write!(f, "rodata"),
369 Self::Bss => write!(f, "bss"),
370 }
371 }
372}
373
374pub struct Sections {
375 sections: Vec<Section>,
376 sections_by_name: HashMap<String, SectionIndex>,
377}
378
379#[derive(Debug, Snafu)]
380pub enum SectionsError {
381 #[snafu(display("Section '{name}' already exists:\n{backtrace}"))]
382 DuplicateName { name: String, backtrace: Backtrace },
383 #[snafu(display("Section '{name}' overlaps with '{other_name}':\n{backtrace}"))]
384 Overlapping { name: String, other_name: String, backtrace: Backtrace },
385}
386
387impl Sections {
388 pub fn new() -> Self {
389 Self { sections: vec![], sections_by_name: HashMap::new() }
390 }
391
392 pub fn from_sections(section_vec: Vec<Section>) -> Result<Self, SectionsError> {
393 let mut sections = Self::new();
394 for section in section_vec {
395 sections.add(section)?;
396 }
397 Ok(sections)
398 }
399
400 pub fn add(&mut self, section: Section) -> Result<SectionIndex, SectionsError> {
401 if self.sections_by_name.contains_key(§ion.name) {
402 return DuplicateNameSnafu { name: section.name }.fail();
403 }
404 for other in &self.sections {
405 if section.overlaps_with(other) {
406 return OverlappingSnafu { name: section.name, other_name: other.name.to_string() }.fail();
407 }
408 }
409
410 let index = SectionIndex(self.sections.len());
411 self.sections_by_name.insert(section.name.clone(), index);
412 self.sections.push(section);
413 Ok(index)
414 }
415
416 pub fn remove(&mut self, name: &str) {
417 let Some(index) = self.sections_by_name.remove(name) else {
418 return;
419 };
420 self.sections.remove(index.0);
421 for (i, section) in self.sections.iter().enumerate() {
423 self.sections_by_name.insert(section.name.clone(), SectionIndex(i));
424 }
425 }
426
427 pub fn get(&self, index: SectionIndex) -> &Section {
428 &self.sections[index.0]
429 }
430
431 pub fn get_mut(&mut self, index: SectionIndex) -> &mut Section {
432 &mut self.sections[index.0]
433 }
434
435 pub fn by_name(&self, name: &str) -> Option<(SectionIndex, &Section)> {
436 let &index = self.sections_by_name.get(name)?;
437 Some((index, &self.sections[index.0]))
438 }
439
440 pub fn iter(&self) -> impl Iterator<Item = &Section> {
441 self.sections.iter()
442 }
443
444 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Section> {
445 self.sections.iter_mut()
446 }
447
448 pub fn len(&self) -> usize {
449 self.sections.len()
450 }
451
452 pub fn get_by_contained_address(&self, address: u32) -> Option<(SectionIndex, &Section)> {
453 self.sections
454 .iter()
455 .enumerate()
456 .find(|(_, s)| address >= s.start_address && address < s.end_address)
457 .map(|(i, s)| (SectionIndex(i), s))
458 }
459
460 pub fn get_by_contained_address_mut(&mut self, address: u32) -> Option<(SectionIndex, &mut Section)> {
461 self.sections
462 .iter_mut()
463 .enumerate()
464 .find(|(_, s)| address >= s.start_address && address < s.end_address)
465 .map(|(i, s)| (SectionIndex(i), s))
466 }
467
468 pub fn add_function(&mut self, function: Function) {
469 let address = function.first_instruction_address();
470 self.sections
471 .iter_mut()
472 .find(|s| address >= s.start_address && address < s.end_address)
473 .unwrap()
474 .functions
475 .insert(address, function);
476 }
477
478 pub fn sorted_by_address(&self) -> Vec<&Section> {
479 let mut sections = self.sections.iter().collect::<Vec<_>>();
480 sections.sort_unstable_by(|a, b| a.start_address.cmp(&b.start_address).then(a.end_address.cmp(&b.end_address)));
481 sections
482 }
483
484 pub fn functions(&self) -> impl Iterator<Item = &Function> {
485 self.sections.iter().flat_map(|s| s.functions.values())
486 }
487
488 pub fn functions_mut(&mut self) -> impl Iterator<Item = &mut Function> {
489 self.sections.iter_mut().flat_map(|s| s.functions.values_mut())
490 }
491
492 pub fn base_address(&self) -> Option<u32> {
493 self.sections.iter().map(|s| s.start_address).min()
494 }
495
496 pub fn end_address(&self) -> Option<u32> {
497 self.sections.iter().map(|s| s.end_address).max()
498 }
499
500 pub fn text_size(&self) -> u32 {
501 self.sections.iter().filter(|s| s.kind != SectionKind::Bss).map(|s| s.size()).sum()
502 }
503
504 pub fn bss_size(&self) -> u32 {
505 self.sections.iter().filter(|s| s.kind == SectionKind::Bss).map(|s| s.size()).sum()
506 }
507
508 pub fn bss_range(&self) -> Option<Range<u32>> {
509 self.sections
510 .iter()
511 .filter(|s| s.kind == SectionKind::Bss)
512 .map(|s| s.address_range())
513 .reduce(|a, b| a.start.min(b.start)..a.end.max(b.end))
514 }
515
516 pub fn get_section_after(&self, text_end: u32) -> Option<&Section> {
517 self.sorted_by_address().iter().copied().find(|s| s.start_address >= text_end)
518 }
519}
520
521impl IntoIterator for Sections {
522 type Item = Section;
523
524 type IntoIter = <Vec<Self::Item> as IntoIterator>::IntoIter;
525
526 fn into_iter(self) -> Self::IntoIter {
527 self.sections.into_iter()
528 }
529}
530
531pub struct Word {
532 pub address: u32,
533 pub value: u32,
534}