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
609 let secure_area = &self.code[..0x800];
611 let mut functions = Function::find_secure_area_functions(secure_area, self.base_address, symbol_map);
612
613 let build_info_offset = arm9.build_info_offset();
615 let build_info_address = arm9.base_address() + build_info_offset;
616 symbol_map.add_data(Some("BuildInfo".to_string()), build_info_address, SymData::Any)?;
617
618 let autoload_callback_address = arm9.autoload_callback();
620 let name = "AutoloadCallback";
621 let parse_result = Function::parse_function(FunctionParseOptions {
622 name: name.to_string(),
623 start_address: autoload_callback_address,
624 base_address: self.base_address,
625 module_code: self.code,
626 known_end_address: None,
627 module_start_address: self.base_address,
628 module_end_address: self.end_address(),
629 parse_options: Default::default(),
630 check_defs_uses: true,
631 existing_functions: Some(&functions),
632 })?;
633 let autoload_function = match parse_result {
634 ParseFunctionResult::Found(function) => function,
635 _ => return FunctionAnalysisFailedSnafu { name, parse_result }.fail(),
636 };
637 symbol_map.add_function(&autoload_function);
638 functions.insert(autoload_function.first_instruction_address(), autoload_function);
639
640 let FoundFunctions { functions: entry_functions, .. } = self
642 .find_functions(
643 symbol_map,
644 FunctionSearchOptions {
645 start_address: Some(self.base_address + 0x800),
646 end_address: Some(build_info_address),
647 existing_functions: Some(&functions),
648 check_defs_uses: true,
649 ..Default::default()
650 },
651 )?
652 .ok_or_else(|| NoEntryFunctionsSnafu.build())?;
653 functions.extend(entry_functions);
654
655 let exception_start = exception_data.as_ref().and_then(|e| e.exception_start());
657 let text_max = exception_start.unwrap_or(read_only_end);
658 let main_start = self.find_build_info_end_address(arm9);
659 let FoundFunctions { functions: text_functions, end: mut text_end, .. } = self
660 .find_functions(
661 symbol_map,
662 FunctionSearchOptions {
663 start_address: Some(main_start),
664 end_address: Some(text_max),
665 max_function_start_search_distance: u32::MAX,
667 use_data_as_upper_bound: true,
668 check_defs_uses: false,
670 ..Default::default()
671 },
672 )?
673 .ok_or_else(|| NoArm9FunctionsSnafu.build())?;
674 let text_start = self.base_address;
675 functions.extend(text_functions);
676 self.add_text_section(FoundFunctions { functions, start: text_start, end: text_end })?;
677
678 if let Some(exception_data) = exception_data {
680 if let Some(exception_start) = exception_data.exception_start() {
681 self.sections.add(Section::new(SectionOptions {
682 name: ".exception".to_string(),
683 kind: SectionKind::Rodata,
684 start_address: exception_start,
685 end_address: exception_data.exceptix_start(),
686 alignment: 1,
687 functions: None,
688 })?)?;
689 }
690
691 self.sections.add(Section::new(SectionOptions {
692 name: ".exceptix".to_string(),
693 kind: SectionKind::Rodata,
694 start_address: exception_data.exceptix_start(),
695 end_address: exception_data.exceptix_end(),
696 alignment: 4,
697 functions: None,
698 })?)?;
699
700 text_end = exception_data.exceptix_end();
701 }
702
703 let rodata_start = rodata_start.unwrap_or(text_end);
705 self.add_rodata_section(rodata_start, ctor.start)?;
706
707 let data_start = ctor.end.next_multiple_of(32);
709 let data_end = self.base_address + self.code.len() as u32;
710 self.add_data_section(data_start, data_end)?;
711 let bss_start = data_end.next_multiple_of(32);
712 self.add_bss_section(bss_start)?;
713
714 let section_after_text = self.sections.get_section_after(text_end);
715 if let Some(section_after_text) = section_after_text {
716 if text_end != section_after_text.start_address() {
717 log::warn!(
718 "Expected .text to end ({:#010x}) where {} starts ({:#010x})",
719 text_end,
720 section_after_text.name(),
721 section_after_text.start_address()
722 );
723 }
724 }
725
726 Ok(())
727 }
728
729 fn find_build_info_end_address(&self, arm9: &Arm9) -> u32 {
730 let build_info_offset = arm9.build_info_offset();
731 let library_list_start = build_info_offset + 0x24; let mut offset = library_list_start as usize;
734 loop {
735 let Some((library_offset, ch)) = self.code[offset..offset + 4].iter().enumerate().find(|(_, &b)| b != b'0') else {
737 break;
738 };
739 if *ch != b'[' {
740 break;
742 }
743 offset += library_offset;
744
745 let library_length = self.code[offset..].iter().position(|&b| b == b']').unwrap() + 1;
746 offset += library_length + 1; }
748
749 arm9.base_address() + offset.next_multiple_of(4) as u32
750 }
751
752 fn find_sections_itcm(&mut self, symbol_map: &mut SymbolMap) -> Result<(), ModuleError> {
753 let text_functions = self
754 .find_functions(
755 symbol_map,
756 FunctionSearchOptions {
757 max_function_start_search_distance: u32::MAX,
759 check_defs_uses: false,
761 ..Default::default()
762 },
763 )?
764 .ok_or_else(|| NoItcmFunctionsSnafu.build())?;
765 let text_end = text_functions.end;
766 self.add_text_section(text_functions)?;
767
768 let bss_start = text_end.next_multiple_of(32);
769 self.add_bss_section(bss_start)?;
770
771 Ok(())
772 }
773
774 fn find_sections_dtcm(&mut self) -> Result<(), ModuleError> {
775 let data_start = self.base_address;
776 let data_end = data_start + self.code.len() as u32;
777 self.add_data_section(data_start, data_end)?;
778
779 let bss_start = data_end.next_multiple_of(32);
780 self.add_bss_section(bss_start)?;
781
782 Ok(())
783 }
784
785 fn find_sections_unknown_autoload(&mut self, symbol_map: &mut SymbolMap, autoload: &Autoload) -> Result<(), ModuleError> {
786 let base_address = autoload.base_address();
787 let AutoloadKind::Unknown(autoload_index) = autoload.kind() else {
788 panic!("Not an unknown autoload: {}", autoload.kind());
789 };
790 let code = autoload.code();
791
792 let text_functions = self.find_functions(
793 symbol_map,
794 FunctionSearchOptions {
795 max_function_start_search_distance: 32,
796 use_data_as_upper_bound: true,
797 check_defs_uses: false,
799 ..Default::default()
800 },
801 )?;
802
803 let text_end = if let Some(text_functions) = text_functions {
804 let text_end = text_functions.end;
805 self.add_text_section(text_functions)?;
806 text_end
807 } else {
808 self.base_address
809 };
810
811 let rodata_start = text_end.next_multiple_of(4);
812 let rodata_end = rodata_start.next_multiple_of(32);
813 log::warn!(
814 "Cannot determine size of .rodata in unknown autoload {}, using {:#010x}..{:#010x}",
815 autoload_index,
816 rodata_start,
817 rodata_end
818 );
819 self.add_rodata_section(rodata_start, rodata_end)?;
820
821 let data_start = rodata_end;
822 let data_end = base_address + code.len() as u32;
823 self.add_data_section(data_start, data_end)?;
824
825 let bss_start = data_end.next_multiple_of(32);
826 self.add_bss_section(bss_start)?;
827
828 Ok(())
829 }
830
831 fn find_data_from_pools(&mut self, symbol_map: &mut SymbolMap, options: &AnalysisOptions) -> Result<(), ModuleError> {
832 for function in self.sections.functions() {
833 data::find_local_data_from_pools(
834 function,
835 FindLocalDataOptions {
836 sections: &self.sections,
837 module_kind: self.kind,
838 symbol_map,
839 relocations: &mut self.relocations,
840 name_prefix: &self.default_data_prefix,
841 code: self.code,
842 base_address: self.base_address,
843 address_range: None,
844 },
845 options,
846 )?;
847 }
848 Ok(())
849 }
850
851 fn find_data_from_sections(&mut self, symbol_map: &mut SymbolMap, options: &AnalysisOptions) -> Result<(), ModuleError> {
852 for section in self.sections.iter() {
853 match section.kind() {
854 SectionKind::Data | SectionKind::Rodata => {
855 let code = section.code(self.code, self.base_address)?.unwrap();
856 data::find_local_data_from_section(
857 section,
858 FindLocalDataOptions {
859 sections: &self.sections,
860 module_kind: self.kind,
861 symbol_map,
862 relocations: &mut self.relocations,
863 name_prefix: &self.default_data_prefix,
864 code,
865 base_address: self.base_address,
866 address_range: None,
867 },
868 options,
869 )?;
870 }
871 SectionKind::Code => {
872 let mut symbols = symbol_map
874 .iter_by_address(section.address_range())
875 .filter(|s| matches!(s.kind, SymbolKind::Function(_)))
876 .peekable();
877 let mut gaps = vec![];
878 while let Some(symbol) = symbols.next() {
879 if symbol.addr >= 0x2000000 && symbol.addr < 0x2000800 {
880 continue;
882 }
883
884 let next_address = symbols.peek().map(|s| s.addr).unwrap_or(section.end_address());
885 let end_address = symbol.addr + symbol.size(next_address);
886 if end_address < next_address {
887 gaps.push(end_address..next_address);
888 log::debug!("Found gap between functions from {end_address:#x} to {next_address:#x}");
889 }
890 }
891 for gap in gaps {
892 if let Some(code) = section.code(self.code, self.base_address)? {
893 data::find_local_data_from_section(
894 section,
895 FindLocalDataOptions {
896 sections: &self.sections,
897 module_kind: self.kind,
898 symbol_map,
899 relocations: &mut self.relocations,
900 name_prefix: &self.default_data_prefix,
901 code,
902 base_address: self.base_address,
903 address_range: Some(gap),
904 },
905 options,
906 )?;
907 }
908 }
909 }
910 SectionKind::Bss => {}
911 }
912 }
913 Ok(())
914 }
915
916 pub fn relocations(&self) -> &Relocations {
917 &self.relocations
918 }
919
920 pub fn relocations_mut(&mut self) -> &mut Relocations {
921 &mut self.relocations
922 }
923
924 pub fn sections(&self) -> &Sections {
925 &self.sections
926 }
927
928 pub fn sections_mut(&mut self) -> &mut Sections {
929 &mut self.sections
930 }
931
932 pub fn code(&self) -> &[u8] {
933 self.code
934 }
935
936 pub fn base_address(&self) -> u32 {
937 self.base_address
938 }
939
940 pub fn end_address(&self) -> u32 {
941 self.base_address + self.code.len() as u32 + self.bss_size()
942 }
943
944 pub fn get_function(&self, addr: u32) -> Option<&Function> {
945 self.sections.get_by_contained_address(addr).and_then(|(_, s)| s.functions().get(&addr))
946 }
947
948 pub fn bss_size(&self) -> u32 {
949 self.bss_size
950 }
951
952 pub fn name(&self) -> &str {
953 &self.name
954 }
955
956 pub fn kind(&self) -> ModuleKind {
957 self.kind
958 }
959
960 pub fn signed(&self) -> bool {
961 self.signed
962 }
963}
964
965#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
966pub enum ModuleKind {
967 Arm9,
968 Overlay(u16),
969 Autoload(AutoloadKind),
970}
971
972impl Display for ModuleKind {
973 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
974 match self {
975 ModuleKind::Arm9 => write!(f, "ARM9 main"),
976 ModuleKind::Overlay(index) => write!(f, "overlay {index}"),
977 ModuleKind::Autoload(kind) => match kind {
978 AutoloadKind::Itcm => write!(f, "ITCM"),
979 AutoloadKind::Dtcm => write!(f, "DTCM"),
980 AutoloadKind::Unknown(index) => write!(f, "autoload {index}"),
981 },
982 }
983 }
984}
985
986struct FoundFunctions {
987 functions: BTreeMap<u32, Function>,
988 start: u32,
989 end: u32,
990}
991
992struct InitFunctions(BTreeSet<u32>);
994
995pub struct AnalysisOptions {
996 pub allow_unknown_function_calls: bool,
999 pub provide_reloc_source: bool,
1001}