Skip to content

Commit

Permalink
Merge pull request #30 from eddyb/trailing-dots
Browse files Browse the repository at this point in the history
v0: also support preserving extra suffixes found after mangled symbol.
  • Loading branch information
alexcrichton authored Aug 13, 2019
2 parents 016ca6e + c1eeee6 commit 51cb6ea
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 58 deletions.
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"
);
}
}

0 comments on commit 51cb6ea

Please sign in to comment.