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