Skip to content

Commit 278683f

Browse files
authored
Improve automatic symbol pairing for functions with compiler-generated names (#303)
* Fix `__arraydtor$1234`s sometimes being swapped The list of symbols is not necessarily sorted by address, so if there are multiple `__arraydtor$1234` functions it's possible that they're in reverse order on the right, which would cause them to be paired up incorrectly. To fix this we sort by section index and symbol address after filtering down the list of symbols to ones that have matching names. * Support pairing up symbols for anonymous classes * Disallow exact-name pairups for compiler-generated symbols
1 parent 6ad60de commit 278683f

File tree

2 files changed

+29
-17
lines changed

2 files changed

+29
-17
lines changed

objdiff-core/src/diff/data.rs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,25 @@ pub fn diff_bss_symbol(
3636
}
3737

3838
pub fn symbol_name_matches(left_name: &str, right_name: &str) -> bool {
39-
// Match Metrowerks symbol$1234 against symbol$2345
40-
// and GCC symbol.1234 against symbol.2345
41-
if let Some((prefix, suffix)) = left_name.split_once(['$', '.']) {
42-
if !suffix.chars().all(char::is_numeric) {
43-
return false;
39+
if let Some((left_prefix, left_suffix)) = left_name.split_once("@class$")
40+
&& let Some((right_prefix, right_suffix)) = right_name.split_once("@class$")
41+
{
42+
// Match Metrowerks anonymous class symbol names, ignoring the unique ID.
43+
// e.g. __dt__Q29dCamera_c23@class$3665d_camera_cppFv
44+
if left_prefix == right_prefix
45+
&& let Some(left_idx) = left_suffix.chars().position(|c| !c.is_numeric())
46+
&& let Some(right_idx) = right_suffix.chars().position(|c| !c.is_numeric())
47+
{
48+
// e.g. d_camera_cppFv (after the unique ID)
49+
left_suffix[left_idx..] == right_suffix[right_idx..]
50+
} else {
51+
false
4452
}
53+
} else if let Some((prefix, suffix)) = left_name.split_once(['$', '.'])
54+
&& suffix.chars().all(char::is_numeric)
55+
{
56+
// Match Metrowerks symbol$1234 against symbol$2345
57+
// and GCC symbol.1234 against symbol.2345
4558
right_name
4659
.split_once(['$', '.'])
4760
.is_some_and(|(p, s)| p == prefix && s.chars().all(char::is_numeric))

objdiff-core/src/diff/mod.rs

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use alloc::{
77
use core::{num::NonZeroU32, ops::Range};
88

99
use anyhow::Result;
10+
use itertools::Itertools;
1011

1112
use crate::{
1213
diff::{
@@ -759,18 +760,16 @@ fn find_symbol(
759760
return closest_match_symbol_idx;
760761
}
761762

762-
// Try to find an exact name match
763-
if let Some((symbol_idx, _)) = unmatched_symbols(obj, used).find(|(_, symbol)| {
764-
symbol.name == in_symbol.name && symbol_section_kind(obj, symbol) == section_kind
765-
}) {
766-
return Some(symbol_idx);
767-
}
768-
769-
if let Some((symbol_idx, _)) = unmatched_symbols(obj, used).find(|&(_, symbol)| {
770-
symbol_name_matches(&in_symbol.name, &symbol.name)
771-
&& symbol_section_kind(obj, symbol) == section_kind
772-
&& symbol_section(obj, symbol).is_some_and(|(name, _)| name == section_name)
773-
}) {
763+
// Try to find a symbol with a matching name
764+
if let Some((symbol_idx, _)) = unmatched_symbols(obj, used)
765+
.filter(|&(_, symbol)| {
766+
symbol_name_matches(&in_symbol.name, &symbol.name)
767+
&& symbol_section_kind(obj, symbol) == section_kind
768+
&& symbol_section(obj, symbol).is_some_and(|(name, _)| name == section_name)
769+
})
770+
.sorted_unstable_by_key(|&(_, symbol)| (symbol.section, symbol.address))
771+
.next()
772+
{
774773
return Some(symbol_idx);
775774
}
776775

0 commit comments

Comments
 (0)