ds_decomp/config/
module.rs

1use std::{
2    backtrace::Backtrace,
3    collections::{BTreeMap, BTreeSet},
4    fmt::Display,
5};
6
7use ds_rom::rom::{
8    Arm9, Autoload, Overlay,
9    raw::{AutoloadKind, RawBuildInfoError},
10};
11use snafu::Snafu;
12
13use crate::{
14    analysis::{
15        ctor::{CtorRange, CtorRangeError},
16        data::{self, FindLocalDataOptions},
17        exception::{ExceptionData, ExceptionDataError},
18        functions::{
19            FindFunctionsOptions, Function, FunctionAnalysisError, FunctionParseOptions, FunctionSearchOptions,
20            ParseFunctionOptions, ParseFunctionResult,
21        },
22        main::{MainFunction, MainFunctionError},
23    },
24    config::symbol::Symbol,
25};
26
27use self::data::FindLocalDataError;
28
29use super::{
30    relocations::Relocations,
31    section::{Section, SectionCodeError, SectionError, SectionKind, SectionOptions, Sections, SectionsError},
32    symbol::{SymData, SymbolKind, SymbolMap, SymbolMapError, SymbolMaps},
33};
34
35pub struct Module {
36    name: String,
37    kind: ModuleKind,
38    relocations: Relocations,
39    code: Vec<u8>,
40    base_address: u32,
41    bss_size: u32,
42    pub default_func_prefix: String,
43    pub default_data_prefix: String,
44    pub default_sinit_prefix: String,
45    sections: Sections,
46    signed: bool,
47}
48
49#[derive(Debug, Snafu)]
50pub enum ModuleError {
51    #[snafu(display("no sections provided:\n{backtrace}"))]
52    NoSections { backtrace: Backtrace },
53    #[snafu(transparent)]
54    CtorRange { source: CtorRangeError },
55    #[snafu(transparent)]
56    MainFunction { source: MainFunctionError },
57    #[snafu(transparent)]
58    RawBuildInfo { source: RawBuildInfoError },
59    #[snafu(transparent)]
60    SymbolMap { source: SymbolMapError },
61    #[snafu(transparent)]
62    FunctionAnalysis { source: FunctionAnalysisError },
63    #[snafu(display("function {name} could not be analyzed: {parse_result:x?}:\n{backtrace}"))]
64    FunctionAnalysisFailed { name: String, parse_result: ParseFunctionResult, backtrace: Backtrace },
65    #[snafu(transparent)]
66    Section { source: SectionError },
67    #[snafu(transparent)]
68    Sections { source: SectionsError },
69    #[snafu(display(
70        ".init section exists in {module_kind} ({min_address:#x}..{max_address:#x}) but no functions were found:\n{backtrace}"
71    ))]
72    NoInitFunctions { module_kind: ModuleKind, min_address: u32, max_address: u32, backtrace: Backtrace },
73    #[snafu(display("Entry functions not found:\n{backtrace}"))]
74    NoEntryFunctions { backtrace: Backtrace },
75    #[snafu(display("No functions in ARM9 main module:\n{backtrace}"))]
76    NoArm9Functions { backtrace: Backtrace },
77    #[snafu(display("No functions in ITCM:\n{backtrace}"))]
78    NoItcmFunctions { backtrace: Backtrace },
79    #[snafu(transparent)]
80    FindLocalData { source: FindLocalDataError },
81    #[snafu(transparent)]
82    SectionCode { source: SectionCodeError },
83    #[snafu(display("The provided autoload is not an unknown autoload:\n{backtrace}"))]
84    NotAnUnknownAutoload { backtrace: Backtrace },
85    #[snafu(transparent)]
86    ExceptionData { source: ExceptionDataError },
87}
88
89pub struct OverlayModuleOptions<'a> {
90    pub id: u16,
91    pub code: &'a [u8],
92    pub signed: bool,
93}
94
95pub struct ModuleOptions<'a> {
96    pub kind: ModuleKind,
97    pub name: String,
98    pub relocations: Relocations,
99    pub sections: Sections,
100    pub code: &'a [u8],
101    pub signed: bool,
102}
103
104impl Module {
105    pub fn new(symbol_map: &mut SymbolMap, options: ModuleOptions) -> Result<Module, ModuleError> {
106        let ModuleOptions { kind, name, relocations, mut sections, code, signed } = options;
107
108        let base_address = sections.base_address().ok_or_else(|| NoSectionsSnafu.build())?;
109        let end_address = sections.end_address().ok_or_else(|| NoSectionsSnafu.build())?;
110        let bss_size = sections.bss_size();
111        Self::import_functions(symbol_map, &mut sections, base_address, end_address, code)?;
112
113        let (default_func_prefix, default_data_prefix, default_sinit_prefix) = match kind {
114            ModuleKind::Overlay(id) => (format!("func_ov{id:03}_"), format!("data_ov{id:03}_"), format!("__sinit_ov{id:03}_")),
115            _ => ("func_".to_string(), "data_".to_string(), "__sinit_".to_string()),
116        };
117
118        Ok(Self {
119            name,
120            kind,
121            relocations,
122            code: code.to_vec(),
123            base_address,
124            bss_size,
125            default_func_prefix,
126            default_data_prefix,
127            default_sinit_prefix,
128            sections,
129            signed,
130        })
131    }
132
133    /// Depricated, use [`Self::new`] instead.
134    ///
135    /// Creates a new ARM9 main module.
136    #[deprecated]
137    pub fn new_arm9(
138        name: String,
139        symbol_map: &mut SymbolMap,
140        relocations: Relocations,
141        mut sections: Sections,
142        code: &[u8],
143    ) -> Result<Module, ModuleError> {
144        let base_address = sections.base_address().ok_or_else(|| NoSectionsSnafu.build())?;
145        let end_address = sections.end_address().ok_or_else(|| NoSectionsSnafu.build())?;
146        let bss_size = sections.bss_size();
147        Self::import_functions(symbol_map, &mut sections, base_address, end_address, code)?;
148        Ok(Self {
149            name,
150            kind: ModuleKind::Arm9,
151            relocations,
152            code: code.to_vec(),
153            base_address,
154            bss_size,
155            default_func_prefix: "func_".to_string(),
156            default_data_prefix: "data_".to_string(),
157            default_sinit_prefix: "__sinit_".to_string(),
158            sections,
159            signed: false,
160        })
161    }
162
163    pub fn analyze_arm9(
164        arm9: &Arm9,
165        unknown_autoloads: &[&Autoload],
166        symbol_maps: &mut SymbolMaps,
167        options: &AnalysisOptions,
168    ) -> Result<Self, ModuleError> {
169        let ctor_range = CtorRange::find_in_arm9(arm9, unknown_autoloads)?;
170        let main_func = MainFunction::find_in_arm9(arm9)?;
171        let exception_data = ExceptionData::analyze(arm9, unknown_autoloads)?;
172
173        let mut module = Self {
174            name: "main".to_string(),
175            kind: ModuleKind::Arm9,
176            relocations: Relocations::new(),
177            code: arm9.code()?.to_vec(),
178            base_address: arm9.base_address(),
179            bss_size: arm9.bss()?.len() as u32,
180            default_func_prefix: "func_".to_string(),
181            default_data_prefix: "data_".to_string(),
182            default_sinit_prefix: "__sinit_".to_string(),
183            sections: Sections::new(),
184            signed: false,
185        };
186        let symbol_map = symbol_maps.get_mut(module.kind);
187
188        module.find_sections_arm9(symbol_map, ctor_range, exception_data, arm9)?;
189        module.find_data_from_pools(symbol_map, options)?;
190        module.find_data_from_sections(symbol_map, options)?;
191
192        symbol_map.rename_by_address(arm9.entry_function(), "Entry")?;
193        symbol_map.rename_by_address(main_func.address, "main")?;
194
195        Ok(module)
196    }
197
198    /// Depricated, use [`Self::new`] instead.
199    ///
200    /// Creates a new overlay module.
201    #[deprecated]
202    pub fn new_overlay(
203        name: String,
204        symbol_map: &mut SymbolMap,
205        relocations: Relocations,
206        mut sections: Sections,
207        options: OverlayModuleOptions,
208    ) -> Result<Self, ModuleError> {
209        let OverlayModuleOptions { id, code, signed } = options;
210
211        let base_address = sections.base_address().ok_or_else(|| NoSectionsSnafu.build())?;
212        let end_address = sections.end_address().ok_or_else(|| NoSectionsSnafu.build())?;
213        let bss_size = sections.bss_size();
214        Self::import_functions(symbol_map, &mut sections, base_address, end_address, code)?;
215        Ok(Self {
216            name,
217            kind: ModuleKind::Overlay(id),
218            relocations,
219            code: code.to_vec(),
220            base_address,
221            bss_size,
222            default_func_prefix: format!("func_ov{id:03}_"),
223            default_data_prefix: format!("data_ov{id:03}_"),
224            default_sinit_prefix: format!("__sinit_ov{id:03}_"),
225            sections,
226            signed,
227        })
228    }
229
230    pub fn analyze_overlay(
231        overlay: &Overlay,
232        symbol_maps: &mut SymbolMaps,
233        options: &AnalysisOptions,
234    ) -> Result<Self, ModuleError> {
235        let mut module = Self {
236            name: format!("ov{:03}", overlay.id()),
237            kind: ModuleKind::Overlay(overlay.id()),
238            relocations: Relocations::new(),
239            code: overlay.code().to_vec(),
240            base_address: overlay.base_address(),
241            bss_size: overlay.bss_size(),
242            default_func_prefix: format!("func_ov{:03}_", overlay.id()),
243            default_data_prefix: format!("data_ov{:03}_", overlay.id()),
244            default_sinit_prefix: format!("__sinit_ov{:03}_", overlay.id()),
245            sections: Sections::new(),
246            signed: overlay.is_signed(),
247        };
248        let symbol_map = symbol_maps.get_mut(module.kind);
249
250        log::debug!("Analyzing overlay {}", overlay.id());
251        module.find_sections_overlay(symbol_map, CtorRange { start: overlay.ctor_start(), end: overlay.ctor_end() })?;
252        module.find_data_from_pools(symbol_map, options)?;
253        module.find_data_from_sections(symbol_map, options)?;
254
255        Ok(module)
256    }
257
258    /// Depricated, use [`Self::new`] instead.
259    ///
260    /// Creates a new autoload module.
261    #[deprecated]
262    pub fn new_autoload(
263        name: String,
264        symbol_map: &mut SymbolMap,
265        relocations: Relocations,
266        mut sections: Sections,
267        kind: AutoloadKind,
268        code: &[u8],
269    ) -> Result<Self, ModuleError> {
270        let base_address = sections.base_address().ok_or_else(|| NoSectionsSnafu.build())?;
271        let end_address = sections.end_address().ok_or_else(|| NoSectionsSnafu.build())?;
272        let bss_size = sections.bss_size();
273        Self::import_functions(symbol_map, &mut sections, base_address, end_address, code)?;
274        Ok(Self {
275            name,
276            kind: ModuleKind::Autoload(kind),
277            relocations,
278            code: code.to_vec(),
279            base_address,
280            bss_size,
281            default_func_prefix: "func_".to_string(),
282            default_data_prefix: "data_".to_string(),
283            default_sinit_prefix: "__sinit_".to_string(),
284            sections,
285            signed: false,
286        })
287    }
288
289    pub fn analyze_itcm(
290        autoload: &Autoload,
291        symbol_maps: &mut SymbolMaps,
292        options: &AnalysisOptions,
293    ) -> Result<Self, ModuleError> {
294        let mut module = Self {
295            name: "itcm".to_string(),
296            kind: ModuleKind::Autoload(AutoloadKind::Itcm),
297            relocations: Relocations::new(),
298            code: autoload.code().to_vec(),
299            base_address: autoload.base_address(),
300            bss_size: autoload.bss_size(),
301            default_func_prefix: "func_".to_string(),
302            default_data_prefix: "data_".to_string(),
303            default_sinit_prefix: "__sinit_".to_string(),
304            sections: Sections::new(),
305            signed: false,
306        };
307        let symbol_map = symbol_maps.get_mut(module.kind);
308
309        module.find_sections_itcm(symbol_map)?;
310        module.find_data_from_pools(symbol_map, options)?;
311
312        Ok(module)
313    }
314
315    pub fn analyze_dtcm(
316        autoload: &Autoload,
317        symbol_maps: &mut SymbolMaps,
318        options: &AnalysisOptions,
319    ) -> Result<Self, ModuleError> {
320        let mut module = Self {
321            name: "dtcm".to_string(),
322            kind: ModuleKind::Autoload(AutoloadKind::Dtcm),
323            relocations: Relocations::new(),
324            code: autoload.code().to_vec(),
325            base_address: autoload.base_address(),
326            bss_size: autoload.bss_size(),
327            default_func_prefix: "func_".to_string(),
328            default_data_prefix: "data_".to_string(),
329            default_sinit_prefix: "__sinit_".to_string(),
330            sections: Sections::new(),
331            signed: false,
332        };
333        let symbol_map = symbol_maps.get_mut(module.kind);
334
335        module.find_sections_dtcm()?;
336        module.find_data_from_sections(symbol_map, options)?;
337
338        Ok(module)
339    }
340
341    pub fn analyze_unknown_autoload(
342        autoload: &Autoload,
343        symbol_maps: &mut SymbolMaps,
344        options: &AnalysisOptions,
345    ) -> Result<Self, ModuleError> {
346        let AutoloadKind::Unknown(autoload_index) = autoload.kind() else {
347            return NotAnUnknownAutoloadSnafu.fail();
348        };
349        let mut module = Self {
350            name: format!("autoload_{autoload_index}"),
351            kind: ModuleKind::Autoload(autoload.kind()),
352            relocations: Relocations::new(),
353            code: autoload.code().to_vec(),
354            base_address: autoload.base_address(),
355            bss_size: autoload.bss_size(),
356            default_func_prefix: "func_".to_string(),
357            default_data_prefix: "data_".to_string(),
358            default_sinit_prefix: "__sinit_".to_string(),
359            sections: Sections::new(),
360            signed: false,
361        };
362        let symbol_map = symbol_maps.get_mut(module.kind);
363
364        module.find_sections_unknown_autoload(symbol_map, autoload)?;
365        module.find_data_from_pools(symbol_maps.get_mut(module.kind), options)?;
366        module.find_data_from_sections(symbol_maps.get_mut(module.kind), options)?;
367
368        Ok(module)
369    }
370
371    fn import_functions(
372        symbol_map: &mut SymbolMap,
373        sections: &mut Sections,
374        base_address: u32,
375        end_address: u32,
376        code: &[u8],
377    ) -> Result<(), ModuleError> {
378        for (sym_function, symbol) in symbol_map.clone_functions() {
379            if sym_function.unknown {
380                continue;
381            }
382            let offset = symbol.addr - base_address;
383            let size = sym_function.size;
384            let parse_result = Function::parse_function(FunctionParseOptions {
385                name: symbol.name.to_string(),
386                start_address: symbol.addr,
387                base_address: symbol.addr,
388                module_code: &code[offset as usize..],
389                known_end_address: Some(symbol.addr + size),
390                module_start_address: base_address,
391                module_end_address: end_address,
392                parse_options: ParseFunctionOptions { thumb: sym_function.mode.into_thumb() },
393                ..Default::default()
394            })?;
395            let function = match parse_result {
396                ParseFunctionResult::Found(function) => function,
397                _ => return FunctionAnalysisFailedSnafu { name: symbol.name, parse_result }.fail(),
398            };
399            function.add_local_symbols_to_map(symbol_map)?;
400            sections.add_function(function);
401        }
402        Ok(())
403    }
404
405    fn find_functions(
406        &mut self,
407        symbol_map: &mut SymbolMap,
408        search_options: FunctionSearchOptions,
409        func_prefix: String,
410    ) -> Result<Option<FoundFunctions>, ModuleError> {
411        let functions = Function::find_functions(FindFunctionsOptions {
412            default_name_prefix: &func_prefix,
413            base_address: self.base_address,
414            module_code: &self.code,
415            symbol_map,
416            module_start_address: self.base_address,
417            module_end_address: self.end_address(),
418            search_options,
419        })?;
420
421        if functions.is_empty() {
422            Ok(None)
423        } else {
424            let start = functions.first_key_value().unwrap().1.start_address();
425            // Align by 4 in case of Thumb function ending on a 2-byte boundary
426            let end = functions.last_key_value().unwrap().1.end_address().next_multiple_of(4);
427            log::debug!("Found {} functions in {}: {:#x} to {:#x}", functions.len(), self.kind, start, end);
428            Ok(Some(FoundFunctions { functions, start, end }))
429        }
430    }
431
432    /// Adds the .ctor section to this module. Returns the min and max address of .init functions in the .ctor section.
433    fn add_ctor_section(
434        &mut self,
435        ctor_range: &CtorRange,
436        symbol_map: &mut SymbolMap,
437    ) -> Result<Option<InitFunctions>, ModuleError> {
438        let section = Section::new(SectionOptions {
439            name: ".ctor".to_string(),
440            kind: SectionKind::Rodata,
441            start_address: ctor_range.start,
442            end_address: ctor_range.end,
443            alignment: 4,
444            functions: None,
445        })?;
446        self.sections.add(section)?;
447
448        let start = (ctor_range.start - self.base_address) as usize;
449        let end = (ctor_range.end - self.base_address) as usize;
450        let ctor = &self.code[start..end];
451
452        let mut init_functions = InitFunctions(BTreeSet::new());
453
454        let mut prev_address = 0;
455        for (i, address) in
456            ctor.chunks(4).map(|b| u32::from_le_bytes([b[0], b[1], b[2], b[3]])).take_while(|&addr| addr != 0).enumerate()
457        {
458            if address >= prev_address {
459                prev_address = address;
460                init_functions.0.insert(address & !1);
461            } else {
462                // Not in order, abort
463
464                // TODO: Create other sections for initializer functions that are not in order in .ctor. As in, every subrange
465                // of functions that are in order gets is own section, so that .ctor can be delinked and linked in a correct
466                // order.
467            }
468
469            let symbol_address = ctor_range.start + i as u32 * 4;
470            symbol_map.add(Symbol::new_data(
471                format!(".p{}{:08x}", self.default_sinit_prefix, address & !1),
472                symbol_address,
473                SymData::Word { count: Some(1) },
474                false,
475            ));
476        }
477
478        if init_functions.0.is_empty() {
479            Ok(None)
480        } else {
481            Ok(Some(init_functions))
482        }
483    }
484
485    /// Adds the .init section to this module. Returns the start and end address of the .init section.
486    fn add_init_section(
487        &mut self,
488        symbol_map: &mut SymbolMap,
489        ctor: &CtorRange,
490        init_functions: InitFunctions,
491        continuous: bool,
492    ) -> Result<Option<(u32, u32)>, ModuleError> {
493        let functions_min = *init_functions.0.first().unwrap();
494        let functions_max = *init_functions.0.last().unwrap();
495        let FoundFunctions { functions: init_functions, start: init_start, end: init_end } = self
496            .find_functions(
497                symbol_map,
498                FunctionSearchOptions {
499                    start_address: Some(functions_min),
500                    last_function_address: Some(functions_max),
501                    function_addresses: Some(init_functions.0),
502                    check_defs_uses: true,
503                    ..Default::default()
504                },
505                self.default_sinit_prefix.clone(),
506            )?
507            .ok_or_else(|| {
508                NoInitFunctionsSnafu { module_kind: self.kind, min_address: functions_min, max_address: functions_max }.build()
509            })?;
510        // Functions in .ctor can sometimes point to .text instead of .init
511        if !continuous || init_end == ctor.start {
512            self.sections.add(Section::new(SectionOptions {
513                name: ".init".to_string(),
514                kind: SectionKind::Code,
515                start_address: init_start,
516                end_address: init_end,
517                alignment: 4,
518                functions: Some(init_functions),
519            })?)?;
520            Ok(Some((init_start, init_end)))
521        } else {
522            Ok(None)
523        }
524    }
525
526    /// Adds the .text section to this module.
527    fn add_text_section(&mut self, functions_result: FoundFunctions) -> Result<(), ModuleError> {
528        let FoundFunctions { functions, start, end } = functions_result;
529
530        if start < end {
531            self.sections.add(Section::new(SectionOptions {
532                name: ".text".to_string(),
533                kind: SectionKind::Code,
534                start_address: start,
535                end_address: end,
536                alignment: 32,
537                functions: Some(functions),
538            })?)?;
539        }
540        Ok(())
541    }
542
543    fn add_rodata_section(&mut self, start: u32, end: u32) -> Result<(), ModuleError> {
544        if start < end {
545            self.sections.add(Section::new(SectionOptions {
546                name: ".rodata".to_string(),
547                kind: SectionKind::Rodata,
548                start_address: start,
549                end_address: end,
550                alignment: 4,
551                functions: None,
552            })?)?;
553        }
554        Ok(())
555    }
556
557    fn add_data_section(&mut self, start: u32, end: u32) -> Result<(), ModuleError> {
558        if start < end {
559            self.sections.add(Section::new(SectionOptions {
560                name: ".data".to_string(),
561                kind: SectionKind::Data,
562                start_address: start,
563                end_address: end,
564                alignment: 32,
565                functions: None,
566            })?)?;
567        }
568        Ok(())
569    }
570
571    fn add_bss_section(&mut self, start: u32) -> Result<(), ModuleError> {
572        self.sections.add(Section::new(SectionOptions {
573            name: ".bss".to_string(),
574            kind: SectionKind::Bss,
575            start_address: start,
576            end_address: start + self.bss_size,
577            alignment: 32,
578            functions: None,
579        })?)?;
580        Ok(())
581    }
582
583    fn find_sections_overlay(&mut self, symbol_map: &mut SymbolMap, ctor: CtorRange) -> Result<(), ModuleError> {
584        let rodata_end = if let Some(init_functions) = self.add_ctor_section(&ctor, symbol_map)? {
585            if let Some((init_start, _)) = self.add_init_section(symbol_map, &ctor, init_functions, true)? {
586                init_start
587            } else {
588                ctor.start
589            }
590        } else {
591            ctor.start
592        };
593
594        let rodata_start = if let Some(functions_result) = self.find_functions(
595            symbol_map,
596            FunctionSearchOptions {
597                end_address: Some(rodata_end),
598                use_data_as_upper_bound: true,
599                check_defs_uses: true,
600                ..Default::default()
601            },
602            self.default_func_prefix.clone(),
603        )? {
604            let end = functions_result.end;
605            self.add_text_section(functions_result)?;
606            end
607        } else {
608            self.base_address
609        };
610
611        self.add_rodata_section(rodata_start, rodata_end)?;
612
613        let data_start = ctor.end.next_multiple_of(32);
614        let data_end = self.base_address + self.code.len() as u32;
615        self.add_data_section(data_start, data_end)?;
616        self.add_bss_section(data_end)?;
617
618        Ok(())
619    }
620
621    fn find_sections_arm9(
622        &mut self,
623        symbol_map: &mut SymbolMap,
624        ctor: CtorRange,
625        exception_data: Option<ExceptionData>,
626        arm9: &Arm9,
627    ) -> Result<(), ModuleError> {
628        // .ctor and .init
629        let (read_only_end, rodata_start) = if let Some(init_functions) = self.add_ctor_section(&ctor, symbol_map)? {
630            if let Some(init_range) = self.add_init_section(symbol_map, &ctor, init_functions, false)? {
631                (init_range.0, Some(init_range.1))
632            } else {
633                (ctor.start, None)
634            }
635        } else {
636            (ctor.start, None)
637        };
638
639        // Secure area functions (software interrupts)
640        let secure_area = &self.code[..0x800];
641        let mut functions = Function::find_secure_area_functions(secure_area, self.base_address, symbol_map);
642
643        // Build info
644        let build_info_offset = arm9.build_info_offset();
645        let build_info_address = arm9.base_address() + build_info_offset;
646        symbol_map.add_data(Some("BuildInfo".to_string()), build_info_address, SymData::Any)?;
647
648        // Autoload callback
649        let autoload_callback_address = arm9.autoload_callback();
650        let name = "AutoloadCallback";
651        let parse_result = Function::parse_function(FunctionParseOptions {
652            name: name.to_string(),
653            start_address: autoload_callback_address,
654            base_address: self.base_address,
655            module_code: &self.code,
656            known_end_address: None,
657            module_start_address: self.base_address,
658            module_end_address: self.end_address(),
659            parse_options: Default::default(),
660            check_defs_uses: true,
661            existing_functions: Some(&functions),
662        })?;
663        let autoload_function = match parse_result {
664            ParseFunctionResult::Found(function) => function,
665            _ => return FunctionAnalysisFailedSnafu { name, parse_result }.fail(),
666        };
667        symbol_map.add_function(&autoload_function);
668        functions.insert(autoload_function.first_instruction_address(), autoload_function);
669
670        // Entry functions
671        let FoundFunctions { functions: entry_functions, .. } = self
672            .find_functions(
673                symbol_map,
674                FunctionSearchOptions {
675                    start_address: Some(self.base_address + 0x800),
676                    end_address: Some(build_info_address),
677                    existing_functions: Some(&functions),
678                    check_defs_uses: true,
679                    ..Default::default()
680                },
681                self.default_func_prefix.clone(),
682            )?
683            .ok_or_else(|| NoEntryFunctionsSnafu.build())?;
684        functions.extend(entry_functions);
685
686        // All other functions, starting from main
687        let exception_start = exception_data.as_ref().and_then(|e| e.exception_start());
688        let text_max = exception_start.unwrap_or(read_only_end);
689        let main_start = self.find_build_info_end_address(arm9);
690        let FoundFunctions { functions: text_functions, end: mut text_end, .. } = self
691            .find_functions(
692                symbol_map,
693                FunctionSearchOptions {
694                    start_address: Some(main_start),
695                    end_address: Some(text_max),
696                    // Skips over segments of strange EOR instructions which are never executed
697                    max_function_start_search_distance: u32::MAX,
698                    use_data_as_upper_bound: true,
699                    // There are some handwritten assembly functions in ARM9 main that don't follow the procedure call standard
700                    check_defs_uses: false,
701                    ..Default::default()
702                },
703                self.default_func_prefix.clone(),
704            )?
705            .ok_or_else(|| NoArm9FunctionsSnafu.build())?;
706        let text_start = self.base_address;
707        functions.extend(text_functions);
708        self.add_text_section(FoundFunctions { functions, start: text_start, end: text_end })?;
709
710        // Add .exception and .exceptix sections if they exist
711        if let Some(exception_data) = exception_data {
712            if let Some(exception_start) = exception_data.exception_start() {
713                self.sections.add(Section::new(SectionOptions {
714                    name: ".exception".to_string(),
715                    kind: SectionKind::Rodata,
716                    start_address: exception_start,
717                    end_address: exception_data.exceptix_start(),
718                    alignment: 1,
719                    functions: None,
720                })?)?;
721            }
722
723            self.sections.add(Section::new(SectionOptions {
724                name: ".exceptix".to_string(),
725                kind: SectionKind::Rodata,
726                start_address: exception_data.exceptix_start(),
727                end_address: exception_data.exceptix_end(),
728                alignment: 4,
729                functions: None,
730            })?)?;
731
732            text_end = exception_data.exceptix_end();
733        }
734
735        // .rodata
736        let rodata_start = rodata_start.unwrap_or(text_end);
737        self.add_rodata_section(rodata_start, ctor.start)?;
738
739        // .data and .bss
740        let data_start = ctor.end.next_multiple_of(32);
741        let data_end = self.base_address + self.code.len() as u32;
742        self.add_data_section(data_start, data_end)?;
743        let bss_start = data_end.next_multiple_of(32);
744        self.add_bss_section(bss_start)?;
745
746        let section_after_text = self.sections.get_section_after(text_end);
747        if let Some(section_after_text) = section_after_text {
748            if text_end != section_after_text.start_address() {
749                log::warn!(
750                    "Expected .text to end ({:#010x}) where {} starts ({:#010x})",
751                    text_end,
752                    section_after_text.name(),
753                    section_after_text.start_address()
754                );
755            }
756        }
757
758        Ok(())
759    }
760
761    fn find_build_info_end_address(&self, arm9: &Arm9) -> u32 {
762        let build_info_offset = arm9.build_info_offset();
763        let library_list_start = build_info_offset + 0x24; // 0x24 is the size of the build info struct
764
765        let mut offset = library_list_start as usize;
766        loop {
767            // Up to 4 bytes of zeros for alignment
768            let Some((library_offset, ch)) = self.code[offset..offset + 4].iter().enumerate().find(|&(_, &b)| b != b'0')
769            else {
770                break;
771            };
772            if *ch != b'[' {
773                // Not a library name
774                break;
775            }
776            offset += library_offset;
777
778            let library_length = self.code[offset..].iter().position(|&b| b == b']').unwrap() + 1;
779            offset += library_length + 1; // +1 for the null terminator
780        }
781
782        arm9.base_address() + offset.next_multiple_of(4) as u32
783    }
784
785    fn find_sections_itcm(&mut self, symbol_map: &mut SymbolMap) -> Result<(), ModuleError> {
786        let text_functions = self
787            .find_functions(
788                symbol_map,
789                FunctionSearchOptions {
790                    // ITCM only contains code, so there's no risk of running into non-code by skipping illegal instructions
791                    max_function_start_search_distance: u32::MAX,
792                    // There are some handwritten assembly functions in the ITCM that don't follow the procedure call standard
793                    check_defs_uses: false,
794                    ..Default::default()
795                },
796                self.default_func_prefix.clone(),
797            )?
798            .ok_or_else(|| NoItcmFunctionsSnafu.build())?;
799        let text_end = text_functions.end;
800        self.add_text_section(text_functions)?;
801
802        let bss_start = text_end.next_multiple_of(32);
803        self.add_bss_section(bss_start)?;
804
805        Ok(())
806    }
807
808    fn find_sections_dtcm(&mut self) -> Result<(), ModuleError> {
809        let data_start = self.base_address;
810        let data_end = data_start + self.code.len() as u32;
811        self.add_data_section(data_start, data_end)?;
812
813        let bss_start = data_end.next_multiple_of(32);
814        self.add_bss_section(bss_start)?;
815
816        Ok(())
817    }
818
819    fn find_sections_unknown_autoload(&mut self, symbol_map: &mut SymbolMap, autoload: &Autoload) -> Result<(), ModuleError> {
820        let base_address = autoload.base_address();
821        let AutoloadKind::Unknown(autoload_index) = autoload.kind() else {
822            panic!("Not an unknown autoload: {}", autoload.kind());
823        };
824        let code = autoload.code();
825
826        let text_functions = self.find_functions(
827            symbol_map,
828            FunctionSearchOptions {
829                max_function_start_search_distance: 32,
830                use_data_as_upper_bound: true,
831                // There are some handwritten assembly functions in unknown autoloads that don't follow the procedure call standard
832                check_defs_uses: false,
833                ..Default::default()
834            },
835            self.default_func_prefix.clone(),
836        )?;
837
838        let text_end = if let Some(text_functions) = text_functions {
839            let text_end = text_functions.end;
840            self.add_text_section(text_functions)?;
841            text_end
842        } else {
843            self.base_address
844        };
845
846        let rodata_start = text_end.next_multiple_of(4);
847        let rodata_end = rodata_start.next_multiple_of(32);
848        log::warn!(
849            "Cannot determine size of .rodata in unknown autoload {}, using {:#010x}..{:#010x}",
850            autoload_index,
851            rodata_start,
852            rodata_end
853        );
854        self.add_rodata_section(rodata_start, rodata_end)?;
855
856        let data_start = rodata_end;
857        let data_end = base_address + code.len() as u32;
858        self.add_data_section(data_start, data_end)?;
859
860        let bss_start = data_end.next_multiple_of(32);
861        self.add_bss_section(bss_start)?;
862
863        Ok(())
864    }
865
866    fn find_data_from_pools(&mut self, symbol_map: &mut SymbolMap, options: &AnalysisOptions) -> Result<(), ModuleError> {
867        for function in self.sections.functions() {
868            data::find_local_data_from_pools(
869                function,
870                FindLocalDataOptions {
871                    sections: &self.sections,
872                    module_kind: self.kind,
873                    symbol_map,
874                    relocations: &mut self.relocations,
875                    name_prefix: &self.default_data_prefix,
876                    code: &self.code,
877                    base_address: self.base_address,
878                    address_range: None,
879                },
880                options,
881            )?;
882        }
883        Ok(())
884    }
885
886    fn find_data_from_sections(&mut self, symbol_map: &mut SymbolMap, options: &AnalysisOptions) -> Result<(), ModuleError> {
887        for section in self.sections.iter() {
888            match section.kind() {
889                SectionKind::Data | SectionKind::Rodata => {
890                    let code = section.code(&self.code, self.base_address)?.unwrap();
891                    data::find_local_data_from_section(
892                        section,
893                        FindLocalDataOptions {
894                            sections: &self.sections,
895                            module_kind: self.kind,
896                            symbol_map,
897                            relocations: &mut self.relocations,
898                            name_prefix: &self.default_data_prefix,
899                            code,
900                            base_address: self.base_address,
901                            address_range: None,
902                        },
903                        options,
904                    )?;
905                }
906                SectionKind::Code => {
907                    // Look for data in gaps between functions
908                    let mut symbols = symbol_map
909                        .iter_by_address(section.address_range())
910                        .filter(|s| matches!(s.kind, SymbolKind::Function(_)))
911                        .peekable();
912                    let mut gaps = vec![];
913                    while let Some(symbol) = symbols.next() {
914                        if symbol.addr >= 0x2000000 && symbol.addr < 0x2000800 {
915                            // Secure area gaps are just random bytes
916                            continue;
917                        }
918
919                        let next_address = symbols.peek().map(|s| s.addr).unwrap_or(section.end_address());
920                        let end_address = symbol.addr + symbol.size(next_address);
921                        if end_address < next_address {
922                            gaps.push(end_address..next_address);
923                            log::debug!("Found gap between functions from {end_address:#x} to {next_address:#x}");
924                        }
925                    }
926                    for gap in gaps {
927                        if let Some(code) = section.code(&self.code, self.base_address)? {
928                            data::find_local_data_from_section(
929                                section,
930                                FindLocalDataOptions {
931                                    sections: &self.sections,
932                                    module_kind: self.kind,
933                                    symbol_map,
934                                    relocations: &mut self.relocations,
935                                    name_prefix: &self.default_data_prefix,
936                                    code,
937                                    base_address: self.base_address,
938                                    address_range: Some(gap),
939                                },
940                                options,
941                            )?;
942                        }
943                    }
944                }
945                SectionKind::Bss => {}
946            }
947        }
948        Ok(())
949    }
950
951    pub fn relocations(&self) -> &Relocations {
952        &self.relocations
953    }
954
955    pub fn relocations_mut(&mut self) -> &mut Relocations {
956        &mut self.relocations
957    }
958
959    pub fn sections(&self) -> &Sections {
960        &self.sections
961    }
962
963    pub fn sections_mut(&mut self) -> &mut Sections {
964        &mut self.sections
965    }
966
967    pub fn code(&self) -> &[u8] {
968        &self.code
969    }
970
971    pub fn base_address(&self) -> u32 {
972        self.base_address
973    }
974
975    pub fn end_address(&self) -> u32 {
976        self.base_address + self.code.len() as u32 + self.bss_size()
977    }
978
979    pub fn get_function(&self, addr: u32) -> Option<&Function> {
980        self.sections.get_by_contained_address(addr).and_then(|(_, s)| s.functions().get(&addr))
981    }
982
983    pub fn bss_size(&self) -> u32 {
984        self.bss_size
985    }
986
987    pub fn name(&self) -> &str {
988        &self.name
989    }
990
991    pub fn kind(&self) -> ModuleKind {
992        self.kind
993    }
994
995    pub fn signed(&self) -> bool {
996        self.signed
997    }
998}
999
1000#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
1001pub enum ModuleKind {
1002    Arm9,
1003    Overlay(u16),
1004    Autoload(AutoloadKind),
1005}
1006
1007impl Display for ModuleKind {
1008    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1009        match self {
1010            ModuleKind::Arm9 => write!(f, "ARM9 main"),
1011            ModuleKind::Overlay(index) => write!(f, "overlay {index}"),
1012            ModuleKind::Autoload(kind) => match kind {
1013                AutoloadKind::Itcm => write!(f, "ITCM"),
1014                AutoloadKind::Dtcm => write!(f, "DTCM"),
1015                AutoloadKind::Unknown(index) => write!(f, "autoload {index}"),
1016            },
1017        }
1018    }
1019}
1020
1021struct FoundFunctions {
1022    functions: BTreeMap<u32, Function>,
1023    start: u32,
1024    end: u32,
1025}
1026
1027/// Sorted list of .init function addresses
1028struct InitFunctions(BTreeSet<u32>);
1029
1030pub struct AnalysisOptions {
1031    /// Generates function symbols when a local function call doesn't lead to a known function. This can happen if the
1032    /// destination function is encrypted or otherwise wasn't found during function analysis.
1033    pub allow_unknown_function_calls: bool,
1034    /// If true, every relocation in relocs.txt will have a comment explaining where/why it was generated.
1035    pub provide_reloc_source: bool,
1036}