ds_decomp/config/
module.rs

1use std::{
2    backtrace::Backtrace,
3    collections::{BTreeMap, BTreeSet},
4    fmt::Display,
5};
6
7use ds_rom::rom::{
8    raw::{AutoloadKind, RawBuildInfoError},
9    Arm9, Autoload, Overlay,
10};
11use snafu::Snafu;
12
13use crate::analysis::{
14    ctor::{CtorRange, CtorRangeError},
15    data::{self, FindLocalDataOptions},
16    functions::{
17        FindFunctionsOptions, Function, FunctionAnalysisError, FunctionParseOptions, FunctionSearchOptions,
18        ParseFunctionOptions, ParseFunctionResult,
19    },
20    main::{MainFunction, MainFunctionError},
21};
22
23use self::data::FindLocalDataError;
24
25use super::{
26    relocations::Relocations,
27    section::{Section, SectionCodeError, SectionError, SectionKind, SectionOptions, Sections, SectionsError},
28    symbol::{SymData, SymbolKind, SymbolMap, SymbolMapError, SymbolMaps},
29};
30
31pub struct Module<'a> {
32    name: String,
33    kind: ModuleKind,
34    relocations: Relocations,
35    code: &'a [u8],
36    base_address: u32,
37    bss_size: u32,
38    pub default_func_prefix: String,
39    pub default_data_prefix: String,
40    sections: Sections,
41}
42
43#[derive(Debug, Snafu)]
44pub enum ModuleError {
45    #[snafu(display("no sections provided:\n{backtrace}"))]
46    NoSections { backtrace: Backtrace },
47    #[snafu(transparent)]
48    CtorRange { source: CtorRangeError },
49    #[snafu(transparent)]
50    MainFunction { source: MainFunctionError },
51    #[snafu(transparent)]
52    RawBuildInfo { source: RawBuildInfoError },
53    #[snafu(transparent)]
54    SymbolMap { source: SymbolMapError },
55    #[snafu(transparent)]
56    FunctionAnalysis { source: FunctionAnalysisError },
57    #[snafu(display("function {name} could not be analyzed: {parse_result:x?}:\n{backtrace}"))]
58    FunctionAnalysisFailed { name: String, parse_result: ParseFunctionResult, backtrace: Backtrace },
59    #[snafu(transparent)]
60    Section { source: SectionError },
61    #[snafu(transparent)]
62    Sections { source: SectionsError },
63    #[snafu(display(
64        ".init section exists in {module_kind} ({min_address:#x}..{max_address:#x}) but no functions were found:\n{backtrace}"
65    ))]
66    NoInitFunctions { module_kind: ModuleKind, min_address: u32, max_address: u32, backtrace: Backtrace },
67    #[snafu(display("Entry functions not found:\n{backtrace}"))]
68    NoEntryFunctions { backtrace: Backtrace },
69    #[snafu(display("No functions in ARM9 main module:\n{backtrace}"))]
70    NoArm9Functions { backtrace: Backtrace },
71    #[snafu(display("No functions in ITCM:\n{backtrace}"))]
72    NoItcmFunctions { backtrace: Backtrace },
73    #[snafu(transparent)]
74    FindLocalData { source: FindLocalDataError },
75    #[snafu(transparent)]
76    SectionCode { source: SectionCodeError },
77}
78
79impl<'a> Module<'a> {
80    pub fn new_arm9(
81        name: String,
82        symbol_map: &mut SymbolMap,
83        relocations: Relocations,
84        mut sections: Sections,
85        code: &'a [u8],
86    ) -> Result<Module<'a>, ModuleError> {
87        let base_address = sections.base_address().ok_or_else(|| NoSectionsSnafu.build())?;
88        let end_address = sections.end_address().ok_or_else(|| NoSectionsSnafu.build())?;
89        let bss_size = sections.bss_size();
90        Self::import_functions(symbol_map, &mut sections, base_address, end_address, code)?;
91        Ok(Self {
92            name,
93            kind: ModuleKind::Arm9,
94            relocations,
95            code,
96            base_address,
97            bss_size,
98            default_func_prefix: "func_".to_string(),
99            default_data_prefix: "data_".to_string(),
100            sections,
101        })
102    }
103
104    pub fn analyze_arm9(arm9: &'a Arm9, symbol_maps: &mut SymbolMaps, options: &AnalysisOptions) -> Result<Self, ModuleError> {
105        let ctor_range = CtorRange::find_in_arm9(arm9)?;
106        let main_func = MainFunction::find_in_arm9(arm9)?;
107
108        let mut module = Self {
109            name: "main".to_string(),
110            kind: ModuleKind::Arm9,
111            relocations: Relocations::new(),
112            code: arm9.code()?,
113            base_address: arm9.base_address(),
114            bss_size: arm9.bss()?.len() as u32,
115            default_func_prefix: "func_".to_string(),
116            default_data_prefix: "data_".to_string(),
117            sections: Sections::new(),
118        };
119        let symbol_map = symbol_maps.get_mut(module.kind);
120
121        module.find_sections_arm9(symbol_map, ctor_range, main_func, arm9)?;
122        module.find_data_from_pools(symbol_map, options)?;
123        module.find_data_from_sections(symbol_map, options)?;
124
125        symbol_map.rename_by_address(arm9.entry_function(), "Entry")?;
126        symbol_map.rename_by_address(main_func.address, "main")?;
127
128        Ok(module)
129    }
130
131    pub fn new_overlay(
132        name: String,
133        symbol_map: &mut SymbolMap,
134        relocations: Relocations,
135        mut sections: Sections,
136        id: u16,
137        code: &'a [u8],
138    ) -> Result<Self, ModuleError> {
139        let base_address = sections.base_address().ok_or_else(|| NoSectionsSnafu.build())?;
140        let end_address = sections.end_address().ok_or_else(|| NoSectionsSnafu.build())?;
141        let bss_size = sections.bss_size();
142        Self::import_functions(symbol_map, &mut sections, base_address, end_address, code)?;
143        Ok(Self {
144            name,
145            kind: ModuleKind::Overlay(id),
146            relocations,
147            code,
148            base_address,
149            bss_size,
150            default_func_prefix: format!("func_ov{:03}_", id),
151            default_data_prefix: format!("data_ov{:03}_", id),
152            sections,
153        })
154    }
155
156    pub fn analyze_overlay(
157        overlay: &'a Overlay,
158        symbol_maps: &mut SymbolMaps,
159        options: &AnalysisOptions,
160    ) -> Result<Self, ModuleError> {
161        let mut module = Self {
162            name: format!("ov{:03}", overlay.id()),
163            kind: ModuleKind::Overlay(overlay.id()),
164            relocations: Relocations::new(),
165            code: overlay.code(),
166            base_address: overlay.base_address(),
167            bss_size: overlay.bss_size(),
168            default_func_prefix: format!("func_ov{:03}_", overlay.id()),
169            default_data_prefix: format!("data_ov{:03}_", overlay.id()),
170            sections: Sections::new(),
171        };
172        let symbol_map = symbol_maps.get_mut(module.kind);
173
174        log::debug!("Analyzing overlay {}", overlay.id());
175        module.find_sections_overlay(symbol_map, CtorRange { start: overlay.ctor_start(), end: overlay.ctor_end() })?;
176        module.find_data_from_pools(symbol_map, options)?;
177        module.find_data_from_sections(symbol_map, options)?;
178
179        Ok(module)
180    }
181
182    pub fn new_autoload(
183        name: String,
184        symbol_map: &mut SymbolMap,
185        relocations: Relocations,
186        mut sections: Sections,
187        kind: AutoloadKind,
188        code: &'a [u8],
189    ) -> Result<Self, ModuleError> {
190        let base_address = sections.base_address().ok_or_else(|| NoSectionsSnafu.build())?;
191        let end_address = sections.end_address().ok_or_else(|| NoSectionsSnafu.build())?;
192        let bss_size = sections.bss_size();
193        Self::import_functions(symbol_map, &mut sections, base_address, end_address, code)?;
194        Ok(Self {
195            name,
196            kind: ModuleKind::Autoload(kind),
197            relocations,
198            code,
199            base_address,
200            bss_size,
201            default_func_prefix: "func_".to_string(),
202            default_data_prefix: "data_".to_string(),
203            sections,
204        })
205    }
206
207    pub fn analyze_itcm(
208        autoload: &'a Autoload,
209        symbol_maps: &mut SymbolMaps,
210        options: &AnalysisOptions,
211    ) -> Result<Self, ModuleError> {
212        let mut module = Self {
213            name: "itcm".to_string(),
214            kind: ModuleKind::Autoload(AutoloadKind::Itcm),
215            relocations: Relocations::new(),
216            code: autoload.code(),
217            base_address: autoload.base_address(),
218            bss_size: autoload.bss_size(),
219            default_func_prefix: "func_".to_string(),
220            default_data_prefix: "data_".to_string(),
221            sections: Sections::new(),
222        };
223        let symbol_map = symbol_maps.get_mut(module.kind);
224
225        module.find_sections_itcm(symbol_map)?;
226        module.find_data_from_pools(symbol_map, options)?;
227
228        Ok(module)
229    }
230
231    pub fn analyze_dtcm(
232        autoload: &'a Autoload,
233        symbol_maps: &mut SymbolMaps,
234        options: &AnalysisOptions,
235    ) -> Result<Self, ModuleError> {
236        let mut module = Self {
237            name: "dtcm".to_string(),
238            kind: ModuleKind::Autoload(AutoloadKind::Dtcm),
239            relocations: Relocations::new(),
240            code: autoload.code(),
241            base_address: autoload.base_address(),
242            bss_size: autoload.bss_size(),
243            default_func_prefix: "func_".to_string(),
244            default_data_prefix: "data_".to_string(),
245            sections: Sections::new(),
246        };
247        let symbol_map = symbol_maps.get_mut(module.kind);
248
249        module.find_sections_dtcm()?;
250        module.find_data_from_sections(symbol_map, options)?;
251
252        Ok(module)
253    }
254
255    fn import_functions(
256        symbol_map: &mut SymbolMap,
257        sections: &mut Sections,
258        base_address: u32,
259        end_address: u32,
260        code: &'a [u8],
261    ) -> Result<(), ModuleError> {
262        for (sym_function, symbol) in symbol_map.clone_functions() {
263            if sym_function.unknown {
264                continue;
265            }
266            let offset = symbol.addr - base_address;
267            let size = sym_function.size;
268            let parse_result = Function::parse_function(FunctionParseOptions {
269                name: symbol.name.to_string(),
270                start_address: symbol.addr,
271                base_address: symbol.addr,
272                module_code: &code[offset as usize..],
273                known_end_address: Some(symbol.addr + size),
274                module_start_address: base_address,
275                module_end_address: end_address,
276                parse_options: ParseFunctionOptions { thumb: sym_function.mode.into_thumb() },
277                ..Default::default()
278            })?;
279            let function = match parse_result {
280                ParseFunctionResult::Found(function) => function,
281                _ => return FunctionAnalysisFailedSnafu { name: symbol.name, parse_result }.fail(),
282            };
283            function.add_local_symbols_to_map(symbol_map)?;
284            sections.add_function(function);
285        }
286        Ok(())
287    }
288
289    fn find_functions(
290        &mut self,
291        symbol_map: &mut SymbolMap,
292        search_options: FunctionSearchOptions,
293    ) -> Result<Option<FoundFunctions>, ModuleError> {
294        let functions = Function::find_functions(FindFunctionsOptions {
295            default_name_prefix: &self.default_func_prefix,
296            base_address: self.base_address,
297            module_code: self.code,
298            symbol_map,
299            module_start_address: self.base_address,
300            module_end_address: self.end_address(),
301            search_options,
302        })?;
303
304        if functions.is_empty() {
305            Ok(None)
306        } else {
307            let start = functions.first_key_value().unwrap().1.start_address();
308            let end = functions.last_key_value().unwrap().1.end_address();
309            Ok(Some(FoundFunctions { functions, start, end }))
310        }
311    }
312
313    /// Adds the .ctor section to this module. Returns the min and max address of .init functions in the .ctor section.
314    fn add_ctor_section(&mut self, ctor_range: &CtorRange) -> Result<Option<InitFunctions>, ModuleError> {
315        let section = Section::new(SectionOptions {
316            name: ".ctor".to_string(),
317            kind: SectionKind::Rodata,
318            start_address: ctor_range.start,
319            end_address: ctor_range.end,
320            alignment: 4,
321            functions: None,
322        })?;
323        self.sections.add(section)?;
324
325        let start = (ctor_range.start - self.base_address) as usize;
326        let end = (ctor_range.end - self.base_address) as usize;
327        let ctor = &self.code[start..end];
328
329        let mut init_functions = InitFunctions(BTreeSet::new());
330
331        let mut prev_address = 0;
332        for address in ctor.chunks(4).map(|b| u32::from_le_bytes([b[0], b[1], b[2], b[3]])).take_while(|&addr| addr != 0) {
333            if address < prev_address {
334                // Not in order, abort
335
336                // TODO: Create other sections for initializer functions that are not in order in .ctor. As in, every subrange
337                // of functions that are in order gets is own section, so that .ctor can be delinked and linked in a correct
338                // order.
339                break;
340            }
341            prev_address = address;
342            init_functions.0.insert(address & !1);
343        }
344
345        if init_functions.0.is_empty() {
346            Ok(None)
347        } else {
348            Ok(Some(init_functions))
349        }
350    }
351
352    /// Adds the .init section to this module. Returns the start and end address of the .init section.
353    fn add_init_section(
354        &mut self,
355        symbol_map: &mut SymbolMap,
356        ctor: &CtorRange,
357        init_functions: InitFunctions,
358        continuous: bool,
359    ) -> Result<Option<(u32, u32)>, ModuleError> {
360        let functions_min = *init_functions.0.first().unwrap();
361        let functions_max = *init_functions.0.last().unwrap();
362        let FoundFunctions { functions: init_functions, start: init_start, end: init_end } = self
363            .find_functions(
364                symbol_map,
365                FunctionSearchOptions {
366                    start_address: Some(functions_min),
367                    last_function_address: Some(functions_max),
368                    function_addresses: Some(init_functions.0),
369                    ..Default::default()
370                },
371            )?
372            .ok_or_else(|| {
373                NoInitFunctionsSnafu { module_kind: self.kind, min_address: functions_min, max_address: functions_max }.build()
374            })?;
375        // Functions in .ctor can sometimes point to .text instead of .init
376        if !continuous || init_end == ctor.start {
377            self.sections.add(Section::new(SectionOptions {
378                name: ".init".to_string(),
379                kind: SectionKind::Code,
380                start_address: init_start,
381                end_address: init_end,
382                alignment: 4,
383                functions: Some(init_functions),
384            })?)?;
385            Ok(Some((init_start, init_end)))
386        } else {
387            Ok(None)
388        }
389    }
390
391    /// Adds the .text section to this module.
392    fn add_text_section(&mut self, functions_result: FoundFunctions) -> Result<(), ModuleError> {
393        let FoundFunctions { functions, start, end } = functions_result;
394
395        if start < end {
396            self.sections.add(Section::new(SectionOptions {
397                name: ".text".to_string(),
398                kind: SectionKind::Code,
399                start_address: start,
400                end_address: end,
401                alignment: 32,
402                functions: Some(functions),
403            })?)?;
404        }
405        Ok(())
406    }
407
408    fn add_rodata_section(&mut self, start: u32, end: u32) -> Result<(), ModuleError> {
409        if start < end {
410            self.sections.add(Section::new(SectionOptions {
411                name: ".rodata".to_string(),
412                kind: SectionKind::Rodata,
413                start_address: start,
414                end_address: end,
415                alignment: 4,
416                functions: None,
417            })?)?;
418        }
419        Ok(())
420    }
421
422    fn add_data_section(&mut self, start: u32, end: u32) -> Result<(), ModuleError> {
423        if start < end {
424            self.sections.add(Section::new(SectionOptions {
425                name: ".data".to_string(),
426                kind: SectionKind::Data,
427                start_address: start,
428                end_address: end,
429                alignment: 32,
430                functions: None,
431            })?)?;
432        }
433        Ok(())
434    }
435
436    fn add_bss_section(&mut self, start: u32) -> Result<(), ModuleError> {
437        self.sections.add(Section::new(SectionOptions {
438            name: ".bss".to_string(),
439            kind: SectionKind::Bss,
440            start_address: start,
441            end_address: start + self.bss_size,
442            alignment: 32,
443            functions: None,
444        })?)?;
445        Ok(())
446    }
447
448    fn find_sections_overlay(&mut self, symbol_map: &mut SymbolMap, ctor: CtorRange) -> Result<(), ModuleError> {
449        let rodata_end = if let Some(init_functions) = self.add_ctor_section(&ctor)? {
450            if let Some((init_start, _)) = self.add_init_section(symbol_map, &ctor, init_functions, true)? {
451                init_start
452            } else {
453                ctor.start
454            }
455        } else {
456            ctor.start
457        };
458
459        let rodata_start = if let Some(functions_result) = self.find_functions(
460            symbol_map,
461            FunctionSearchOptions { end_address: Some(rodata_end), use_data_as_upper_bound: true, ..Default::default() },
462        )? {
463            let end = functions_result.end;
464            self.add_text_section(functions_result)?;
465            end
466        } else {
467            self.base_address
468        };
469
470        self.add_rodata_section(rodata_start, rodata_end)?;
471
472        let data_start = ctor.end.next_multiple_of(32);
473        let data_end = self.base_address + self.code.len() as u32;
474        self.add_data_section(data_start, data_end)?;
475        self.add_bss_section(data_end)?;
476
477        Ok(())
478    }
479
480    fn find_sections_arm9(
481        &mut self,
482        symbol_map: &mut SymbolMap,
483        ctor: CtorRange,
484        main_func: MainFunction,
485        arm9: &Arm9,
486    ) -> Result<(), ModuleError> {
487        // .ctor and .init
488        let (read_only_end, rodata_start) = if let Some(init_functions) = self.add_ctor_section(&ctor)? {
489            if let Some(init_range) = self.add_init_section(symbol_map, &ctor, init_functions, false)? {
490                (init_range.0, Some(init_range.1))
491            } else {
492                (ctor.start, None)
493            }
494        } else {
495            (ctor.start, None)
496        };
497        let has_init_section = read_only_end != ctor.start;
498
499        // Secure area functions (software interrupts)
500        let secure_area = &self.code[..0x800];
501        let mut functions = Function::find_secure_area_functions(secure_area, self.base_address, symbol_map);
502
503        // Build info
504        let build_info_offset = arm9.build_info_offset();
505        let build_info_address = arm9.base_address() + build_info_offset;
506        symbol_map.add_data(Some("BuildInfo".to_string()), build_info_address, SymData::Any)?;
507
508        // Autoload callback
509        let autoload_callback_address = arm9.autoload_callback();
510        let name = "AutoloadCallback";
511        let parse_result = Function::parse_function(FunctionParseOptions {
512            name: name.to_string(),
513            start_address: autoload_callback_address,
514            base_address: self.base_address,
515            module_code: self.code,
516            known_end_address: None,
517            module_start_address: self.base_address,
518            module_end_address: self.end_address(),
519            parse_options: Default::default(),
520            existing_functions: Some(&functions),
521        })?;
522        let autoload_function = match parse_result {
523            ParseFunctionResult::Found(function) => function,
524            _ => return FunctionAnalysisFailedSnafu { name, parse_result }.fail(),
525        };
526        symbol_map.add_function(&autoload_function);
527        functions.insert(autoload_function.first_instruction_address(), autoload_function);
528
529        // Entry functions
530        let FoundFunctions { functions: entry_functions, .. } = self
531            .find_functions(
532                symbol_map,
533                FunctionSearchOptions {
534                    start_address: Some(self.base_address + 0x800),
535                    end_address: Some(build_info_address),
536                    existing_functions: Some(&functions),
537                    ..Default::default()
538                },
539            )?
540            .ok_or_else(|| NoEntryFunctionsSnafu.build())?;
541        functions.extend(entry_functions);
542
543        // All other functions, starting from main
544        let FoundFunctions { functions: text_functions, end: mut text_end, .. } = self
545            .find_functions(
546                symbol_map,
547                FunctionSearchOptions {
548                    start_address: Some(main_func.address),
549                    end_address: Some(read_only_end),
550                    // Skips over segments of strange EOR instructions which are never executed
551                    keep_searching_for_valid_function_start: true,
552                    use_data_as_upper_bound: true,
553                    ..Default::default()
554                },
555            )?
556            .ok_or_else(|| NoArm9FunctionsSnafu.build())?;
557        if text_end != read_only_end && has_init_section {
558            log::warn!("Expected .text to end ({text_end:#x}) where .init starts ({read_only_end:#x})");
559        }
560        let text_start = self.base_address;
561        if has_init_section {
562            text_end = read_only_end;
563        }
564        functions.extend(text_functions);
565        self.add_text_section(FoundFunctions { functions, start: text_start, end: text_end })?;
566
567        // .rodata
568        let rodata_start = rodata_start.unwrap_or(text_end);
569        self.add_rodata_section(rodata_start, ctor.start)?;
570
571        // .data and .bss
572        let data_start = ctor.end.next_multiple_of(32);
573        let data_end = self.base_address + self.code.len() as u32;
574        self.add_data_section(data_start, data_end)?;
575        let bss_start = data_end.next_multiple_of(32);
576        self.add_bss_section(bss_start)?;
577
578        Ok(())
579    }
580
581    fn find_sections_itcm(&mut self, symbol_map: &mut SymbolMap) -> Result<(), ModuleError> {
582        let text_functions = self
583            .find_functions(
584                symbol_map,
585                FunctionSearchOptions {
586                    // ITCM only contains code, so there's no risk of running into non-code by skipping illegal instructions
587                    keep_searching_for_valid_function_start: true,
588                    ..Default::default()
589                },
590            )?
591            .ok_or_else(|| NoItcmFunctionsSnafu.build())?;
592        let text_end = text_functions.end;
593        self.add_text_section(text_functions)?;
594
595        let bss_start = text_end.next_multiple_of(32);
596        self.add_bss_section(bss_start)?;
597
598        Ok(())
599    }
600
601    fn find_sections_dtcm(&mut self) -> Result<(), ModuleError> {
602        let data_start = self.base_address;
603        let data_end = data_start + self.code.len() as u32;
604        self.add_data_section(data_start, data_end)?;
605
606        let bss_start = data_end.next_multiple_of(32);
607        self.add_bss_section(bss_start)?;
608
609        Ok(())
610    }
611
612    fn find_data_from_pools(&mut self, symbol_map: &mut SymbolMap, options: &AnalysisOptions) -> Result<(), ModuleError> {
613        for function in self.sections.functions() {
614            data::find_local_data_from_pools(
615                function,
616                FindLocalDataOptions {
617                    sections: &self.sections,
618                    module_kind: self.kind,
619                    symbol_map,
620                    relocations: &mut self.relocations,
621                    name_prefix: &self.default_data_prefix,
622                    code: self.code,
623                    base_address: self.base_address,
624                    address_range: None,
625                },
626                options,
627            )?;
628        }
629        Ok(())
630    }
631
632    fn find_data_from_sections(&mut self, symbol_map: &mut SymbolMap, options: &AnalysisOptions) -> Result<(), ModuleError> {
633        for section in self.sections.iter() {
634            match section.kind() {
635                SectionKind::Data | SectionKind::Rodata => {
636                    let code = section.code(self.code, self.base_address)?.unwrap();
637                    data::find_local_data_from_section(
638                        section,
639                        FindLocalDataOptions {
640                            sections: &self.sections,
641                            module_kind: self.kind,
642                            symbol_map,
643                            relocations: &mut self.relocations,
644                            name_prefix: &self.default_data_prefix,
645                            code,
646                            base_address: self.base_address,
647                            address_range: None,
648                        },
649                        options,
650                    )?;
651                }
652                SectionKind::Code => {
653                    // Look for data in gaps between functions
654                    let mut symbols = symbol_map
655                        .iter_by_address(section.address_range())
656                        .filter(|s| matches!(s.kind, SymbolKind::Function(_)))
657                        .peekable();
658                    let mut gaps = vec![];
659                    while let Some(symbol) = symbols.next() {
660                        if symbol.addr >= 0x2000000 && symbol.addr < 0x2000800 {
661                            // Secure area gaps are just random bytes
662                            continue;
663                        }
664
665                        let next_address = symbols.peek().map(|s| s.addr).unwrap_or(section.end_address());
666                        let end_address = symbol.addr + symbol.size(next_address);
667                        if end_address < next_address {
668                            gaps.push(end_address..next_address);
669                            log::debug!("Found gap between functions from {end_address:#x} to {next_address:#x}");
670                        }
671                    }
672                    for gap in gaps {
673                        if let Some(code) = section.code(self.code, self.base_address)? {
674                            data::find_local_data_from_section(
675                                section,
676                                FindLocalDataOptions {
677                                    sections: &self.sections,
678                                    module_kind: self.kind,
679                                    symbol_map,
680                                    relocations: &mut self.relocations,
681                                    name_prefix: &self.default_data_prefix,
682                                    code,
683                                    base_address: self.base_address,
684                                    address_range: Some(gap),
685                                },
686                                options,
687                            )?;
688                        }
689                    }
690                }
691                SectionKind::Bss => {}
692            }
693        }
694        Ok(())
695    }
696
697    pub fn relocations(&self) -> &Relocations {
698        &self.relocations
699    }
700
701    pub fn relocations_mut(&mut self) -> &mut Relocations {
702        &mut self.relocations
703    }
704
705    pub fn sections(&self) -> &Sections {
706        &self.sections
707    }
708
709    pub fn sections_mut(&mut self) -> &mut Sections {
710        &mut self.sections
711    }
712
713    pub fn code(&self) -> &[u8] {
714        self.code
715    }
716
717    pub fn base_address(&self) -> u32 {
718        self.base_address
719    }
720
721    pub fn end_address(&self) -> u32 {
722        self.base_address + self.code.len() as u32 + self.bss_size()
723    }
724
725    pub fn get_function(&self, addr: u32) -> Option<&Function> {
726        self.sections.get_by_contained_address(addr).and_then(|(_, s)| s.functions().get(&addr))
727    }
728
729    pub fn bss_size(&self) -> u32 {
730        self.bss_size
731    }
732
733    pub fn name(&self) -> &str {
734        &self.name
735    }
736
737    pub fn kind(&self) -> ModuleKind {
738        self.kind
739    }
740}
741
742#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
743pub enum ModuleKind {
744    Arm9,
745    Overlay(u16),
746    Autoload(AutoloadKind),
747}
748
749impl ModuleKind {
750    pub fn index(self) -> usize {
751        match self {
752            ModuleKind::Arm9 => 0,
753            ModuleKind::Autoload(kind) => match kind {
754                AutoloadKind::Itcm => 1,
755                AutoloadKind::Dtcm => 2,
756                AutoloadKind::Unknown(_) => 3,
757            },
758            ModuleKind::Overlay(id) => 4 + id as usize,
759        }
760    }
761}
762
763impl Display for ModuleKind {
764    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
765        match self {
766            ModuleKind::Arm9 => write!(f, "ARM9 main"),
767            ModuleKind::Overlay(index) => write!(f, "overlay {index}"),
768            ModuleKind::Autoload(kind) => write!(f, "{kind}"),
769        }
770    }
771}
772
773struct FoundFunctions {
774    functions: BTreeMap<u32, Function>,
775    start: u32,
776    end: u32,
777}
778
779/// Sorted list of .init function addresses
780struct InitFunctions(BTreeSet<u32>);
781
782pub struct AnalysisOptions {
783    /// Generates function symbols when a local function call doesn't lead to a known function. This can happen if the
784    /// destination function is encrypted or otherwise wasn't found during function analysis.
785    pub allow_unknown_function_calls: bool,
786    /// If true, every relocation in relocs.txt will have a comment explaining where/why it was generated.
787    pub provide_reloc_source: bool,
788}