Skip to content

Commit b9c54b3

Browse files
committed
WIP
1 parent e6df549 commit b9c54b3

File tree

3 files changed

+110
-84
lines changed

3 files changed

+110
-84
lines changed

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
6868
#![doc(html_root_url = "http://alexcrichton.com/backtrace-rs")]
6969
#![deny(missing_docs)]
70-
#![deny(warnings)]
70+
// #![deny(warnings)]
7171

7272
extern crate libc;
7373
#[cfg(all(windows, feature = "kernel32-sys"))] extern crate kernel32;

src/symbolize/mod.rs

Lines changed: 94 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -111,44 +111,36 @@ impl fmt::Debug for Symbol {
111111
}
112112
}
113113

114-
// Maybe a parsed C++ symbol, if parsing the mangled symbol as Rust failed.
115-
#[cfg(feature = "cpp_demangle")]
116-
struct OptionCppSymbol<'a>(Option<::cpp_demangle::BorrowedSymbol<'a>>);
117114

118-
#[cfg(feature = "cpp_demangle")]
119-
impl<'a> OptionCppSymbol<'a> {
120-
fn parse(input: &'a [u8]) -> OptionCppSymbol<'a> {
121-
OptionCppSymbol(::cpp_demangle::BorrowedSymbol::with_tail(input)
122-
.ok()
123-
.map(|(sym, _tail)| sym))
124-
}
125-
126-
fn none() -> OptionCppSymbol<'a> {
127-
OptionCppSymbol(None)
128-
}
129-
130-
fn as_str(&self) -> Option<Cow<'a, str>> {
131-
self.0.as_ref().map(|cpp| Cow::from(format!("{}", cpp)))
132-
}
133-
}
115+
cfg_if! {
116+
if #[cfg(feature = "cpp_demangle")] {
117+
// Maybe a parsed C++ symbol, if parsing the mangled symbol as Rust
118+
// failed.
119+
struct OptionCppSymbol<'a>(Option<::cpp_demangle::BorrowedSymbol<'a>>);
134120

135-
// Make sure to keep this zero-sized, so that the `cpp_demangle` feature has no
136-
// cost when disabled.
137-
#[cfg(not(feature = "cpp_demangle"))]
138-
struct OptionCppSymbol<'a>(PhantomData<&'a ()>);
121+
impl<'a> OptionCppSymbol<'a> {
122+
fn parse(input: &'a [u8]) -> OptionCppSymbol<'a> {
123+
OptionCppSymbol(::cpp_demangle::BorrowedSymbol::new(input).ok())
124+
}
139125

140-
#[cfg(not(feature = "cpp_demangle"))]
141-
impl<'a> OptionCppSymbol<'a> {
142-
fn parse(_: &'a [u8]) -> OptionCppSymbol<'a> {
143-
OptionCppSymbol(PhantomData)
144-
}
126+
fn as_str(&self) -> Option<Cow<'a, str>> {
127+
self.0.as_ref().map(|cpp| Cow::from(cpp.to_string()))
128+
}
129+
}
130+
} else {
131+
// Make sure to keep this zero-sized, so that the `cpp_demangle` feature
132+
// has no cost when disabled.
133+
struct OptionCppSymbol<'a>(PhantomData<&'a ()>);
145134

146-
fn none() -> OptionCppSymbol<'a> {
147-
OptionCppSymbol(PhantomData)
148-
}
135+
impl<'a> OptionCppSymbol<'a> {
136+
fn parse(_: &'a [u8]) -> OptionCppSymbol<'a> {
137+
OptionCppSymbol(PhantomData)
138+
}
149139

150-
fn as_str(&self) -> Option<Cow<'a, str>> {
151-
None
140+
fn as_str(&self) -> Option<Cow<'a, str>> {
141+
None
142+
}
143+
}
152144
}
153145
}
154146

@@ -165,12 +157,18 @@ impl<'a> SymbolName<'a> {
165157
pub fn new(bytes: &'a [u8]) -> SymbolName<'a> {
166158
let demangled = str::from_utf8(bytes).ok().map(demangle);
167159

168-
// Only try and parse a C++ symbol if we didn't parse a Rust symbol.
169-
let cpp = if demangled.is_none() {
170-
OptionCppSymbol::parse(bytes)
171-
} else {
172-
OptionCppSymbol::none()
173-
};
160+
// Unfortunately, rustc_demangle::Demangle doesn't expose its internal
161+
// `valid` flag, so we don't know if it successfully "demangled" as a
162+
// no-op on the str or not. Therefore, we have no choice but to always
163+
// attempt to parse the bytes as a C++ symbol, and can't do it only as a
164+
// fall back when demangling as Rust fails.
165+
let cpp = OptionCppSymbol::parse(bytes);
166+
167+
println!("FITZGEN: bytes = {}", String::from_utf8_lossy(bytes));
168+
println!("FITZGEN: cpp = {:#?}", cpp.0);
169+
if let Some(ref cpp) = cpp.0 {
170+
println!("FITZGEN: demangled = {}", cpp);
171+
}
174172

175173
SymbolName {
176174
bytes: bytes,
@@ -180,12 +178,22 @@ impl<'a> SymbolName<'a> {
180178
}
181179

182180
/// Returns the raw symbol name as a `str` if the symbols is valid utf-8.
183-
pub fn as_str(&self) -> Option<Cow<'a, str>> {
184-
self.demangled
185-
.as_ref()
186-
.map(|s| Cow::from(s.as_str()))
181+
///
182+
/// Will not demangle C++ symbols.
183+
pub fn as_str(&self) -> Option<&'a str> {
184+
self.demangled.as_ref().map(|s| s.as_str())
185+
}
186+
187+
/// Returns the symbol name as `Cow<'a, str>` if the symbol is valid utf-8.
188+
///
189+
/// Will demangle C++ symbols.
190+
pub fn as_cow(&self) -> Option<Cow<'a, str>> {
191+
// TODO: Next major version bump, remove the old `as_str` above, and
192+
// rename this to `as_str`.
193+
self.cpp_demangled
194+
.as_str()
187195
.or_else(|| {
188-
self.cpp_demangled.as_str()
196+
self.demangled.as_ref().map(|s| Cow::from(s.as_str()))
189197
})
190198
}
191199

@@ -195,46 +203,54 @@ impl<'a> SymbolName<'a> {
195203
}
196204
}
197205

198-
impl<'a> fmt::Display for SymbolName<'a> {
199-
#[cfg(feature = "cpp_demangle")]
200-
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
201-
if let Some(ref s) = self.demangled {
202-
s.fmt(f)
203-
} else if let Some(ref cpp) = self.cpp_demangled.0 {
204-
cpp.fmt(f)
205-
} else {
206-
String::from_utf8_lossy(self.bytes).fmt(f)
206+
cfg_if! {
207+
if #[cfg(feature = "cpp_demangle")] {
208+
impl<'a> fmt::Display for SymbolName<'a> {
209+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
210+
if let Some(ref cpp) = self.cpp_demangled.0 {
211+
cpp.fmt(f)
212+
} else if let Some(ref s) = self.demangled {
213+
s.fmt(f)
214+
} else {
215+
String::from_utf8_lossy(self.bytes).fmt(f)
216+
}
217+
}
207218
}
208-
}
209-
210-
#[cfg(not(feature = "cpp_demangle"))]
211-
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
212-
if let Some(ref s) = self.demangled {
213-
s.fmt(f)
214-
} else {
215-
String::from_utf8_lossy(self.bytes).fmt(f)
219+
} else {
220+
impl<'a> fmt::Display for SymbolName<'a> {
221+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
222+
if let Some(ref s) = self.demangled {
223+
s.fmt(f)
224+
} else {
225+
String::from_utf8_lossy(self.bytes).fmt(f)
226+
}
227+
}
216228
}
217229
}
218230
}
219231

220-
impl<'a> fmt::Debug for SymbolName<'a> {
221-
#[cfg(feature = "cpp_demangle")]
222-
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
223-
if let Some(ref s) = self.demangled {
224-
s.fmt(f)
225-
} else if let Some(ref cpp) = self.cpp_demangled.0 {
226-
cpp.fmt(f)
227-
} else {
228-
String::from_utf8_lossy(self.bytes).fmt(f)
232+
cfg_if! {
233+
if #[cfg(feature = "cpp_demangle")] {
234+
impl<'a> fmt::Debug for SymbolName<'a> {
235+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
236+
if let Some(ref cpp) = self.cpp_demangled.0 {
237+
fmt::Display::fmt(cpp, f)
238+
} else if let Some(ref s) = self.demangled {
239+
s.fmt(f)
240+
} else {
241+
String::from_utf8_lossy(self.bytes).fmt(f)
242+
}
243+
}
229244
}
230-
}
231-
232-
#[cfg(not(feature = "cpp_demangle"))]
233-
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
234-
if let Some(ref s) = self.demangled {
235-
s.fmt(f)
236-
} else {
237-
String::from_utf8_lossy(self.bytes).fmt(f)
245+
} else {
246+
impl<'a> fmt::Debug for SymbolName<'a> {
247+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
248+
if let Some(ref s) = self.demangled {
249+
s.fmt(f)
250+
} else {
251+
String::from_utf8_lossy(self.bytes).fmt(f)
252+
}
253+
}
238254
}
239255
}
240256
}

tests/smoke.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -195,21 +195,31 @@ fn smoke_test_cpp() {
195195
let mut name = None;
196196
backtrace::resolve(*ip, |sym| {
197197
assert!(name.is_none(), "Shouldn't have any inlined frames");
198-
name = Some(sym.name().unwrap().to_string());
198+
let sym_name = sym.name().expect("Should have a symbol name");
199+
let demangled = sym_name.as_cow()
200+
.expect("Should have a demangled form")
201+
.to_string();
202+
name = Some(demangled);
199203
});
200-
name.unwrap()
204+
name.expect("Should have resolved the ip to a symbol")
201205
})
202206
.collect();
203207

204-
println!("FITZGEN: names = {:?}", names);
208+
println!("actual names = {:#?}", names);
205209

206-
assert_eq!(names, [
210+
let expected = [
207211
"backtrace::backtrace::trace<closure>",
208212
"smoke::smoke_test_cpp::assert_cpp_frames",
209213
"void space::templated_trampoline<void (*)()>(void (*)())",
210214
"cpp_trampoline",
211215
"smoke::smoke_test_cpp"
212-
]);
216+
];
217+
println!("expected names = {:#?}", expected);
218+
219+
assert_eq!(names.len(), expected.len());
220+
for (actual, expected) in names.iter().zip(expected.iter()) {
221+
assert_eq!(actual, expected);
222+
}
213223

214224
RAN_ASSERTS.store(true, Ordering::SeqCst);
215225
}

0 commit comments

Comments
 (0)