@@ -40,20 +40,40 @@ fn map_section_kind(section: &object::Section) -> SectionKind {
4040 }
4141}
4242
43+ /// Normalize Metrowerks class names that are suffixed with a unique ID and the source filename.
44+ /// This is done on the demangled name as the mangled names include the length of the name before
45+ /// the name, which varies depending on the length of the unique ID.
46+ fn normalize_mwcc_unique_id_with_filename ( demangled_name : & str ) -> Option < String > {
47+ const DUMMY_UNIQUE_ID : & str = "$0000" ;
48+ let mut parts = Vec :: new ( ) ;
49+ let mut next = demangled_name;
50+ while let Some ( ( prefix, suffix) ) = next. split_once ( "$" )
51+ && let Some ( idx) = suffix. chars ( ) . position ( |c| !c. is_numeric ( ) )
52+ && idx > 0
53+ {
54+ parts. push ( prefix) ;
55+ next = & suffix[ idx..] ;
56+ }
57+ parts. push ( next) ;
58+ if parts. len ( ) >= 2 {
59+ return Some ( parts. join ( DUMMY_UNIQUE_ID ) ) ;
60+ }
61+ None
62+ }
63+
4364/// Check if a symbol's name is partially compiler-generated, and if so normalize it for pairing.
4465/// e.g. symbol$1234 and symbol$2345 will both be replaced with symbol$0000 internally.
45- fn get_normalized_symbol_name ( name : & str ) -> Option < String > {
66+ fn get_normalized_symbol_name ( name : & str , demangled_name : & Option < String > ) -> Option < String > {
4667 const DUMMY_UNIQUE_ID : & str = "0000" ;
4768 const DUMMY_UNIQUE_MSVC_ID : & str = "00000000" ;
48- if let Some ( ( prefix, suffix) ) = name. split_once ( "@class$" )
69+ if let Some ( demangled_name) = demangled_name
70+ && let Some ( ( _, suffix) ) = name. split_once ( "$" )
4971 && let Some ( idx) = suffix. chars ( ) . position ( |c| !c. is_numeric ( ) )
5072 && idx > 0
5173 {
52- // Match Metrowerks anonymous class symbol names, ignoring the unique ID.
53- // e.g. __dt__Q29dCamera_c23@class$3665d_camera_cppFv
54- // and: __dt__Q29dCamera_c23@class$1727d_camera_cppFv
55- let suffix = & suffix[ idx..] ;
56- Some ( format ! ( "{prefix}@class${DUMMY_UNIQUE_ID}{suffix}" ) )
74+ // Match Metrowerks symbols that have a class name, a unique ID, and the source filename.
75+ // Unlike the other normalizations, this is done on the demangled name.
76+ normalize_mwcc_unique_id_with_filename ( demangled_name)
5777 } else if let Some ( ( prefix, suffix) ) = name. split_once ( '$' )
5878 && suffix. chars ( ) . all ( char:: is_numeric)
5979 {
@@ -174,7 +194,7 @@ fn map_symbol(
174194 . and_then ( |m| m. virtual_addresses . as_ref ( ) )
175195 . and_then ( |v| v. get ( symbol. index ( ) . 0 ) . cloned ( ) ) ;
176196 let section = symbol. section_index ( ) . and_then ( |i| section_indices. get ( i. 0 ) . copied ( ) ) ;
177- let normalized_name = get_normalized_symbol_name ( & name) ;
197+ let normalized_name = get_normalized_symbol_name ( & name, & demangled_name ) ;
178198 if is_symbol_name_compiler_generated ( & name) {
179199 flags |= SymbolFlag :: CompilerGenerated ;
180200 }
@@ -1205,6 +1225,48 @@ fn parse_mw_comment_syms(obj_file: &object::File) -> Result<Option<Vec<CommentSy
12051225#[ cfg( test) ]
12061226mod test {
12071227 use super :: * ;
1228+ use crate :: diff:: Demangler ;
1229+
1230+ #[ test]
1231+ fn test_get_normalized_symbol_name ( ) {
1232+ // Metrowerks in-function static variable.
1233+ let left = "eff_scale$24884" ;
1234+ let right = "eff_scale$21920" ;
1235+ assert_eq ! (
1236+ get_normalized_symbol_name( left, & Demangler :: Codewarrior . demangle( left) ) ,
1237+ get_normalized_symbol_name( right, & Demangler :: Codewarrior . demangle( right) )
1238+ ) ;
1239+
1240+ // Metrowerks anonymous class. Uses @class prefix, unique ID, then filename suffix.
1241+ let left = "__dt__Q29dCamera_c23@class$3665d_camera_cppFv" ;
1242+ let right = "__dt__Q29dCamera_c23@class$1727d_camera_cppFv" ;
1243+ assert_eq ! (
1244+ get_normalized_symbol_name( left, & Demangler :: Codewarrior . demangle( left) ) ,
1245+ get_normalized_symbol_name( right, & Demangler :: Codewarrior . demangle( right) )
1246+ ) ;
1247+ // Metrowerks class defined in function body. Uses class name prefix, unique ID, then filename suffix.
1248+ let left = "makeDL__Q219TMBindShadowManager26TSetup1$2172ShadowUtil_cppFv" ;
1249+ let right = "makeDL__Q219TMBindShadowManager25TSetup1$874ShadowUtil_cppFv" ;
1250+ assert_eq ! (
1251+ get_normalized_symbol_name( left, & Demangler :: Codewarrior . demangle( left) ) ,
1252+ get_normalized_symbol_name( right, & Demangler :: Codewarrior . demangle( right) )
1253+ ) ;
1254+ // Metrowerks class defined in function body, but the unique ID appears again within the function parameters.
1255+ let left = "__as__Q210daB_ZANT_c31dZantSph_c$132966d_a_b_zant_cppFRCQ210daB_ZANT_c31dZantSph_c$132966d_a_b_zant_cpp" ;
1256+ let right = "__as__Q210daB_ZANT_c30dZantSph_c$55068d_a_b_zant_cppFRCQ210daB_ZANT_c30dZantSph_c$55068d_a_b_zant_cpp" ;
1257+ assert_eq ! (
1258+ get_normalized_symbol_name( left, & Demangler :: Codewarrior . demangle( left) ) ,
1259+ get_normalized_symbol_name( right, & Demangler :: Codewarrior . demangle( right) )
1260+ ) ;
1261+
1262+ // MSVC anonymous class.
1263+ let left = "?CheckContextOr@?A0x24773155@@YA_NPBVDataArray@@@Z" ;
1264+ let right = "?CheckContextOr@?A0xddf6240c@@YA_NPBVDataArray@@@Z" ;
1265+ assert_eq ! (
1266+ get_normalized_symbol_name( left, & Demangler :: Msvc . demangle( left) ) ,
1267+ get_normalized_symbol_name( right, & Demangler :: Msvc . demangle( right) )
1268+ ) ;
1269+ }
12081270
12091271 #[ test]
12101272 fn test_combine_sections ( ) {
0 commit comments