@@ -11,14 +11,13 @@ use itertools::Itertools;
1111use crate :: {
1212 analysis:: {
1313 executor:: { ExecCbData , ExecCbResult , Executor } ,
14- skip_alignment,
1514 slices:: { FunctionSlices , TailCallResult } ,
1615 vm:: { BranchTarget , GprValue , StepResult , VM } ,
1716 RelocationTarget ,
1817 } ,
1918 obj:: {
20- ObjInfo , ObjSectionKind , ObjSymbol , ObjSymbolFlagSet , ObjSymbolFlags , ObjSymbolKind ,
21- SectionIndex ,
19+ ObjInfo , ObjSection , ObjSectionKind , ObjSymbol , ObjSymbolFlagSet , ObjSymbolFlags ,
20+ ObjSymbolKind , SectionIndex ,
2221 } ,
2322 util:: config:: create_auto_symbol_name,
2423} ;
@@ -125,9 +124,21 @@ pub struct AnalyzerState {
125124 pub jump_tables : BTreeMap < SectionAddress , u32 > ,
126125 pub known_symbols : BTreeMap < SectionAddress , Vec < ObjSymbol > > ,
127126 pub known_sections : BTreeMap < SectionIndex , String > ,
127+ pub skip_ranges : BTreeMap < SectionAddress , SectionAddress > ,
128128}
129129
130130impl AnalyzerState {
131+ pub fn new ( skip_ranges : BTreeMap < SectionAddress , SectionAddress > ) -> Self {
132+ Self {
133+ sda_bases : None ,
134+ functions : BTreeMap :: new ( ) ,
135+ jump_tables : BTreeMap :: new ( ) ,
136+ known_symbols : BTreeMap :: new ( ) ,
137+ known_sections : BTreeMap :: new ( ) ,
138+ skip_ranges,
139+ }
140+ }
141+
131142 pub fn apply ( & self , obj : & mut ObjInfo ) -> Result < ( ) > {
132143 for ( & section_index, section_name) in & self . known_sections {
133144 obj. sections [ section_index] . rename ( section_name. clone ( ) ) ?;
@@ -371,12 +382,7 @@ impl AnalyzerState {
371382 log:: trace!( "Finalizing {:#010X}" , addr) ;
372383 slices. finalize ( obj, & self . functions ) ?;
373384 for address in slices. function_references . iter ( ) . cloned ( ) {
374- // Only create functions for code sections
375- // Some games use branches to data sections to prevent dead stripping (Mario Party)
376- if matches ! ( obj. sections. get( address. section) , Some ( section) if section. kind == ObjSectionKind :: Code )
377- {
378- self . functions . entry ( address) . or_default ( ) ;
379- }
385+ self . try_add_function ( obj, address) ;
380386 }
381387 self . jump_tables . append ( & mut slices. jump_table_references . clone ( ) ) ;
382388 let end = slices. end ( ) ;
@@ -390,6 +396,25 @@ impl AnalyzerState {
390396 Ok ( finalized_any)
391397 }
392398
399+ fn try_add_function ( & mut self , obj : & ObjInfo , address : SectionAddress ) {
400+ // Only create functions for code sections
401+ // Some games use branches to data sections to prevent dead stripping (Mario Party)
402+ if !matches ! ( obj. sections. get( address. section) , Some ( section) if section. kind == ObjSectionKind :: Code )
403+ // Avoid creating functions in skipped ranges
404+ || self . in_skipped_range ( address)
405+ {
406+ return ;
407+ }
408+ self . functions . entry ( address) . or_default ( ) ;
409+ }
410+
411+ fn in_skipped_range ( & self , address : SectionAddress ) -> bool {
412+ match self . skip_ranges . range ( ..=address) . next_back ( ) {
413+ Some ( ( & start, & end) ) => address >= start && address < end,
414+ None => false ,
415+ }
416+ }
417+
393418 fn first_unbounded_function ( & self ) -> Option < SectionAddress > {
394419 self . functions . iter ( ) . find ( |( _, info) | !info. is_analyzed ( ) ) . map ( |( & addr, _) | addr)
395420 }
@@ -414,12 +439,7 @@ impl AnalyzerState {
414439 pub fn process_function_at ( & mut self , obj : & ObjInfo , addr : SectionAddress ) -> Result < bool > {
415440 Ok ( if let Some ( mut slices) = self . process_function ( obj, addr) ? {
416441 for address in slices. function_references . iter ( ) . cloned ( ) {
417- // Only create functions for code sections
418- // Some games use branches to data sections to prevent dead stripping (Mario Party)
419- if matches ! ( obj. sections. get( address. section) , Some ( section) if section. kind == ObjSectionKind :: Code )
420- {
421- self . functions . entry ( address) . or_default ( ) ;
422- }
442+ self . try_add_function ( obj, address) ;
423443 }
424444 self . jump_tables . append ( & mut slices. jump_table_references . clone ( ) ) ;
425445 if slices. can_finalize ( ) {
@@ -470,7 +490,7 @@ impl AnalyzerState {
470490 if first_end > second {
471491 bail ! ( "Overlapping functions {}-{} -> {}" , first, first_end, second) ;
472492 }
473- let addr = match skip_alignment ( section, first_end, second) {
493+ let addr = match self . skip_alignment ( section, first_end, second) {
474494 Some ( addr) => addr,
475495 None => continue ,
476496 } ;
@@ -489,7 +509,7 @@ impl AnalyzerState {
489509 ( Some ( ( last, last_info) ) , None ) => {
490510 let Some ( last_end) = last_info. end else { continue } ;
491511 if last_end < section_end {
492- let addr = match skip_alignment ( section, last_end, section_end) {
512+ let addr = match self . skip_alignment ( section, last_end, section_end) {
493513 Some ( addr) => addr,
494514 None => continue ,
495515 } ;
@@ -516,6 +536,33 @@ impl AnalyzerState {
516536 }
517537 Ok ( found_new)
518538 }
539+
540+ fn skip_alignment (
541+ & self ,
542+ section : & ObjSection ,
543+ mut addr : SectionAddress ,
544+ end : SectionAddress ,
545+ ) -> Option < SectionAddress > {
546+ loop {
547+ if let Some ( ( & start, & end) ) = self . skip_ranges . range ( ..=addr) . next_back ( ) {
548+ if addr >= start && addr < end {
549+ addr = end;
550+ }
551+ } ;
552+ if addr. address + 4 > end. address {
553+ break None ;
554+ }
555+ let data = match section. data_range ( addr. address , addr. address + 4 ) {
556+ Ok ( data) => data,
557+ Err ( _) => return None ,
558+ } ;
559+ if data == [ 0u8 ; 4 ] {
560+ addr += 4 ;
561+ } else {
562+ break Some ( addr) ;
563+ }
564+ }
565+ }
519566}
520567
521568/// Execute VM from entry point following branches and function calls
0 commit comments