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