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