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 #[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 #[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 #[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 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 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 }
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 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 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 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 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 let secure_area = &self.code[..0x800];
641 let mut functions = Function::find_secure_area_functions(secure_area, self.base_address, symbol_map);
642
643 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 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 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 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 max_function_start_search_distance: u32::MAX,
698 use_data_as_upper_bound: true,
699 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 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 let rodata_start = rodata_start.unwrap_or(text_end);
737 self.add_rodata_section(rodata_start, ctor.start)?;
738
739 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; let mut offset = library_list_start as usize;
766 loop {
767 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 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; }
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 max_function_start_search_distance: u32::MAX,
792 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 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 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 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
1027struct InitFunctions(BTreeSet<u32>);
1029
1030pub struct AnalysisOptions {
1031 pub allow_unknown_function_calls: bool,
1034 pub provide_reloc_source: bool,
1036}