Skip to content

Commit 51cb6ea

Browse files
authored
Merge pull request rust-lang#30 from eddyb/trailing-dots
v0: also support preserving extra suffixes found after mangled symbol.
2 parents 016ca6e + c1eeee6 commit 51cb6ea

File tree

3 files changed

+76
-58
lines changed

3 files changed

+76
-58
lines changed

src/legacy.rs

+29-36
Original file line numberDiff line numberDiff line change
@@ -46,64 +46,57 @@ pub struct Demangle<'a> {
4646
// Note that this demangler isn't quite as fancy as it could be. We have lots
4747
// of other information in our symbols like hashes, version, type information,
4848
// etc. Additionally, this doesn't handle glue symbols at all.
49-
pub fn demangle(s: &str) -> Result<Demangle, ()> {
49+
pub fn demangle(s: &str) -> Result<(Demangle, &str), ()> {
5050
// First validate the symbol. If it doesn't look like anything we're
5151
// expecting, we just print it literally. Note that we must handle non-Rust
5252
// symbols because we could have any function in the backtrace.
53-
let inner;
54-
if s.len() > 4 && s.starts_with("_ZN") && s.ends_with('E') {
55-
inner = &s[3..s.len() - 1];
56-
} else if s.len() > 3 && s.starts_with("ZN") && s.ends_with('E') {
53+
let inner = if s.starts_with("_ZN") {
54+
&s[3..]
55+
} else if s.starts_with("ZN") {
5756
// On Windows, dbghelp strips leading underscores, so we accept "ZN...E"
5857
// form too.
59-
inner = &s[2..s.len() - 1];
60-
} else if s.len() > 5 && s.starts_with("__ZN") && s.ends_with('E') {
58+
&s[2..]
59+
} else if s.starts_with("__ZN") {
6160
// On OSX, symbols are prefixed with an extra _
62-
inner = &s[4..s.len() - 1];
61+
&s[4..]
6362
} else {
6463
return Err(());
65-
}
64+
};
6665

6766
// only work with ascii text
6867
if inner.bytes().any(|c| c & 0x80 != 0) {
6968
return Err(());
7069
}
7170

7271
let mut elements = 0;
73-
let mut chars = inner.chars().peekable();
74-
loop {
75-
let mut i = 0usize;
76-
while let Some(&c) = chars.peek() {
77-
if !c.is_digit(10) {
78-
break
79-
}
80-
chars.next();
81-
let next = i.checked_mul(10)
82-
.and_then(|i| i.checked_add(c as usize - '0' as usize));
83-
i = match next {
84-
Some(i) => i,
85-
None => {
86-
return Err(());
87-
}
88-
};
72+
let mut chars = inner.chars();
73+
let mut c = try!(chars.next().ok_or(()));
74+
while c != 'E' {
75+
// Decode an identifier element's length.
76+
if !c.is_digit(10) {
77+
return Err(());
78+
}
79+
let mut len = 0usize;
80+
while let Some(d) = c.to_digit(10) {
81+
len = try!(len.checked_mul(10)
82+
.and_then(|len| len.checked_add(d as usize))
83+
.ok_or(()));
84+
c = try!(chars.next().ok_or(()));
8985
}
9086

91-
if i == 0 {
92-
if !chars.next().is_none() {
93-
return Err(());
94-
}
95-
break;
96-
} else if chars.by_ref().take(i).count() != i {
97-
return Err(());
98-
} else {
99-
elements += 1;
87+
// `c` already contains the first character of this identifier, skip it and
88+
// all the other characters of this identifier, to reach the next element.
89+
for _ in 0..len {
90+
c = try!(chars.next().ok_or(()));
10091
}
92+
93+
elements += 1;
10194
}
10295

103-
Ok(Demangle {
96+
Ok((Demangle {
10497
inner: inner,
10598
elements: elements,
106-
})
99+
}, chars.as_str()))
107100
}
108101

109102
// Rust hashes are hex digits with an `h` prepended.

src/lib.rs

+21-13
Original file line numberDiff line numberDiff line change
@@ -81,25 +81,33 @@ pub fn demangle(mut s: &str) -> Demangle {
8181
}
8282
}
8383

84-
// Output like LLVM IR adds extra period-delimited words. See if
85-
// we are in that case and save the trailing words if so.
8684
let mut suffix = "";
87-
if let Some(i) = s.rfind("E.") {
88-
let (head, tail) = s.split_at(i + 1); // After the E, before the period
89-
90-
if is_symbol_like(tail) {
91-
s = head;
92-
suffix = tail;
85+
let mut style = match legacy::demangle(s) {
86+
Ok((d, s)) => {
87+
suffix = s;
88+
Some(DemangleStyle::Legacy(d))
9389
}
94-
}
95-
96-
let style = match legacy::demangle(s) {
97-
Ok(d) => Some(DemangleStyle::Legacy(d)),
9890
Err(()) => match v0::demangle(s) {
99-
Ok(d) => Some(DemangleStyle::V0(d)),
91+
Ok((d, s)) => {
92+
suffix = s;
93+
Some(DemangleStyle::V0(d))
94+
}
10095
Err(v0::Invalid) => None,
10196
},
10297
};
98+
99+
// Output like LLVM IR adds extra period-delimited words. See if
100+
// we are in that case and save the trailing words if so.
101+
if !suffix.is_empty() {
102+
if suffix.starts_with(".") && is_symbol_like(suffix) {
103+
// Keep the suffix.
104+
} else {
105+
// Reset the suffix and invalidate the demangling.
106+
suffix = "";
107+
style = None;
108+
}
109+
}
110+
103111
Demangle {
104112
style: style,
105113
original: s,

src/v0.rs

+26-9
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ pub struct Demangle<'a> {
1212
/// This function will take a **mangled** symbol and return a value. When printed,
1313
/// the de-mangled version will be written. If the symbol does not look like
1414
/// a mangled symbol, the original value will be written instead.
15-
pub fn demangle(s: &str) -> Result<Demangle, Invalid> {
15+
pub fn demangle(s: &str) -> Result<(Demangle, &str), Invalid> {
1616
// First validate the symbol. If it doesn't look like anything we're
1717
// expecting, we just print it literally. Note that we must handle non-Rust
1818
// symbols because we could have any function in the backtrace.
@@ -47,17 +47,18 @@ pub fn demangle(s: &str) -> Result<Demangle, Invalid> {
4747
next: 0,
4848
};
4949
try!(parser.skip_path());
50-
if parser.next < parser.sym.len() {
51-
// Instantiating crate.
52-
try!(parser.skip_path());
53-
}
54-
if parser.next != parser.sym.len() {
55-
return Err(Invalid);
50+
51+
// Instantiating crate (paths always start with uppercase characters).
52+
match parser.sym.as_bytes().get(parser.next) {
53+
Some(&b'A'...b'Z') => {
54+
try!(parser.skip_path());
55+
}
56+
_ => {}
5657
}
5758

58-
Ok(Demangle {
59+
Ok((Demangle {
5960
inner: inner,
60-
})
61+
}, &parser.sym[parser.next..]))
6162
}
6263

6364
impl<'s> Display for Demangle<'s> {
@@ -1064,4 +1065,20 @@ mod tests {
10641065
((((_, _), (_, _)), ((_, _), (_, _))), (((_, _), (_, _)), ((_, _), (_, _))))))"
10651066
);
10661067
}
1068+
1069+
#[test]
1070+
fn demangle_thinlto() {
1071+
t_nohash!("_RC3foo.llvm.9D1C9369", "foo");
1072+
t_nohash!("_RC3foo.llvm.9D1C9369@@16", "foo");
1073+
t_nohash!("_RNvC9backtrace3foo.llvm.A5310EB9", "backtrace::foo");
1074+
}
1075+
1076+
#[test]
1077+
fn demangle_extra_suffix() {
1078+
// From alexcrichton/rustc-demangle#27:
1079+
t_nohash!(
1080+
"_RNvNtNtNtNtCs92dm3009vxr_4rand4rngs7adapter9reseeding4fork23FORK_HANDLER_REGISTERED.0.0",
1081+
"rand::rngs::adapter::reseeding::fork::FORK_HANDLER_REGISTERED.0.0"
1082+
);
1083+
}
10671084
}

0 commit comments

Comments
 (0)