1use std::{
2 backtrace::Backtrace,
3 borrow::Cow,
4 collections::{BTreeMap, HashMap},
5 fmt::Display,
6 num::ParseIntError,
7 ops::Range,
8};
9
10use ds_rom::rom::raw::AutoloadKind;
11use serde::Serialize;
12use snafu::Snafu;
13
14use super::{ParseContext, iter_attributes, module::Module};
15use crate::{
16 analysis::functions::Function,
17 config::{CommentedLine, Comments, module::ModuleKind},
18 util::{bytes::FromSlice, parse::parse_u32},
19};
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 comments: Comments,
33 migration_to: Option<MigrateSection>,
35}
36
37#[derive(Debug, Snafu)]
38pub enum SectionError {
39 #[snafu(display(
40 "Section {name} must not end ({end_address:#010x}) before it starts ({start_address:#010x}):\n{backtrace}"
41 ))]
42 EndBeforeStart { name: String, start_address: u32, end_address: u32, backtrace: Backtrace },
43 #[snafu(display("Section {name} aligment ({alignment}) must be a power of two:\n{backtrace}"))]
44 AlignmentPowerOfTwo { name: String, alignment: u32, backtrace: Backtrace },
45 #[snafu(display(
46 "Section {name} starts at a misaligned address {start_address:#010x}; the provided alignment was {alignment}:\n{backtrace}"
47 ))]
48 MisalignedStart { name: String, start_address: u32, alignment: u32, backtrace: Backtrace },
49}
50
51#[derive(Debug, Snafu)]
52pub enum SectionParseError {
53 #[snafu(display("{context}: expected section, got empty line"))]
54 EmptyLine { context: ParseContext },
55 #[snafu(transparent)]
56 SectionKind { source: SectionKindError },
57 #[snafu(display("{context}: failed to parse start address '{value}': {error}\n{backtrace}"))]
58 ParseStartAddress {
59 context: ParseContext,
60 value: String,
61 error: ParseIntError,
62 backtrace: Backtrace,
63 },
64 #[snafu(display("{context}: failed to parse end address '{value}': {error}\n{backtrace}"))]
65 ParseEndAddress {
66 context: ParseContext,
67 value: String,
68 error: ParseIntError,
69 backtrace: Backtrace,
70 },
71 #[snafu(display("{context}: failed to parse alignment '{value}': {error}\n{backtrace}"))]
72 ParseAlignment {
73 context: ParseContext,
74 value: String,
75 error: ParseIntError,
76 backtrace: Backtrace,
77 },
78 #[snafu(display(
79 "{context}: expected section attribute 'kind', 'start', 'end' or 'align' but got '{key}':\n{backtrace}"
80 ))]
81 UnknownAttribute { context: ParseContext, key: String, backtrace: Backtrace },
82 #[snafu(display("{context}: missing '{attribute}' attribute:\n{backtrace}"))]
83 MissingAttribute { context: ParseContext, attribute: String, backtrace: Backtrace },
84 #[snafu(display("{context}: {error}"))]
85 Section { context: ParseContext, error: Box<SectionError> },
86}
87
88#[derive(Debug, Snafu)]
89pub enum SectionInheritParseError {
90 #[snafu(display(
91 "{context}: section {name} does not exist in this file's header:\n{backtrace}"
92 ))]
93 NotInHeader { context: ParseContext, name: String, backtrace: Backtrace },
94 #[snafu(display(
95 "{context}: attribute '{attribute}' should be omitted as it is inherited from this file's header"
96 ))]
97 InheritedAttribute { context: ParseContext, attribute: String, backtrace: Backtrace },
98 #[snafu(transparent)]
99 SectionParse { source: SectionParseError },
100 #[snafu(transparent)]
101 Section { source: SectionError },
102 #[snafu(transparent)]
103 MigrateSection { source: MigrateSectionError },
104}
105
106#[derive(Debug, Snafu)]
107pub enum SectionCodeError {
108 #[snafu(display(
109 "section {name} starts at {actual:#010x} before base address {expected:#010x}:\n{backtrace}"
110 ))]
111 StartsBeforeBaseAddress { name: String, actual: u32, expected: u32, backtrace: Backtrace },
112 #[snafu(display("section ends after code ends:\n{backtrace}"))]
113 EndsOutsideModule { backtrace: Backtrace },
114}
115
116pub struct SectionOptions {
117 pub name: String,
118 pub kind: SectionKind,
119 pub start_address: u32,
120 pub end_address: u32,
121 pub alignment: u32,
122 pub functions: Option<BTreeMap<u32, Function>>,
123 pub comments: Comments,
124}
125
126pub struct SectionInheritOptions {
127 pub start_address: u32,
128 pub end_address: u32,
129 pub comments: Comments,
130 pub migration: Option<MigrateSection>,
131}
132
133impl Section {
134 pub fn new(options: SectionOptions) -> Result<Self, SectionError> {
135 let SectionOptions {
136 name,
137 kind,
138 start_address,
139 end_address,
140 alignment,
141 functions,
142 comments,
143 } = options;
144
145 if end_address < start_address {
146 return EndBeforeStartSnafu { name, start_address, end_address }.fail();
147 }
148 if !alignment.is_power_of_two() {
149 return AlignmentPowerOfTwoSnafu { name, alignment }.fail();
150 }
151 let misalign_mask = alignment - 1;
152 if (start_address & misalign_mask) != 0 {
153 return MisalignedStartSnafu { name, start_address, alignment }.fail();
154 }
155
156 let functions = functions.unwrap_or_else(BTreeMap::new);
157
158 Ok(Self {
159 name,
160 kind,
161 start_address,
162 end_address,
163 alignment,
164 functions,
165 comments,
166 migration_to: None,
167 })
168 }
169
170 pub fn inherit(other: &Section, options: SectionInheritOptions) -> Result<Self, SectionError> {
171 let SectionInheritOptions { start_address, end_address, comments, migration } = options;
172
173 if end_address < start_address {
174 return EndBeforeStartSnafu { name: other.name.clone(), start_address, end_address }
175 .fail();
176 }
177 Ok(Self {
178 name: other.name.clone(),
179 kind: other.kind,
180 start_address,
181 end_address,
182 alignment: other.alignment,
183 functions: BTreeMap::new(),
184 comments,
185 migration_to: migration,
186 })
187 }
188
189 pub(crate) fn parse(
190 line: &CommentedLine,
191 context: &ParseContext,
192 ) -> Result<Self, SectionParseError> {
193 let mut words = line.text.split_whitespace();
194 let Some(name) = words.next() else {
195 return EmptyLineSnafu { context: context.clone() }.fail();
196 };
197
198 let mut kind = None;
199 let mut start = None;
200 let mut end = None;
201 let mut align = None;
202 for (key, value) in iter_attributes(words) {
203 match key {
204 "kind" => kind = Some(SectionKind::parse(value, context)?),
205 "start" => {
206 start = Some(parse_u32(value).map_err(|error| {
207 ParseStartAddressSnafu { context, value, error }.build()
208 })?);
209 }
210 "end" => {
211 end =
212 Some(parse_u32(value).map_err(|error| {
213 ParseEndAddressSnafu { context, value, error }.build()
214 })?)
215 }
216 "align" => {
217 align =
218 Some(parse_u32(value).map_err(|error| {
219 ParseAlignmentSnafu { context, value, error }.build()
220 })?);
221 }
222 _ => return UnknownAttributeSnafu { context: context.clone(), key }.fail(),
223 }
224 }
225
226 let kind =
227 kind.ok_or_else(|| MissingAttributeSnafu { context, attribute: "kind" }.build())?;
228 let start_address =
229 start.ok_or_else(|| MissingAttributeSnafu { context, attribute: "start" }.build())?;
230 let end_address =
231 end.ok_or_else(|| MissingAttributeSnafu { context, attribute: "end" }.build())?;
232 let alignment =
233 align.ok_or_else(|| MissingAttributeSnafu { context, attribute: "align" }.build())?;
234
235 Section::new(SectionOptions {
236 name: name.to_string(),
237 kind,
238 start_address,
239 end_address,
240 alignment,
241 functions: None,
242 comments: line.comments.clone(),
243 })
244 .map_err(|error| SectionSnafu { context, error }.build())
245 }
246
247 pub(crate) fn parse_inherit(
248 line: &CommentedLine,
249 context: &ParseContext,
250 sections: &Sections,
251 ) -> Result<Self, SectionInheritParseError> {
252 let mut words = line.text.split_whitespace();
253 let Some(name) = words.next() else {
254 return EmptyLineSnafu { context: context.clone() }.fail()?;
255 };
256
257 let migrate_section = MigrateSection::parse(name)?;
258
259 let inherit_section = match migrate_section {
260 None => Some(
261 sections
262 .by_name(name)
263 .map(|(_, section)| section)
264 .ok_or_else(|| NotInHeaderSnafu { context, name }.build())?,
265 ),
266 Some(_) => None,
267 };
268
269 let mut start = None;
270 let mut end = None;
271 for (key, value) in iter_attributes(words) {
272 match key {
273 "kind" => return InheritedAttributeSnafu { context, attribute: "kind" }.fail(),
274 "start" => {
275 start = Some(parse_u32(value).map_err(|error| {
276 ParseStartAddressSnafu { context, value, error }.build()
277 })?);
278 }
279 "end" => {
280 end =
281 Some(parse_u32(value).map_err(|error| {
282 ParseEndAddressSnafu { context, value, error }.build()
283 })?)
284 }
285 "align" => return InheritedAttributeSnafu { context, attribute: "align" }.fail(),
286 _ => return UnknownAttributeSnafu { context, key }.fail()?,
287 }
288 }
289
290 let start =
291 start.ok_or_else(|| MissingAttributeSnafu { context, attribute: "start" }.build())?;
292 let end = end.ok_or_else(|| MissingAttributeSnafu { context, attribute: "end" }.build())?;
293
294 match migrate_section {
295 None => {
296 let inherit_section = inherit_section.unwrap();
297 Ok(Section::inherit(inherit_section, SectionInheritOptions {
298 start_address: start,
299 end_address: end,
300 comments: line.comments.clone(),
301 migration: None,
302 })
303 .map_err(|error| SectionSnafu { context, error }.build())?)
304 }
305 Some(migrate_section) => Ok(Section::new(SectionOptions {
306 name: name.to_string(),
307 kind: migrate_section.section_kind(),
308 start_address: start,
309 end_address: end,
310 alignment: 4,
311 functions: None,
312 comments: line.comments.clone(),
313 })?),
314 }
315 }
316
317 pub fn code_from_module<'a>(
318 &'a self,
319 module: &'a Module,
320 ) -> Result<Option<&'a [u8]>, SectionCodeError> {
321 self.code(module.code(), module.base_address())
322 }
323
324 pub fn code<'a>(
325 &'a self,
326 code: &'a [u8],
327 base_address: u32,
328 ) -> Result<Option<&'a [u8]>, SectionCodeError> {
329 if self.kind() == SectionKind::Bss {
330 return Ok(None);
331 }
332 if self.start_address() < base_address {
333 return StartsBeforeBaseAddressSnafu {
334 name: self.name.clone(),
335 actual: self.start_address(),
336 expected: base_address,
337 }
338 .fail();
339 }
340 let start = self.start_address() - base_address;
341 let end = self.end_address() - base_address;
342 if end as usize > code.len() {
343 return EndsOutsideModuleSnafu.fail();
344 }
345 Ok(Some(&code[start as usize..end as usize]))
346 }
347
348 pub fn size(&self) -> u32 {
349 self.end_address - self.start_address
350 }
351
352 pub fn iter_words<'a>(
355 &'a self,
356 code: &'a [u8],
357 range: Option<Range<u32>>,
358 ) -> impl Iterator<Item = Word> + 'a {
359 let range = range.unwrap_or(self.address_range());
360 let start = range.start.next_multiple_of(4);
361 let end = range.end & !3;
362
363 (start..end).step_by(4).map(move |address| {
364 let offset = address - self.start_address();
365 let bytes = &code[offset as usize..];
366 Word { address, value: u32::from_le_slice(bytes) }
367 })
368 }
369
370 pub fn name(&self) -> &str {
371 &self.name
372 }
373
374 pub fn kind(&self) -> SectionKind {
375 self.kind
376 }
377
378 pub fn start_address(&self) -> u32 {
379 self.start_address
380 }
381
382 pub fn set_start_address(&mut self, start_address: u32) {
383 self.start_address = start_address;
384 }
385
386 pub fn end_address(&self) -> u32 {
387 self.end_address
388 }
389
390 pub fn set_end_address(&mut self, end_address: u32) {
391 self.end_address = end_address;
392 }
393
394 pub fn address_range(&self) -> Range<u32> {
395 self.start_address..self.end_address
396 }
397
398 pub fn alignment(&self) -> u32 {
399 self.alignment
400 }
401
402 pub fn set_alignment(&mut self, alignment: u32) {
403 self.alignment = alignment;
404 }
405
406 pub fn overlaps_with(&self, other: &Section) -> bool {
407 self.start_address < other.end_address && other.start_address < self.end_address
408 }
409
410 pub fn functions(&self) -> &BTreeMap<u32, Function> {
411 &self.functions
412 }
413
414 pub fn functions_mut(&mut self) -> &mut BTreeMap<u32, Function> {
415 &mut self.functions
416 }
417
418 pub fn add_function(&mut self, function: Function) {
419 self.functions.insert(function.start_address(), function);
420 }
421
422 pub(crate) fn write_inherit(&self, f: &mut impl std::fmt::Write) -> std::fmt::Result {
423 write!(f, "{}", self.comments.display_pre_comments())?;
424 write!(
425 f,
426 " {:11} start:{:#010x} end:{:#010x}",
427 self.name, self.start_address, self.end_address
428 )?;
429 write!(f, "{}", self.comments.display_post_comment())?;
430
431 Ok(())
432 }
433
434 pub fn source_name(&self) -> Cow<'_, str> {
435 if let Some(migration) = &self.migration_to {
436 migration.source_name()
437 } else {
438 Cow::Borrowed(&self.name)
439 }
440 }
441
442 pub fn migration(&self) -> Option<MigrateSection> {
443 self.migration_to
444 }
445}
446
447impl Display for Section {
448 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
449 write!(f, "{}", self.comments.display_pre_comments())?;
450 write!(
451 f,
452 " {:11} start:{:#010x} end:{:#010x} kind:{} align:{}",
453 self.name, self.start_address, self.end_address, self.kind, self.alignment
454 )?;
455 write!(f, "{}", self.comments.display_post_comment())?;
456
457 Ok(())
458 }
459}
460
461#[derive(PartialEq, Eq, Clone, Copy)]
462pub enum MigrateSection {
463 Dtcm,
464 Itcm,
465 AutoloadData(u32),
466 AutoloadBss(u32),
467}
468
469const DTCM_SECTION: &str = ".dtcm";
470const ITCM_SECTION: &str = ".itcm";
471const AUTOLOAD_DATA_SECTION_PREFIX: &str = ".autodata_";
472const AUTOLOAD_BSS_SECTION_PREFIX: &str = ".autobss_";
473
474#[derive(Debug, Snafu)]
475pub enum MigrateSectionError {
476 #[snafu(display("Failed to parse autoload index from section '{name}': {error}\n{backtrace}"))]
477 InvalidAutoloadIndex { name: String, error: ParseIntError, backtrace: Backtrace },
478}
479
480impl MigrateSection {
481 pub fn parse(name: &str) -> Result<Option<Self>, MigrateSectionError> {
482 match name {
483 DTCM_SECTION => Ok(Some(Self::Dtcm)),
484 ITCM_SECTION => Ok(Some(Self::Itcm)),
485 _ => {
486 if let Some(index) = name.strip_prefix(AUTOLOAD_DATA_SECTION_PREFIX) {
487 let index: u32 = index.parse().map_err(|error| {
488 InvalidAutoloadIndexSnafu { name: name.to_string(), error }.build()
489 })?;
490 Ok(Some(Self::AutoloadData(index)))
491 } else if let Some(index) = name.strip_prefix(AUTOLOAD_BSS_SECTION_PREFIX) {
492 let index: u32 = index.parse().map_err(|error| {
493 InvalidAutoloadIndexSnafu { name: name.to_string(), error }.build()
494 })?;
495 Ok(Some(Self::AutoloadBss(index)))
496 } else {
497 Ok(None)
498 }
499 }
500 }
501 }
502
503 pub fn source_name(&self) -> Cow<'static, str> {
504 match self {
505 MigrateSection::Dtcm => DTCM_SECTION.into(),
506 MigrateSection::Itcm => ITCM_SECTION.into(),
507 MigrateSection::AutoloadData(index) => {
508 format!("{AUTOLOAD_DATA_SECTION_PREFIX}{index}").into()
509 }
510 MigrateSection::AutoloadBss(index) => {
511 format!("{AUTOLOAD_BSS_SECTION_PREFIX}{index}").into()
512 }
513 }
514 }
515
516 pub fn target_name(&self) -> &str {
517 match self {
518 MigrateSection::Dtcm => ".bss",
519 MigrateSection::Itcm => ".text",
520 MigrateSection::AutoloadData(_) => ".data",
521 MigrateSection::AutoloadBss(_) => ".bss",
522 }
523 }
524
525 pub fn sections_to_migrate(module_kind: ModuleKind) -> Vec<MigrateSection> {
526 match module_kind {
527 ModuleKind::Arm9 => vec![],
528 ModuleKind::Overlay(_) => vec![],
529 ModuleKind::Autoload(AutoloadKind::Dtcm) => vec![MigrateSection::Dtcm],
530 ModuleKind::Autoload(AutoloadKind::Itcm) => vec![MigrateSection::Itcm],
531 ModuleKind::Autoload(AutoloadKind::Unknown(index)) => {
532 vec![MigrateSection::AutoloadData(index), MigrateSection::AutoloadBss(index)]
533 }
534 }
535 }
536
537 pub fn section_kind(&self) -> SectionKind {
538 match self {
539 MigrateSection::Dtcm => SectionKind::Bss,
540 MigrateSection::Itcm => SectionKind::Code,
541 MigrateSection::AutoloadData(_) => SectionKind::Data,
542 MigrateSection::AutoloadBss(_) => SectionKind::Bss,
543 }
544 }
545
546 pub fn module_kind(&self) -> ModuleKind {
547 match self {
548 MigrateSection::Dtcm => ModuleKind::Autoload(AutoloadKind::Dtcm),
549 MigrateSection::Itcm => ModuleKind::Autoload(AutoloadKind::Itcm),
550 MigrateSection::AutoloadData(index) | MigrateSection::AutoloadBss(index) => {
551 ModuleKind::Autoload(AutoloadKind::Unknown(*index))
552 }
553 }
554 }
555}
556
557#[derive(PartialEq, Eq, Clone, Copy, Serialize)]
558pub enum SectionKind {
559 Code,
560 Data,
561 Rodata,
562 Bss,
563 }
566
567#[derive(Debug, Snafu)]
568pub enum SectionKindError {
569 #[snafu(display("{context}: unknown section kind '{value}', must be one of: code, data, bss"))]
570 UnknownKind { context: ParseContext, value: String, backtrace: Backtrace },
571}
572
573impl SectionKind {
574 pub fn parse(value: &str, context: &ParseContext) -> Result<Self, SectionKindError> {
575 match value {
576 "code" => Ok(Self::Code),
577 "data" => Ok(Self::Data),
578 "rodata" => Ok(Self::Rodata),
579 "bss" => Ok(Self::Bss),
580 _ => UnknownKindSnafu { context, value }.fail(),
581 }
582 }
583
584 pub fn is_initialized(self) -> bool {
585 match self {
586 SectionKind::Code => true,
587 SectionKind::Data => true,
588 SectionKind::Rodata => true,
589 SectionKind::Bss => false,
590 }
591 }
592
593 pub fn is_writeable(self) -> bool {
594 match self {
595 SectionKind::Code => false,
596 SectionKind::Data => true,
597 SectionKind::Rodata => false,
598 SectionKind::Bss => true,
599 }
600 }
601
602 pub fn is_executable(self) -> bool {
603 match self {
604 SectionKind::Code => true,
605 SectionKind::Data => false,
606 SectionKind::Rodata => false,
607 SectionKind::Bss => false,
608 }
609 }
610}
611
612impl Display for SectionKind {
613 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
614 match self {
615 Self::Code => write!(f, "code"),
616 Self::Data => write!(f, "data"),
617 Self::Rodata => write!(f, "rodata"),
618 Self::Bss => write!(f, "bss"),
619 }
620 }
621}
622
623#[derive(Clone)]
624pub struct Sections {
625 sections: Vec<Section>,
626 sections_by_name: HashMap<String, SectionIndex>,
627}
628
629#[derive(Debug, Snafu)]
630pub enum SectionsError {
631 #[snafu(display("Section '{name}' already exists:\n{backtrace}"))]
632 DuplicateName { name: String, backtrace: Backtrace },
633 #[snafu(display("Section '{name}' overlaps with '{other_name}':\n{backtrace}"))]
634 Overlapping { name: String, other_name: String, backtrace: Backtrace },
635}
636
637impl Sections {
638 pub fn new() -> Self {
639 Self { sections: vec![], sections_by_name: HashMap::new() }
640 }
641
642 pub fn from_sections(section_vec: Vec<Section>) -> Result<Self, SectionsError> {
643 let mut sections = Self::new();
644 for section in section_vec {
645 sections.add(section)?;
646 }
647 Ok(sections)
648 }
649
650 pub fn add(&mut self, section: Section) -> Result<SectionIndex, SectionsError> {
651 if self.sections_by_name.contains_key(§ion.name) {
652 return DuplicateNameSnafu { name: section.name }.fail();
653 }
654 for other in &self.sections {
655 if section.overlaps_with(other) {
656 return OverlappingSnafu { name: section.name, other_name: other.name.clone() }
657 .fail();
658 }
659 }
660
661 let index = SectionIndex(self.sections.len());
662 self.sections_by_name.insert(section.name.clone(), index);
663 self.sections.push(section);
664 Ok(index)
665 }
666
667 pub fn remove(&mut self, name: &str) -> Option<Section> {
668 let index = self.sections_by_name.remove(name)?;
669 let section = self.sections.remove(index.0);
670 for (i, section) in self.sections.iter().enumerate() {
672 self.sections_by_name.insert(section.name.clone(), SectionIndex(i));
673 }
674 Some(section)
675 }
676
677 pub fn get(&self, index: SectionIndex) -> &Section {
678 &self.sections[index.0]
679 }
680
681 pub fn get_mut(&mut self, index: SectionIndex) -> &mut Section {
682 &mut self.sections[index.0]
683 }
684
685 pub fn by_name(&self, name: &str) -> Option<(SectionIndex, &Section)> {
686 let &index = self.sections_by_name.get(name)?;
687 Some((index, &self.sections[index.0]))
688 }
689
690 pub fn by_name_mut(&mut self, name: &str) -> Option<(SectionIndex, &mut Section)> {
691 let &index = self.sections_by_name.get(name)?;
692 Some((index, &mut self.sections[index.0]))
693 }
694
695 pub fn iter(&self) -> impl Iterator<Item = &Section> {
696 self.sections.iter()
697 }
698
699 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Section> {
700 self.sections.iter_mut()
701 }
702
703 pub fn len(&self) -> usize {
704 self.sections.len()
705 }
706
707 pub fn get_by_contained_address(&self, address: u32) -> Option<(SectionIndex, &Section)> {
708 self.sections
709 .iter()
710 .enumerate()
711 .find(|(_, s)| address >= s.start_address && address < s.end_address)
712 .map(|(i, s)| (SectionIndex(i), s))
713 }
714
715 pub fn get_by_contained_address_mut(
716 &mut self,
717 address: u32,
718 ) -> Option<(SectionIndex, &mut Section)> {
719 self.sections
720 .iter_mut()
721 .enumerate()
722 .find(|(_, s)| address >= s.start_address && address < s.end_address)
723 .map(|(i, s)| (SectionIndex(i), s))
724 }
725
726 pub fn add_function(&mut self, function: Function) {
727 let address = function.first_instruction_address();
728 self.sections
729 .iter_mut()
730 .find(|s| address >= s.start_address && address < s.end_address)
731 .unwrap()
732 .functions
733 .insert(address, function);
734 }
735
736 pub fn sorted_by_address(&self) -> Vec<&Section> {
737 let mut sections = self.sections.iter().collect::<Vec<_>>();
738 sections.sort_unstable_by(|a, b| {
739 a.start_address.cmp(&b.start_address).then(a.end_address.cmp(&b.end_address))
740 });
741 sections
742 }
743
744 pub fn functions(&self) -> impl Iterator<Item = &Function> {
745 self.sections.iter().flat_map(|s| s.functions.values())
746 }
747
748 pub fn functions_mut(&mut self) -> impl Iterator<Item = &mut Function> {
749 self.sections.iter_mut().flat_map(|s| s.functions.values_mut())
750 }
751
752 pub fn base_address(&self) -> Option<u32> {
753 self.sections.iter().map(|s| s.start_address).min()
754 }
755
756 pub fn end_address(&self) -> Option<u32> {
757 self.sections.iter().map(|s| s.end_address).max()
758 }
759
760 pub fn text_size(&self) -> u32 {
761 self.sections.iter().filter(|s| s.kind != SectionKind::Bss).map(Section::size).sum()
762 }
763
764 pub fn bss_size(&self) -> u32 {
765 self.sections.iter().filter(|s| s.kind == SectionKind::Bss).map(Section::size).sum()
766 }
767
768 pub fn bss_range(&self) -> Option<Range<u32>> {
769 self.sections
770 .iter()
771 .filter(|s| s.kind == SectionKind::Bss)
772 .map(Section::address_range)
773 .reduce(|a, b| a.start.min(b.start)..a.end.max(b.end))
774 }
775
776 pub fn get_section_after(&self, text_end: u32) -> Option<&Section> {
777 self.sorted_by_address().iter().copied().find(|s| s.start_address >= text_end)
778 }
779}
780
781impl IntoIterator for Sections {
782 type IntoIter = <Vec<Self::Item> as IntoIterator>::IntoIter;
783 type Item = Section;
784
785 fn into_iter(self) -> Self::IntoIter {
786 self.sections.into_iter()
787 }
788}
789
790pub struct Word {
791 pub address: u32,
792 pub value: u32,
793}