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