1 //===-- Mangled.cpp -------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "lldb/Core/Mangled.h" 10 11 #include "lldb/Core/RichManglingContext.h" 12 #include "lldb/Utility/ConstString.h" 13 #include "lldb/Utility/Log.h" 14 #include "lldb/Utility/Logging.h" 15 #include "lldb/Utility/RegularExpression.h" 16 #include "lldb/Utility/Stream.h" 17 #include "lldb/lldb-enumerations.h" 18 19 #include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h" 20 21 #include "llvm/ADT/StringRef.h" 22 #include "llvm/Demangle/Demangle.h" 23 #include "llvm/Support/Compiler.h" 24 25 #include <mutex> 26 #include <string> 27 #include <utility> 28 29 #include <cstdlib> 30 #include <cstring> 31 using namespace lldb_private; 32 33 static inline bool cstring_is_mangled(llvm::StringRef s) { 34 return Mangled::GetManglingScheme(s) != Mangled::eManglingSchemeNone; 35 } 36 37 static ConstString GetDemangledNameWithoutArguments(ConstString mangled, 38 ConstString demangled) { 39 const char *mangled_name_cstr = mangled.GetCString(); 40 41 if (demangled && mangled_name_cstr && mangled_name_cstr[0]) { 42 if (mangled_name_cstr[0] == '_' && mangled_name_cstr[1] == 'Z' && 43 (mangled_name_cstr[2] != 'T' && // avoid virtual table, VTT structure, 44 // typeinfo structure, and typeinfo 45 // mangled_name 46 mangled_name_cstr[2] != 'G' && // avoid guard variables 47 mangled_name_cstr[2] != 'Z')) // named local entities (if we eventually 48 // handle eSymbolTypeData, we will want 49 // this back) 50 { 51 CPlusPlusLanguage::MethodName cxx_method(demangled); 52 if (!cxx_method.GetBasename().empty()) { 53 std::string shortname; 54 if (!cxx_method.GetContext().empty()) 55 shortname = cxx_method.GetContext().str() + "::"; 56 shortname += cxx_method.GetBasename().str(); 57 return ConstString(shortname); 58 } 59 } 60 } 61 if (demangled) 62 return demangled; 63 return mangled; 64 } 65 66 #pragma mark Mangled 67 68 Mangled::ManglingScheme Mangled::GetManglingScheme(llvm::StringRef const name) { 69 if (name.empty()) 70 return Mangled::eManglingSchemeNone; 71 72 if (name.startswith("?")) 73 return Mangled::eManglingSchemeMSVC; 74 75 if (name.startswith("_R")) 76 return Mangled::eManglingSchemeRustV0; 77 78 if (name.startswith("_Z")) 79 return Mangled::eManglingSchemeItanium; 80 81 // ___Z is a clang extension of block invocations 82 if (name.startswith("___Z")) 83 return Mangled::eManglingSchemeItanium; 84 85 return Mangled::eManglingSchemeNone; 86 } 87 88 Mangled::Mangled(ConstString s) : m_mangled(), m_demangled() { 89 if (s) 90 SetValue(s); 91 } 92 93 Mangled::Mangled(llvm::StringRef name) { 94 if (!name.empty()) 95 SetValue(ConstString(name)); 96 } 97 98 // Convert to pointer operator. This allows code to check any Mangled objects 99 // to see if they contain anything valid using code such as: 100 // 101 // Mangled mangled(...); 102 // if (mangled) 103 // { ... 104 Mangled::operator void *() const { 105 return (m_mangled) ? const_cast<Mangled *>(this) : nullptr; 106 } 107 108 // Logical NOT operator. This allows code to check any Mangled objects to see 109 // if they are invalid using code such as: 110 // 111 // Mangled mangled(...); 112 // if (!file_spec) 113 // { ... 114 bool Mangled::operator!() const { return !m_mangled; } 115 116 // Clear the mangled and demangled values. 117 void Mangled::Clear() { 118 m_mangled.Clear(); 119 m_demangled.Clear(); 120 } 121 122 // Compare the string values. 123 int Mangled::Compare(const Mangled &a, const Mangled &b) { 124 return ConstString::Compare(a.GetName(ePreferMangled), 125 b.GetName(ePreferMangled)); 126 } 127 128 // Set the string value in this objects. If "mangled" is true, then the mangled 129 // named is set with the new value in "s", else the demangled name is set. 130 void Mangled::SetValue(ConstString s, bool mangled) { 131 if (s) { 132 if (mangled) { 133 m_demangled.Clear(); 134 m_mangled = s; 135 } else { 136 m_demangled = s; 137 m_mangled.Clear(); 138 } 139 } else { 140 m_demangled.Clear(); 141 m_mangled.Clear(); 142 } 143 } 144 145 void Mangled::SetValue(ConstString name) { 146 if (name) { 147 if (cstring_is_mangled(name.GetStringRef())) { 148 m_demangled.Clear(); 149 m_mangled = name; 150 } else { 151 m_demangled = name; 152 m_mangled.Clear(); 153 } 154 } else { 155 m_demangled.Clear(); 156 m_mangled.Clear(); 157 } 158 } 159 160 // Local helpers for different demangling implementations. 161 static char *GetMSVCDemangledStr(const char *M) { 162 char *demangled_cstr = llvm::microsoftDemangle( 163 M, nullptr, nullptr, nullptr, nullptr, 164 llvm::MSDemangleFlags(llvm::MSDF_NoAccessSpecifier | 165 llvm::MSDF_NoCallingConvention | 166 llvm::MSDF_NoMemberType)); 167 168 if (Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE)) { 169 if (demangled_cstr && demangled_cstr[0]) 170 LLDB_LOGF(log, "demangled msvc: %s -> \"%s\"", M, demangled_cstr); 171 else 172 LLDB_LOGF(log, "demangled msvc: %s -> error", M); 173 } 174 175 return demangled_cstr; 176 } 177 178 static char *GetItaniumDemangledStr(const char *M) { 179 char *demangled_cstr = nullptr; 180 181 llvm::ItaniumPartialDemangler ipd; 182 bool err = ipd.partialDemangle(M); 183 if (!err) { 184 // Default buffer and size (will realloc in case it's too small). 185 size_t demangled_size = 80; 186 demangled_cstr = static_cast<char *>(std::malloc(demangled_size)); 187 demangled_cstr = ipd.finishDemangle(demangled_cstr, &demangled_size); 188 189 assert(demangled_cstr && 190 "finishDemangle must always succeed if partialDemangle did"); 191 assert(demangled_cstr[demangled_size - 1] == '\0' && 192 "Expected demangled_size to return length including trailing null"); 193 } 194 195 if (Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE)) { 196 if (demangled_cstr) 197 LLDB_LOGF(log, "demangled itanium: %s -> \"%s\"", M, demangled_cstr); 198 else 199 LLDB_LOGF(log, "demangled itanium: %s -> error: failed to demangle", M); 200 } 201 202 return demangled_cstr; 203 } 204 205 static char *GetRustV0DemangledStr(const char *M) { 206 char *demangled_cstr = llvm::rustDemangle(M, nullptr, nullptr, nullptr); 207 208 if (Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE)) { 209 if (demangled_cstr && demangled_cstr[0]) 210 LLDB_LOG(log, "demangled rustv0: {0} -> \"{1}\"", M, demangled_cstr); 211 else 212 LLDB_LOG(log, "demangled rustv0: {0} -> error: failed to demangle", M); 213 } 214 215 return demangled_cstr; 216 } 217 218 // Explicit demangling for scheduled requests during batch processing. This 219 // makes use of ItaniumPartialDemangler's rich demangle info 220 bool Mangled::DemangleWithRichManglingInfo( 221 RichManglingContext &context, SkipMangledNameFn *skip_mangled_name) { 222 // Others are not meant to arrive here. ObjC names or C's main() for example 223 // have their names stored in m_demangled, while m_mangled is empty. 224 assert(m_mangled); 225 226 // Check whether or not we are interested in this name at all. 227 ManglingScheme scheme = GetManglingScheme(m_mangled.GetStringRef()); 228 if (skip_mangled_name && skip_mangled_name(m_mangled.GetStringRef(), scheme)) 229 return false; 230 231 switch (scheme) { 232 case eManglingSchemeNone: 233 // The current mangled_name_filter would allow llvm_unreachable here. 234 return false; 235 236 case eManglingSchemeItanium: 237 // We want the rich mangling info here, so we don't care whether or not 238 // there is a demangled string in the pool already. 239 if (context.FromItaniumName(m_mangled)) { 240 // If we got an info, we have a name. Copy to string pool and connect the 241 // counterparts to accelerate later access in GetDemangledName(). 242 context.ParseFullName(); 243 m_demangled.SetStringWithMangledCounterpart(context.GetBufferRef(), 244 m_mangled); 245 return true; 246 } else { 247 m_demangled.SetCString(""); 248 return false; 249 } 250 251 case eManglingSchemeMSVC: { 252 // We have no rich mangling for MSVC-mangled names yet, so first try to 253 // demangle it if necessary. 254 if (!m_demangled && !m_mangled.GetMangledCounterpart(m_demangled)) { 255 if (char *d = GetMSVCDemangledStr(m_mangled.GetCString())) { 256 // If we got an info, we have a name. Copy to string pool and connect 257 // the counterparts to accelerate later access in GetDemangledName(). 258 m_demangled.SetStringWithMangledCounterpart(llvm::StringRef(d), 259 m_mangled); 260 ::free(d); 261 } else { 262 m_demangled.SetCString(""); 263 } 264 } 265 266 if (m_demangled.IsEmpty()) { 267 // Cannot demangle it, so don't try parsing. 268 return false; 269 } else { 270 // Demangled successfully, we can try and parse it with 271 // CPlusPlusLanguage::MethodName. 272 return context.FromCxxMethodName(m_demangled); 273 } 274 } 275 276 case eManglingSchemeRustV0: 277 // Rich demangling scheme is not supported for Rust 278 return false; 279 } 280 llvm_unreachable("Fully covered switch above!"); 281 } 282 283 // Generate the demangled name on demand using this accessor. Code in this 284 // class will need to use this accessor if it wishes to decode the demangled 285 // name. The result is cached and will be kept until a new string value is 286 // supplied to this object, or until the end of the object's lifetime. 287 ConstString Mangled::GetDemangledName() const { 288 // Check to make sure we have a valid mangled name and that we haven't 289 // already decoded our mangled name. 290 if (m_mangled && m_demangled.IsNull()) { 291 // Don't bother running anything that isn't mangled 292 const char *mangled_name = m_mangled.GetCString(); 293 ManglingScheme mangling_scheme = GetManglingScheme(m_mangled.GetStringRef()); 294 if (mangling_scheme != eManglingSchemeNone && 295 !m_mangled.GetMangledCounterpart(m_demangled)) { 296 // We didn't already mangle this name, demangle it and if all goes well 297 // add it to our map. 298 char *demangled_name = nullptr; 299 switch (mangling_scheme) { 300 case eManglingSchemeMSVC: 301 demangled_name = GetMSVCDemangledStr(mangled_name); 302 break; 303 case eManglingSchemeItanium: { 304 demangled_name = GetItaniumDemangledStr(mangled_name); 305 break; 306 } 307 case eManglingSchemeRustV0: 308 demangled_name = GetRustV0DemangledStr(mangled_name); 309 break; 310 case eManglingSchemeNone: 311 llvm_unreachable("eManglingSchemeNone was handled already"); 312 } 313 if (demangled_name) { 314 m_demangled.SetStringWithMangledCounterpart( 315 llvm::StringRef(demangled_name), m_mangled); 316 free(demangled_name); 317 } 318 } 319 if (m_demangled.IsNull()) { 320 // Set the demangled string to the empty string to indicate we tried to 321 // parse it once and failed. 322 m_demangled.SetCString(""); 323 } 324 } 325 326 return m_demangled; 327 } 328 329 ConstString 330 Mangled::GetDisplayDemangledName() const { 331 return GetDemangledName(); 332 } 333 334 bool Mangled::NameMatches(const RegularExpression ®ex) const { 335 if (m_mangled && regex.Execute(m_mangled.GetStringRef())) 336 return true; 337 338 ConstString demangled = GetDemangledName(); 339 return demangled && regex.Execute(demangled.GetStringRef()); 340 } 341 342 // Get the demangled name if there is one, else return the mangled name. 343 ConstString Mangled::GetName(Mangled::NamePreference preference) const { 344 if (preference == ePreferMangled && m_mangled) 345 return m_mangled; 346 347 ConstString demangled = GetDemangledName(); 348 349 if (preference == ePreferDemangledWithoutArguments) { 350 return GetDemangledNameWithoutArguments(m_mangled, demangled); 351 } 352 if (preference == ePreferDemangled) { 353 // Call the accessor to make sure we get a demangled name in case it hasn't 354 // been demangled yet... 355 if (demangled) 356 return demangled; 357 return m_mangled; 358 } 359 return demangled; 360 } 361 362 // Dump a Mangled object to stream "s". We don't force our demangled name to be 363 // computed currently (we don't use the accessor). 364 void Mangled::Dump(Stream *s) const { 365 if (m_mangled) { 366 *s << ", mangled = " << m_mangled; 367 } 368 if (m_demangled) { 369 const char *demangled = m_demangled.AsCString(); 370 s->Printf(", demangled = %s", demangled[0] ? demangled : "<error>"); 371 } 372 } 373 374 // Dumps a debug version of this string with extra object and state information 375 // to stream "s". 376 void Mangled::DumpDebug(Stream *s) const { 377 s->Printf("%*p: Mangled mangled = ", static_cast<int>(sizeof(void *) * 2), 378 static_cast<const void *>(this)); 379 m_mangled.DumpDebug(s); 380 s->Printf(", demangled = "); 381 m_demangled.DumpDebug(s); 382 } 383 384 // Return the size in byte that this object takes in memory. The size includes 385 // the size of the objects it owns, and not the strings that it references 386 // because they are shared strings. 387 size_t Mangled::MemorySize() const { 388 return m_mangled.MemorySize() + m_demangled.MemorySize(); 389 } 390 391 // We "guess" the language because we can't determine a symbol's language from 392 // it's name. For example, a Pascal symbol can be mangled using the C++ 393 // Itanium scheme, and defined in a compilation unit within the same module as 394 // other C++ units. In addition, different targets could have different ways 395 // of mangling names from a given language, likewise the compilation units 396 // within those targets. 397 lldb::LanguageType Mangled::GuessLanguage() const { 398 lldb::LanguageType result = lldb::eLanguageTypeUnknown; 399 // Ask each language plugin to check if the mangled name belongs to it. 400 Language::ForEach([this, &result](Language *l) { 401 if (l->SymbolNameFitsToLanguage(*this)) { 402 result = l->GetLanguageType(); 403 return false; 404 } 405 return true; 406 }); 407 return result; 408 } 409 410 // Dump OBJ to the supplied stream S. 411 Stream &operator<<(Stream &s, const Mangled &obj) { 412 if (obj.GetMangledName()) 413 s << "mangled = '" << obj.GetMangledName() << "'"; 414 415 ConstString demangled = obj.GetDemangledName(); 416 if (demangled) 417 s << ", demangled = '" << demangled << '\''; 418 else 419 s << ", demangled = <error>"; 420 return s; 421 } 422