Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v0: also support preserving extra suffixes found after mangled symbol. #30

Merged
merged 3 commits into from
Aug 13, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 29 additions & 36 deletions src/legacy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,64 +46,57 @@ pub struct Demangle<'a> {
// Note that this demangler isn't quite as fancy as it could be. We have lots
// of other information in our symbols like hashes, version, type information,
// etc. Additionally, this doesn't handle glue symbols at all.
pub fn demangle(s: &str) -> Result<Demangle, ()> {
pub fn demangle(s: &str) -> Result<(Demangle, &str), ()> {
// First validate the symbol. If it doesn't look like anything we're
// expecting, we just print it literally. Note that we must handle non-Rust
// symbols because we could have any function in the backtrace.
let inner;
if s.len() > 4 && s.starts_with("_ZN") && s.ends_with('E') {
inner = &s[3..s.len() - 1];
} else if s.len() > 3 && s.starts_with("ZN") && s.ends_with('E') {
let inner = if s.starts_with("_ZN") {
&s[3..]
} else if s.starts_with("ZN") {
// On Windows, dbghelp strips leading underscores, so we accept "ZN...E"
// form too.
inner = &s[2..s.len() - 1];
} else if s.len() > 5 && s.starts_with("__ZN") && s.ends_with('E') {
&s[2..]
} else if s.starts_with("__ZN") {
// On OSX, symbols are prefixed with an extra _
inner = &s[4..s.len() - 1];
&s[4..]
} else {
return Err(());
}
};

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

let mut elements = 0;
let mut chars = inner.chars().peekable();
loop {
let mut i = 0usize;
while let Some(&c) = chars.peek() {
if !c.is_digit(10) {
break
}
chars.next();
let next = i.checked_mul(10)
.and_then(|i| i.checked_add(c as usize - '0' as usize));
i = match next {
Some(i) => i,
None => {
return Err(());
}
};
let mut chars = inner.chars();
let mut c = try!(chars.next().ok_or(()));
while c != 'E' {
// Decode an identifier element's length.
if !c.is_digit(10) {
return Err(());
}
let mut len = 0usize;
while let Some(d) = c.to_digit(10) {
len = try!(len.checked_mul(10)
.and_then(|len| len.checked_add(d as usize))
.ok_or(()));
c = try!(chars.next().ok_or(()));
}

if i == 0 {
if !chars.next().is_none() {
return Err(());
}
break;
} else if chars.by_ref().take(i).count() != i {
return Err(());
} else {
elements += 1;
// `c` already contains the first character of this identifier, skip it and
// all the other characters of this identifier, to reach the next element.
for _ in 0..len {
c = try!(chars.next().ok_or(()));
}

elements += 1;
}

Ok(Demangle {
Ok((Demangle {
inner: inner,
elements: elements,
})
}, chars.as_str()))
}

// Rust hashes are hex digits with an `h` prepended.
Expand Down
34 changes: 21 additions & 13 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,25 +81,33 @@ pub fn demangle(mut s: &str) -> Demangle {
}
}

// Output like LLVM IR adds extra period-delimited words. See if
// we are in that case and save the trailing words if so.
let mut suffix = "";
if let Some(i) = s.rfind("E.") {
let (head, tail) = s.split_at(i + 1); // After the E, before the period

if is_symbol_like(tail) {
s = head;
suffix = tail;
let mut style = match legacy::demangle(s) {
Ok((d, s)) => {
suffix = s;
Some(DemangleStyle::Legacy(d))
}
}

let style = match legacy::demangle(s) {
Ok(d) => Some(DemangleStyle::Legacy(d)),
Err(()) => match v0::demangle(s) {
Ok(d) => Some(DemangleStyle::V0(d)),
Ok((d, s)) => {
suffix = s;
Some(DemangleStyle::V0(d))
}
Err(v0::Invalid) => None,
},
};

// Output like LLVM IR adds extra period-delimited words. See if
// we are in that case and save the trailing words if so.
if !suffix.is_empty() {
if suffix.starts_with(".") && is_symbol_like(suffix) {
// Keep the suffix.
} else {
// Reset the suffix and invalidate the demangling.
suffix = "";
style = None;
}
}

Demangle {
style: style,
original: s,
Expand Down
35 changes: 26 additions & 9 deletions src/v0.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub struct Demangle<'a> {
/// This function will take a **mangled** symbol and return a value. When printed,
/// the de-mangled version will be written. If the symbol does not look like
/// a mangled symbol, the original value will be written instead.
pub fn demangle(s: &str) -> Result<Demangle, Invalid> {
pub fn demangle(s: &str) -> Result<(Demangle, &str), Invalid> {
// First validate the symbol. If it doesn't look like anything we're
// expecting, we just print it literally. Note that we must handle non-Rust
// symbols because we could have any function in the backtrace.
Expand Down Expand Up @@ -47,17 +47,18 @@ pub fn demangle(s: &str) -> Result<Demangle, Invalid> {
next: 0,
};
try!(parser.skip_path());
if parser.next < parser.sym.len() {
// Instantiating crate.
try!(parser.skip_path());
}
if parser.next != parser.sym.len() {
return Err(Invalid);

// Instantiating crate (paths always start with uppercase characters).
match parser.sym.as_bytes().get(parser.next) {
Some(&b'A'...b'Z') => {
try!(parser.skip_path());
}
_ => {}
}

Ok(Demangle {
Ok((Demangle {
inner: inner,
})
}, &parser.sym[parser.next..]))
}

impl<'s> Display for Demangle<'s> {
Expand Down Expand Up @@ -1064,4 +1065,20 @@ mod tests {
((((_, _), (_, _)), ((_, _), (_, _))), (((_, _), (_, _)), ((_, _), (_, _))))))"
);
}

#[test]
fn demangle_thinlto() {
t_nohash!("_RC3foo.llvm.9D1C9369", "foo");
t_nohash!("_RC3foo.llvm.9D1C9369@@16", "foo");
t_nohash!("_RNvC9backtrace3foo.llvm.A5310EB9", "backtrace::foo");
}

#[test]
fn demangle_extra_suffix() {
// From alexcrichton/rustc-demangle#27:
t_nohash!(
"_RNvNtNtNtNtCs92dm3009vxr_4rand4rngs7adapter9reseeding4fork23FORK_HANDLER_REGISTERED.0.0",
"rand::rngs::adapter::reseeding::fork::FORK_HANDLER_REGISTERED.0.0"
);
}
}