Support demangling symbols with dot-delimited words at the end This accounts for values like LLVM IR branch labels. Closes #15
diff --git a/src/lib.rs b/src/lib.rs index b1156f4..2d0d7c8 100644 --- a/src/lib.rs +++ b/src/lib.rs
@@ -36,6 +36,7 @@ pub struct Demangle<'a> { original: &'a str, inner: &'a str, + suffix: &'a str, valid: bool, /// The number of ::-separated elements in the original name. elements: usize, @@ -98,6 +99,18 @@ } } + // 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; + } + } + // 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. @@ -155,6 +168,7 @@ Demangle { inner: inner, + suffix: suffix, valid: valid, elements: elements, original: s, @@ -202,6 +216,35 @@ s.starts_with('h') && s[1..].chars().all(|c| c.is_digit(16)) } +fn is_symbol_like(s: &str) -> bool { + s.chars().all(|c| { + // Once `char::is_ascii_punctuation` and `char::is_ascii_alphanumeric` + // have been stable for long enough, use those instead for clarity + is_ascii_alphanumeric(c) || is_ascii_punctuation(c) + }) +} + +// Copied from the documentation of `char::is_ascii_alphanumeric` +fn is_ascii_alphanumeric(c: char) -> bool { + match c { + '\u{0041}' ... '\u{005A}' | + '\u{0061}' ... '\u{007A}' | + '\u{0030}' ... '\u{0039}' => true, + _ => false, + } +} + +// Copied from the documentation of `char::is_ascii_punctuation` +fn is_ascii_punctuation(c: char) -> bool { + match c { + '\u{0021}' ... '\u{002F}' | + '\u{003A}' ... '\u{0040}' | + '\u{005B}' ... '\u{0060}' | + '\u{007B}' ... '\u{007E}' => true, + _ => false, + } +} + impl<'a> fmt::Display for Demangle<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // Alright, let's do this. @@ -288,6 +331,8 @@ } } + try!(f.write_str(self.suffix)); + Ok(()) } } @@ -399,6 +444,17 @@ } #[test] + fn demangle_llvm_ir_branch_labels() { + t!("_ZN4core5slice77_$LT$impl$u20$core..ops..index..IndexMut$LT$I$GT$$u20$for$u20$$u5b$T$u5d$$GT$9index_mut17haf9727c2edfbc47bE.exit.i.i", "core::slice::<impl core::ops::index::IndexMut<I> for [T]>::index_mut::haf9727c2edfbc47b.exit.i.i"); + t_nohash!("_ZN4core5slice77_$LT$impl$u20$core..ops..index..IndexMut$LT$I$GT$$u20$for$u20$$u5b$T$u5d$$GT$9index_mut17haf9727c2edfbc47bE.exit.i.i", "core::slice::<impl core::ops::index::IndexMut<I> for [T]>::index_mut.exit.i.i"); + } + + #[test] + fn demangle_ignores_suffix_that_doesnt_look_like_a_symbol() { + t!("_ZN3fooE.llvm moocow", "_ZN3fooE.llvm moocow"); + } + + #[test] fn dont_panic() { super::demangle("_ZN2222222222222222222222EE").to_string(); super::demangle("_ZN5*70527e27.ll34csaғE").to_string();