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