1 | // Copyright (c) 2010 Google Inc. |
2 | // All rights reserved. |
3 | // |
4 | // Redistribution and use in source and binary forms, with or without |
5 | // modification, are permitted provided that the following conditions are |
6 | // met: |
7 | // |
8 | // * Redistributions of source code must retain the above copyright |
9 | // notice, this list of conditions and the following disclaimer. |
10 | // * Redistributions in binary form must reproduce the above |
11 | // copyright notice, this list of conditions and the following disclaimer |
12 | // in the documentation and/or other materials provided with the |
13 | // distribution. |
14 | // * Neither the name of Google Inc. nor the names of its |
15 | // contributors may be used to endorse or promote products derived from |
16 | // this software without specific prior written permission. |
17 | // |
18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 | |
30 | // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> |
31 | |
32 | // language.cc: Subclasses and singletons for google_breakpad::Language. |
33 | // See language.h for details. |
34 | |
35 | #include "common/language.h" |
36 | |
37 | #include <stdlib.h> |
38 | #include <array> |
39 | |
40 | #if !defined(__ANDROID__) |
41 | #include <cxxabi.h> |
42 | #endif |
43 | |
44 | #if defined(HAVE_RUSTC_DEMANGLE) |
45 | #include <rustc_demangle.h> |
46 | #endif |
47 | |
48 | #include <limits> |
49 | |
50 | namespace { |
51 | |
52 | string MakeQualifiedNameWithSeparator(const string& parent_name, |
53 | const char* separator, |
54 | const string& name) { |
55 | if (parent_name.empty()) { |
56 | return name; |
57 | } |
58 | |
59 | return parent_name + separator + name; |
60 | } |
61 | |
62 | } // namespace |
63 | |
64 | namespace google_breakpad { |
65 | |
66 | // C++ language-specific operations. |
67 | class CPPLanguage: public Language { |
68 | public: |
69 | CPPLanguage() {} |
70 | |
71 | string MakeQualifiedName(const string& parent_name, |
72 | const string& name) const { |
73 | return MakeQualifiedNameWithSeparator(parent_name, "::" , name); |
74 | } |
75 | |
76 | virtual DemangleResult DemangleName(const string& mangled, |
77 | string* demangled) const { |
78 | #if defined(__ANDROID__) |
79 | // Android NDK doesn't provide abi::__cxa_demangle. |
80 | demangled->clear(); |
81 | return kDontDemangle; |
82 | #else |
83 | // Attempting to demangle non-C++ symbols with the C++ demangler would print |
84 | // warnings and fail, so return kDontDemangle for these. |
85 | if (!IsMangledName(mangled)) { |
86 | demangled->clear(); |
87 | return kDontDemangle; |
88 | } |
89 | |
90 | int status; |
91 | char* demangled_c = |
92 | abi::__cxa_demangle(mangled.c_str(), NULL, NULL, &status); |
93 | |
94 | DemangleResult result; |
95 | if (status == 0) { |
96 | result = kDemangleSuccess; |
97 | demangled->assign(demangled_c); |
98 | } else { |
99 | result = kDemangleFailure; |
100 | demangled->clear(); |
101 | } |
102 | |
103 | if (demangled_c) { |
104 | free(reinterpret_cast<void*>(demangled_c)); |
105 | } |
106 | |
107 | return result; |
108 | #endif |
109 | } |
110 | |
111 | private: |
112 | static bool IsMangledName(const string& name) { |
113 | // NOTE: For proper cross-compilation support, this should depend on target |
114 | // binary's platform, not current build platform. |
115 | #if defined(__APPLE__) |
116 | // Mac C++ symbols can have up to 4 underscores, followed by a "Z". |
117 | // Non-C++ symbols are not coded that way, but may have leading underscores. |
118 | size_t i = name.find_first_not_of('_'); |
119 | return i > 0 && i != string::npos && i <= 4 && name[i] == 'Z'; |
120 | #else |
121 | // Linux C++ symbols always start with "_Z". |
122 | return name.size() > 2 && name[0] == '_' && name[1] == 'Z'; |
123 | #endif |
124 | } |
125 | }; |
126 | |
127 | CPPLanguage CPPLanguageSingleton; |
128 | |
129 | // Java language-specific operations. |
130 | class JavaLanguage: public Language { |
131 | public: |
132 | JavaLanguage() {} |
133 | |
134 | string MakeQualifiedName(const string& parent_name, |
135 | const string& name) const { |
136 | return MakeQualifiedNameWithSeparator(parent_name, "." , name); |
137 | } |
138 | }; |
139 | |
140 | JavaLanguage JavaLanguageSingleton; |
141 | |
142 | // Swift language-specific operations. |
143 | class SwiftLanguage: public Language { |
144 | public: |
145 | SwiftLanguage() {} |
146 | |
147 | string MakeQualifiedName(const string& parent_name, |
148 | const string& name) const { |
149 | return MakeQualifiedNameWithSeparator(parent_name, "." , name); |
150 | } |
151 | |
152 | virtual DemangleResult DemangleName(const string& mangled, |
153 | string* demangled) const { |
154 | // There is no programmatic interface to a Swift demangler. Pass through the |
155 | // mangled form because it encodes more information than the qualified name |
156 | // that would have been built by MakeQualifiedName(). The output can be |
157 | // post-processed by xcrun swift-demangle to transform mangled Swift names |
158 | // into something more readable. |
159 | demangled->assign(mangled); |
160 | return kDemangleSuccess; |
161 | } |
162 | }; |
163 | |
164 | SwiftLanguage SwiftLanguageSingleton; |
165 | |
166 | // Rust language-specific operations. |
167 | class RustLanguage: public Language { |
168 | public: |
169 | RustLanguage() {} |
170 | |
171 | string MakeQualifiedName(const string& parent_name, |
172 | const string& name) const { |
173 | return MakeQualifiedNameWithSeparator(parent_name, "." , name); |
174 | } |
175 | |
176 | virtual DemangleResult DemangleName(const string& mangled, |
177 | string* demangled) const { |
178 | // Rust names use GCC C++ name mangling, but demangling them with |
179 | // abi_demangle doesn't produce stellar results due to them having |
180 | // another layer of encoding. |
181 | // If callers provide rustc-demangle, use that. |
182 | #if defined(HAVE_RUSTC_DEMANGLE) |
183 | std::array<char, 1 * 1024 * 1024> rustc_demangled; |
184 | if (rustc_demangle(mangled.c_str(), rustc_demangled.data(), |
185 | rustc_demangled.size()) == 0) { |
186 | return kDemangleFailure; |
187 | } |
188 | demangled->assign(rustc_demangled.data()); |
189 | #else |
190 | // Otherwise, pass through the mangled name so callers can demangle |
191 | // after the fact. |
192 | demangled->assign(mangled); |
193 | #endif |
194 | return kDemangleSuccess; |
195 | } |
196 | }; |
197 | |
198 | RustLanguage RustLanguageSingleton; |
199 | |
200 | // Assembler language-specific operations. |
201 | class AssemblerLanguage: public Language { |
202 | public: |
203 | AssemblerLanguage() {} |
204 | |
205 | bool HasFunctions() const { return false; } |
206 | string MakeQualifiedName(const string& parent_name, |
207 | const string& name) const { |
208 | return name; |
209 | } |
210 | }; |
211 | |
212 | AssemblerLanguage AssemblerLanguageSingleton; |
213 | |
214 | const Language * const Language::CPlusPlus = &CPPLanguageSingleton; |
215 | const Language * const Language::Java = &JavaLanguageSingleton; |
216 | const Language * const Language::Swift = &SwiftLanguageSingleton; |
217 | const Language * const Language::Rust = &RustLanguageSingleton; |
218 | const Language * const Language::Assembler = &AssemblerLanguageSingleton; |
219 | |
220 | } // namespace google_breakpad |
221 | |