Skip to content

Commit 23654c7

Browse files
committed
legacy: handle extra suffixes after parsing the _ZN...E part of the symbol name.
1 parent d0fc0e1 commit 23654c7

File tree

3 files changed

+53
-52
lines changed

3 files changed

+53
-52
lines changed

src/legacy.rs

Lines changed: 29 additions & 36 deletions
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

Lines changed: 21 additions & 13 deletions
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

Lines changed: 3 additions & 3 deletions
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.
@@ -55,9 +55,9 @@ pub fn demangle(s: &str) -> Result<Demangle, Invalid> {
5555
return Err(Invalid);
5656
}
5757

58-
Ok(Demangle {
58+
Ok((Demangle {
5959
inner: inner,
60-
})
60+
}, ""))
6161
}
6262

6363
impl<'s> Display for Demangle<'s> {

0 commit comments

Comments
 (0)