Skip to main content

ds_decomp/config/
section.rs

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    /// When a section is migrated, this was the migration used
34    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    /// Iterates over every 32-bit word in the specified `range`, which defaults to the entire section if it is `None`. Note
353    /// that `code` must be the full raw content of this section.
354    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    // /// Special section for adding .bss objects to the DTCM module
564    // Dtcm,
565}
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(&section.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        // Update indices in sections_by_name
671        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}