]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2014 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | use prelude::v1::*; | |
12 | ||
13 | use io::IoResult; | |
14 | ||
15 | #[cfg(any(all(stage0, target_word_size = "64"), all(not(stage0), target_pointer_width = "64")))] | |
16 | pub const HEX_WIDTH: uint = 18; | |
17 | ||
18 | #[cfg(any(all(stage0, target_word_size = "32"), all(not(stage0), target_pointer_width = "32")))] | |
19 | pub const HEX_WIDTH: uint = 10; | |
20 | ||
21 | // All rust symbols are in theory lists of "::"-separated identifiers. Some | |
22 | // assemblers, however, can't handle these characters in symbol names. To get | |
23 | // around this, we use C++-style mangling. The mangling method is: | |
24 | // | |
25 | // 1. Prefix the symbol with "_ZN" | |
26 | // 2. For each element of the path, emit the length plus the element | |
27 | // 3. End the path with "E" | |
28 | // | |
29 | // For example, "_ZN4testE" => "test" and "_ZN3foo3bar" => "foo::bar". | |
30 | // | |
31 | // We're the ones printing our backtraces, so we can't rely on anything else to | |
32 | // demangle our symbols. It's *much* nicer to look at demangled symbols, so | |
33 | // this function is implemented to give us nice pretty output. | |
34 | // | |
35 | // Note that this demangler isn't quite as fancy as it could be. We have lots | |
36 | // of other information in our symbols like hashes, version, type information, | |
37 | // etc. Additionally, this doesn't handle glue symbols at all. | |
38 | pub fn demangle(writer: &mut Writer, s: &str) -> IoResult<()> { | |
39 | // First validate the symbol. If it doesn't look like anything we're | |
40 | // expecting, we just print it literally. Note that we must handle non-rust | |
41 | // symbols because we could have any function in the backtrace. | |
42 | let mut valid = true; | |
43 | let mut inner = s; | |
44 | if s.len() > 4 && s.starts_with("_ZN") && s.ends_with("E") { | |
45 | inner = s.slice(3, s.len() - 1); | |
46 | // On Windows, dbghelp strips leading underscores, so we accept "ZN...E" form too. | |
47 | } else if s.len() > 3 && s.starts_with("ZN") && s.ends_with("E") { | |
48 | inner = s.slice(2, s.len() - 1); | |
49 | } else { | |
50 | valid = false; | |
51 | } | |
52 | ||
53 | if valid { | |
54 | let mut chars = inner.chars(); | |
55 | while valid { | |
56 | let mut i = 0; | |
57 | for c in chars { | |
58 | if c.is_numeric() { | |
59 | i = i * 10 + c as uint - '0' as uint; | |
60 | } else { | |
61 | break | |
62 | } | |
63 | } | |
64 | if i == 0 { | |
65 | valid = chars.next().is_none(); | |
66 | break | |
67 | } else if chars.by_ref().take(i - 1).count() != i - 1 { | |
68 | valid = false; | |
69 | } | |
70 | } | |
71 | } | |
72 | ||
73 | // Alright, let's do this. | |
74 | if !valid { | |
75 | try!(writer.write_str(s)); | |
76 | } else { | |
77 | let mut first = true; | |
78 | while inner.len() > 0 { | |
79 | if !first { | |
80 | try!(writer.write_str("::")); | |
81 | } else { | |
82 | first = false; | |
83 | } | |
84 | let mut rest = inner; | |
85 | while rest.char_at(0).is_numeric() { | |
86 | rest = rest.slice_from(1); | |
87 | } | |
88 | let i: uint = inner.slice_to(inner.len() - rest.len()).parse().unwrap(); | |
89 | inner = rest.slice_from(i); | |
90 | rest = rest.slice_to(i); | |
91 | while rest.len() > 0 { | |
92 | if rest.starts_with("$") { | |
93 | macro_rules! demangle { | |
94 | ($($pat:expr, => $demangled:expr),*) => ({ | |
95 | $(if rest.starts_with($pat) { | |
96 | try!(writer.write_str($demangled)); | |
97 | rest = rest.slice_from($pat.len()); | |
98 | } else)* | |
99 | { | |
100 | try!(writer.write_str(rest)); | |
101 | break; | |
102 | } | |
103 | ||
104 | }) | |
105 | } | |
106 | ||
107 | // see src/librustc/back/link.rs for these mappings | |
108 | demangle! ( | |
109 | "$SP$", => "@", | |
110 | "$UP$", => "Box", | |
111 | "$RP$", => "*", | |
112 | "$BP$", => "&", | |
113 | "$LT$", => "<", | |
114 | "$GT$", => ">", | |
115 | "$LP$", => "(", | |
116 | "$RP$", => ")", | |
117 | "$C$", => ",", | |
118 | ||
119 | // in theory we can demangle any Unicode code point, but | |
120 | // for simplicity we just catch the common ones. | |
121 | "$u{20}", => " ", | |
122 | "$u{27}", => "'", | |
123 | "$u{5b}", => "[", | |
124 | "$u{5d}", => "]" | |
125 | ) | |
126 | } else { | |
127 | let idx = match rest.find('$') { | |
128 | None => rest.len(), | |
129 | Some(i) => i, | |
130 | }; | |
131 | try!(writer.write_str(rest.slice_to(idx))); | |
132 | rest = rest.slice_from(idx); | |
133 | } | |
134 | } | |
135 | } | |
136 | } | |
137 | ||
138 | Ok(()) | |
139 | } |