|
14 | 14 | use env;
|
15 | 15 | use io::prelude::*;
|
16 | 16 | use io;
|
| 17 | +use path::{self, Path}; |
| 18 | +use ptr; |
| 19 | +use rustc_demangle::demangle; |
17 | 20 | use str;
|
18 | 21 | use sync::atomic::{self, Ordering};
|
19 |
| -use path::{self, Path}; |
20 | 22 | use sys::mutex::Mutex;
|
21 |
| -use ptr; |
22 | 23 |
|
23 | 24 | pub use sys::backtrace::{
|
24 | 25 | unwind_backtrace,
|
@@ -191,7 +192,14 @@ fn output(w: &mut dyn Write, idx: usize, frame: Frame,
|
191 | 192 | PrintFormat::Short => write!(w, " {:2}: ", idx)?,
|
192 | 193 | }
|
193 | 194 | match s {
|
194 |
| - Some(string) => demangle(w, string, format)?, |
| 195 | + Some(string) => { |
| 196 | + let symbol = demangle(string); |
| 197 | + match format { |
| 198 | + PrintFormat::Full => write!(w, "{}", symbol)?, |
| 199 | + // strip the trailing hash if short mode |
| 200 | + PrintFormat::Short => write!(w, "{:#}", symbol)?, |
| 201 | + } |
| 202 | + } |
195 | 203 | None => w.write_all(b"<unknown>")?,
|
196 | 204 | }
|
197 | 205 | w.write_all(b"\n")
|
@@ -235,228 +243,3 @@ fn output_fileline(w: &mut dyn Write,
|
235 | 243 | w.write_all(b"\n")
|
236 | 244 | }
|
237 | 245 |
|
238 |
| - |
239 |
| -// All rust symbols are in theory lists of "::"-separated identifiers. Some |
240 |
| -// assemblers, however, can't handle these characters in symbol names. To get |
241 |
| -// around this, we use C++-style mangling. The mangling method is: |
242 |
| -// |
243 |
| -// 1. Prefix the symbol with "_ZN" |
244 |
| -// 2. For each element of the path, emit the length plus the element |
245 |
| -// 3. End the path with "E" |
246 |
| -// |
247 |
| -// For example, "_ZN4testE" => "test" and "_ZN3foo3barE" => "foo::bar". |
248 |
| -// |
249 |
| -// We're the ones printing our backtraces, so we can't rely on anything else to |
250 |
| -// demangle our symbols. It's *much* nicer to look at demangled symbols, so |
251 |
| -// this function is implemented to give us nice pretty output. |
252 |
| -// |
253 |
| -// Note that this demangler isn't quite as fancy as it could be. We have lots |
254 |
| -// of other information in our symbols like hashes, version, type information, |
255 |
| -// etc. Additionally, this doesn't handle glue symbols at all. |
256 |
| -pub fn demangle(writer: &mut dyn Write, mut s: &str, format: PrintFormat) -> io::Result<()> { |
257 |
| - // During ThinLTO LLVM may import and rename internal symbols, so strip out |
258 |
| - // those endings first as they're one of the last manglings applied to |
259 |
| - // symbol names. |
260 |
| - let llvm = ".llvm."; |
261 |
| - if let Some(i) = s.find(llvm) { |
262 |
| - let candidate = &s[i + llvm.len()..]; |
263 |
| - let all_hex = candidate.chars().all(|c| { |
264 |
| - match c { |
265 |
| - 'A' ..= 'F' | '0' ..= '9' => true, |
266 |
| - _ => false, |
267 |
| - } |
268 |
| - }); |
269 |
| - |
270 |
| - if all_hex { |
271 |
| - s = &s[..i]; |
272 |
| - } |
273 |
| - } |
274 |
| - |
275 |
| - // Validate the symbol. If it doesn't look like anything we're |
276 |
| - // expecting, we just print it literally. Note that we must handle non-rust |
277 |
| - // symbols because we could have any function in the backtrace. |
278 |
| - let mut valid = true; |
279 |
| - let mut inner = s; |
280 |
| - if s.len() > 4 && s.starts_with("_ZN") && s.ends_with("E") { |
281 |
| - inner = &s[3 .. s.len() - 1]; |
282 |
| - // On Windows, dbghelp strips leading underscores, so we accept "ZN...E" form too. |
283 |
| - } else if s.len() > 3 && s.starts_with("ZN") && s.ends_with("E") { |
284 |
| - inner = &s[2 .. s.len() - 1]; |
285 |
| - } else { |
286 |
| - valid = false; |
287 |
| - } |
288 |
| - |
289 |
| - if valid { |
290 |
| - let mut chars = inner.chars(); |
291 |
| - while valid { |
292 |
| - let mut i = 0; |
293 |
| - for c in chars.by_ref() { |
294 |
| - if c.is_numeric() { |
295 |
| - i = i * 10 + c as usize - '0' as usize; |
296 |
| - } else { |
297 |
| - break |
298 |
| - } |
299 |
| - } |
300 |
| - if i == 0 { |
301 |
| - valid = chars.next().is_none(); |
302 |
| - break |
303 |
| - } else if chars.by_ref().take(i - 1).count() != i - 1 { |
304 |
| - valid = false; |
305 |
| - } |
306 |
| - } |
307 |
| - } |
308 |
| - |
309 |
| - // Alright, let's do this. |
310 |
| - if !valid { |
311 |
| - writer.write_all(s.as_bytes())?; |
312 |
| - } else { |
313 |
| - // remove the `::hfc2edb670e5eda97` part at the end of the symbol. |
314 |
| - if format == PrintFormat::Short { |
315 |
| - // The symbol in still mangled. |
316 |
| - let mut split = inner.rsplitn(2, "17h"); |
317 |
| - match (split.next(), split.next()) { |
318 |
| - (Some(addr), rest) => { |
319 |
| - if addr.len() == 16 && |
320 |
| - addr.chars().all(|c| c.is_digit(16)) |
321 |
| - { |
322 |
| - inner = rest.unwrap_or(""); |
323 |
| - } |
324 |
| - } |
325 |
| - _ => (), |
326 |
| - } |
327 |
| - } |
328 |
| - |
329 |
| - let mut first = true; |
330 |
| - while !inner.is_empty() { |
331 |
| - if !first { |
332 |
| - writer.write_all(b"::")?; |
333 |
| - } else { |
334 |
| - first = false; |
335 |
| - } |
336 |
| - let mut rest = inner; |
337 |
| - while rest.chars().next().unwrap().is_numeric() { |
338 |
| - rest = &rest[1..]; |
339 |
| - } |
340 |
| - let i: usize = inner[.. (inner.len() - rest.len())].parse().unwrap(); |
341 |
| - inner = &rest[i..]; |
342 |
| - rest = &rest[..i]; |
343 |
| - if rest.starts_with("_$") { |
344 |
| - rest = &rest[1..]; |
345 |
| - } |
346 |
| - while !rest.is_empty() { |
347 |
| - if rest.starts_with(".") { |
348 |
| - if let Some('.') = rest[1..].chars().next() { |
349 |
| - writer.write_all(b"::")?; |
350 |
| - rest = &rest[2..]; |
351 |
| - } else { |
352 |
| - writer.write_all(b".")?; |
353 |
| - rest = &rest[1..]; |
354 |
| - } |
355 |
| - } else if rest.starts_with("$") { |
356 |
| - macro_rules! demangle { |
357 |
| - ($($pat:expr => $demangled:expr),*) => ({ |
358 |
| - $(if rest.starts_with($pat) { |
359 |
| - writer.write_all($demangled)?; |
360 |
| - rest = &rest[$pat.len()..]; |
361 |
| - } else)* |
362 |
| - { |
363 |
| - writer.write_all(rest.as_bytes())?; |
364 |
| - break; |
365 |
| - } |
366 |
| - |
367 |
| - }) |
368 |
| - } |
369 |
| - |
370 |
| - // see src/librustc/back/link.rs for these mappings |
371 |
| - demangle! ( |
372 |
| - "$SP$" => b"@", |
373 |
| - "$BP$" => b"*", |
374 |
| - "$RF$" => b"&", |
375 |
| - "$LT$" => b"<", |
376 |
| - "$GT$" => b">", |
377 |
| - "$LP$" => b"(", |
378 |
| - "$RP$" => b")", |
379 |
| - "$C$" => b",", |
380 |
| - |
381 |
| - // in theory we can demangle any Unicode code point, but |
382 |
| - // for simplicity we just catch the common ones. |
383 |
| - "$u7e$" => b"~", |
384 |
| - "$u20$" => b" ", |
385 |
| - "$u27$" => b"'", |
386 |
| - "$u5b$" => b"[", |
387 |
| - "$u5d$" => b"]", |
388 |
| - "$u7b$" => b"{", |
389 |
| - "$u7d$" => b"}", |
390 |
| - "$u3b$" => b";", |
391 |
| - "$u2b$" => b"+", |
392 |
| - "$u22$" => b"\"" |
393 |
| - ) |
394 |
| - } else { |
395 |
| - let idx = match rest.char_indices().find(|&(_, c)| c == '$' || c == '.') { |
396 |
| - None => rest.len(), |
397 |
| - Some((i, _)) => i, |
398 |
| - }; |
399 |
| - writer.write_all(rest[..idx].as_bytes())?; |
400 |
| - rest = &rest[idx..]; |
401 |
| - } |
402 |
| - } |
403 |
| - } |
404 |
| - } |
405 |
| - |
406 |
| - Ok(()) |
407 |
| -} |
408 |
| - |
409 |
| -#[cfg(test)] |
410 |
| -mod tests { |
411 |
| - use sys_common; |
412 |
| - macro_rules! t { ($a:expr, $b:expr) => ({ |
413 |
| - let mut m = Vec::new(); |
414 |
| - sys_common::backtrace::demangle(&mut m, |
415 |
| - $a, |
416 |
| - super::PrintFormat::Full).unwrap(); |
417 |
| - assert_eq!(String::from_utf8(m).unwrap(), $b); |
418 |
| - }) } |
419 |
| - |
420 |
| - #[test] |
421 |
| - fn demangle() { |
422 |
| - t!("test", "test"); |
423 |
| - t!("_ZN4testE", "test"); |
424 |
| - t!("_ZN4test", "_ZN4test"); |
425 |
| - t!("_ZN4test1a2bcE", "test::a::bc"); |
426 |
| - } |
427 |
| - |
428 |
| - #[test] |
429 |
| - fn demangle_dollars() { |
430 |
| - t!("_ZN4$RP$E", ")"); |
431 |
| - t!("_ZN8$RF$testE", "&test"); |
432 |
| - t!("_ZN8$BP$test4foobE", "*test::foob"); |
433 |
| - t!("_ZN9$u20$test4foobE", " test::foob"); |
434 |
| - t!("_ZN35Bar$LT$$u5b$u32$u3b$$u20$4$u5d$$GT$E", "Bar<[u32; 4]>"); |
435 |
| - } |
436 |
| - |
437 |
| - #[test] |
438 |
| - fn demangle_many_dollars() { |
439 |
| - t!("_ZN13test$u20$test4foobE", "test test::foob"); |
440 |
| - t!("_ZN12test$BP$test4foobE", "test*test::foob"); |
441 |
| - } |
442 |
| - |
443 |
| - #[test] |
444 |
| - fn demangle_windows() { |
445 |
| - t!("ZN4testE", "test"); |
446 |
| - t!("ZN13test$u20$test4foobE", "test test::foob"); |
447 |
| - t!("ZN12test$RF$test4foobE", "test&test::foob"); |
448 |
| - } |
449 |
| - |
450 |
| - #[test] |
451 |
| - fn demangle_elements_beginning_with_underscore() { |
452 |
| - t!("_ZN13_$LT$test$GT$E", "<test>"); |
453 |
| - t!("_ZN28_$u7b$$u7b$closure$u7d$$u7d$E", "{{closure}}"); |
454 |
| - t!("_ZN15__STATIC_FMTSTRE", "__STATIC_FMTSTR"); |
455 |
| - } |
456 |
| - |
457 |
| - #[test] |
458 |
| - fn demangle_trait_impls() { |
459 |
| - t!("_ZN71_$LT$Test$u20$$u2b$$u20$$u27$static$u20$as$u20$foo..Bar$LT$Test$GT$$GT$3barE", |
460 |
| - "<Test + 'static as foo::Bar<Test>>::bar"); |
461 |
| - } |
462 |
| -} |
0 commit comments