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