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