1- #![ allow( unused) ]
2-
3- // use ar::Archive;
41use object:: read:: archive:: { ArchiveFile , ArchiveMember } ;
5- use object:: read:: elf:: FileHeader ;
6- use object:: { Object , ObjectSection , ObjectSymbol , Symbol , SymbolKind , SymbolScope , SymbolSection } ;
7- use std:: collections:: { BTreeMap , HashSet } ;
8- use std:: error:: Error ;
2+ use object:: { Object , ObjectSymbol , Symbol , SymbolKind , SymbolScope , SymbolSection } ;
3+ use std:: collections:: { BTreeMap , BTreeSet } ;
94use std:: fs;
10- use std:: hash:: Hash ;
11- use std:: path:: { Path , PathBuf } ;
12-
13- type Result < T , E = Box < dyn Error > > = std:: result:: Result < T , E > ;
5+ use std:: path:: Path ;
146
157const USAGE : & str = "Usage:
16- symbol-check check-duplicates PATH...
17- symbol-check check-core-syms PATH...
8+
9+ symbol-check check-duplicates PATHS...
10+ symbol-check check-core-syms PATHS...
1811" ;
1912
2013fn main ( ) {
2114 let args = std:: env:: args ( ) . collect :: < Vec < _ > > ( ) ;
22- let args_ref = args. iter ( ) . map ( |arg| arg . as_str ( ) ) . collect :: < Vec < _ > > ( ) ;
15+ let args_ref = args. iter ( ) . map ( String :: as_str) . collect :: < Vec < _ > > ( ) ;
2316
2417 match & args_ref[ 1 ..] {
2518 [ "check-duplicates" , rest @ ..] if !rest. is_empty ( ) => {
26- rest. iter ( ) . for_each ( verify_no_duplicates)
19+ rest. iter ( ) . for_each ( verify_no_duplicates) ;
2720 }
2821 [ "check-core-syms" , rest @ ..] if !rest. is_empty ( ) => {
29- rest. iter ( ) . for_each ( verify_no_duplicates )
22+ rest. iter ( ) . for_each ( verify_core_symbols ) ;
3023 }
3124 _ => {
3225 println ! ( "{USAGE}" ) ;
3326 std:: process:: exit ( 1 ) ;
3427 }
3528 }
36-
37- // Raise an error if the same symbol is present in multiple object files
3829}
3930
31+ #[ expect( unused) ] // only for printing
4032#[ derive( Clone , Debug ) ]
4133struct SymInfo {
4234 name : String ,
@@ -53,7 +45,7 @@ struct SymInfo {
5345}
5446
5547impl SymInfo {
56- fn new ( sym : Symbol , member : & ArchiveMember ) -> Self {
48+ fn new ( sym : & Symbol , member : & ArchiveMember ) -> Self {
5749 Self {
5850 name : sym. name ( ) . expect ( "missing name" ) . to_owned ( ) ,
5951 kind : sym. kind ( ) ,
@@ -70,56 +62,87 @@ impl SymInfo {
7062 }
7163}
7264
65+ /// Ensure that the same global symbol isn't defined in multiple object files within an archive.
7366fn verify_no_duplicates ( path : impl AsRef < Path > ) {
74- println ! ( "Checking for duplicates at {:? }" , path. as_ref( ) ) ;
67+ println ! ( "Checking for duplicates at {}" , path. as_ref( ) . display ( ) ) ;
7568
76- // Global defined symbols
7769 let mut syms = BTreeMap :: < String , SymInfo > :: new ( ) ;
7870 let mut dups = Vec :: new ( ) ;
7971
8072 for_each_symbol ( path, |sym, member| {
81- if sym. is_global ( ) && !sym. is_undefined ( ) {
82- let info = SymInfo :: new ( sym, member) ;
83- match syms. get ( & info. name ) {
84- Some ( existing) => {
85- dups. push ( info) ;
86- dups. push ( existing. clone ( ) ) ;
87- }
88- None => {
89- syms. insert ( info. name . clone ( ) , info) ;
90- }
73+ if !sym. is_global ( ) || sym. is_undefined ( ) {
74+ // Only check defined globals
75+ return ;
76+ }
77+
78+ let info = SymInfo :: new ( & sym, member) ;
79+ match syms. get ( & info. name ) {
80+ Some ( existing) => {
81+ dups. push ( info) ;
82+ dups. push ( existing. clone ( ) ) ;
83+ }
84+ None => {
85+ syms. insert ( info. name . clone ( ) , info) ;
9186 }
9287 }
93- Ok ( ( ) )
94- } )
95- . unwrap ( ) ;
88+ } ) ;
89+
90+ if cfg ! ( windows) {
91+ let allowed_dup_pfx = [ "__real@" , "__xmm@" ] ;
92+ dups. retain ( |sym| !allowed_dup_pfx. iter ( ) . any ( |pfx| sym. name . starts_with ( pfx) ) ) ;
93+ }
9694
9795 if !dups. is_empty ( ) {
9896 dups. sort_unstable_by ( |a, b| a. name . cmp ( & b. name ) ) ;
9997 panic ! ( "Found duplicate symbols: {dups:#?}" ) ;
10098 }
99+
100+ println ! ( "success: no duplicate symbols found" ) ;
101101}
102102
103103fn verify_core_symbols ( path : impl AsRef < Path > ) {
104- todo ! ( )
104+ println ! (
105+ "Checking for references to core at {}" ,
106+ path. as_ref( ) . display( )
107+ ) ;
108+
109+ let mut defined = BTreeSet :: new ( ) ;
110+ let mut undefined = Vec :: new ( ) ;
111+
112+ for_each_symbol ( path, |sym, member| {
113+ if !sym. name ( ) . unwrap ( ) . contains ( "_ZN4core" ) {
114+ return ;
115+ }
116+
117+ let info = SymInfo :: new ( & sym, member) ;
118+ if info. is_undefined {
119+ undefined. push ( info) ;
120+ } else {
121+ defined. insert ( info. name ) ;
122+ }
123+ } ) ;
124+
125+ undefined. retain ( |sym| !defined. contains ( & sym. name ) ) ;
126+
127+ if !undefined. is_empty ( ) {
128+ undefined. sort_unstable_by ( |a, b| a. name . cmp ( & b. name ) ) ;
129+ panic ! ( "Found undefined symbols from `core`: {undefined:#?}" ) ;
130+ }
131+
132+ println ! ( "success: no undefined references to core found" ) ;
105133}
106134
107135/// For a given archive path, do something with each symbol.
108- fn for_each_symbol (
109- path : impl AsRef < Path > ,
110- mut f : impl FnMut ( Symbol , & ArchiveMember ) -> Result < ( ) > ,
111- ) -> Result < ( ) > {
112- let archive_data = fs:: read ( path) ?;
113- let x = ArchiveFile :: parse ( archive_data. as_slice ( ) ) ?;
136+ fn for_each_symbol ( path : impl AsRef < Path > , mut f : impl FnMut ( Symbol , & ArchiveMember ) ) {
137+ let archive_data = fs:: read ( path) . expect ( "reading file failed" ) ;
138+ let x = ArchiveFile :: parse ( archive_data. as_slice ( ) ) . expect ( "archive parse failed" ) ;
114139 for member in x. members ( ) {
115140 let member = member. unwrap ( ) ;
116141 let data = member. data ( & * archive_data) . unwrap ( ) ;
117- let obj = object:: File :: parse ( data) ? ;
142+ let obj = object:: File :: parse ( data) . expect ( "object parse failed" ) ;
118143
119144 for sym in obj. symbols ( ) {
120- f ( sym, & member) ? ;
145+ f ( sym, & member) ;
121146 }
122147 }
123-
124- Ok ( ( ) )
125148}
0 commit comments