1 //===-- Mangled.cpp ---------------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include <cxxabi.h> 11 12 #include "llvm/ADT/DenseMap.h" 13 14 #include "lldb/Core/ConstString.h" 15 #include "lldb/Core/Mangled.h" 16 #include "lldb/Core/Stream.h" 17 #include "lldb/Core/Timer.h" 18 #include <ctype.h> 19 #include <string.h> 20 21 using namespace lldb_private; 22 23 #pragma mark Mangled 24 //---------------------------------------------------------------------- 25 // Default constructor 26 //---------------------------------------------------------------------- 27 Mangled::Mangled () : 28 m_mangled(), 29 m_demangled() 30 { 31 } 32 33 //---------------------------------------------------------------------- 34 // Constructor with an optional string and a boolean indicating if it is 35 // the mangled version. 36 //---------------------------------------------------------------------- 37 Mangled::Mangled (const char *s, bool mangled) : 38 m_mangled(), 39 m_demangled() 40 { 41 if (s && s[0]) 42 { 43 SetValue(s, mangled); 44 } 45 } 46 47 //---------------------------------------------------------------------- 48 // Destructor 49 //---------------------------------------------------------------------- 50 Mangled::~Mangled () 51 { 52 } 53 54 //---------------------------------------------------------------------- 55 // Convert to pointer operator. This allows code to check any Mangled 56 // objects to see if they contain anything valid using code such as: 57 // 58 // Mangled mangled(...); 59 // if (mangled) 60 // { ... 61 //---------------------------------------------------------------------- 62 Mangled::operator void* () const 63 { 64 return (m_mangled) ? const_cast<Mangled*>(this) : NULL; 65 } 66 67 //---------------------------------------------------------------------- 68 // Logical NOT operator. This allows code to check any Mangled 69 // objects to see if they are invalid using code such as: 70 // 71 // Mangled mangled(...); 72 // if (!file_spec) 73 // { ... 74 //---------------------------------------------------------------------- 75 bool 76 Mangled::operator! () const 77 { 78 return !m_mangled; 79 } 80 81 //---------------------------------------------------------------------- 82 // Clear the mangled and demangled values. 83 //---------------------------------------------------------------------- 84 void 85 Mangled::Clear () 86 { 87 m_mangled.Clear(); 88 m_demangled.Clear(); 89 } 90 91 92 //---------------------------------------------------------------------- 93 // Compare the the string values. 94 //---------------------------------------------------------------------- 95 int 96 Mangled::Compare (const Mangled& a, const Mangled& b) 97 { 98 return ConstString::Compare(a.GetName(ePreferMangled), a.GetName(ePreferMangled)); 99 } 100 101 102 103 //---------------------------------------------------------------------- 104 // Set the string value in this objects. If "mangled" is true, then 105 // the mangled named is set with the new value in "s", else the 106 // demangled name is set. 107 //---------------------------------------------------------------------- 108 void 109 Mangled::SetValue (const char *s, bool mangled) 110 { 111 m_mangled.Clear(); 112 m_demangled.Clear(); 113 114 if (s) 115 { 116 if (mangled) 117 m_mangled.SetCString (s); 118 else 119 m_demangled.SetCString(s); 120 } 121 } 122 123 //---------------------------------------------------------------------- 124 // Generate the demangled name on demand using this accessor. Code in 125 // this class will need to use this accessor if it wishes to decode 126 // the demangled name. The result is cached and will be kept until a 127 // new string value is supplied to this object, or until the end of the 128 // object's lifetime. 129 //---------------------------------------------------------------------- 130 const ConstString& 131 Mangled::GetDemangledName () const 132 { 133 // Check to make sure we have a valid mangled name and that we 134 // haven't already decoded our mangled name. 135 if (m_mangled && !m_demangled) 136 { 137 // We need to generate and cache the demangled name. 138 Timer scoped_timer (__PRETTY_FUNCTION__, 139 "Mangled::GetDemangledName (m_mangled = %s)", 140 m_mangled.GetCString()); 141 142 // We already know mangled is valid from the above check, 143 // lets just make sure it isn't empty... 144 const char * mangled = m_mangled.AsCString(); 145 if (mangled[0]) 146 { 147 // Since demangling can be a costly, and since all names that go 148 // into a ConstString (like our m_mangled and m_demangled members) 149 // end up being unique "const char *" values, we can use a DenseMap 150 // to speed up our lookup. We do this because often our symbol table 151 // and our debug information both have the mangled names which they 152 // would each need to demangle. Also, with GCC we end up with the one 153 // definition rule where a lot of STL code produces symbols that are 154 // in multiple compile units and the mangled names end up being in 155 // the same binary multiple times. The performance win isn't huge, 156 // but we showed a 20% improvement on darwin. 157 typedef llvm::DenseMap<const char *, const char *> MangledToDemangledMap; 158 static MangledToDemangledMap g_mangled_to_demangled; 159 160 // Check our mangled string pointer to demangled string pointer map first 161 MangledToDemangledMap::const_iterator pos = g_mangled_to_demangled.find (mangled); 162 if (pos != g_mangled_to_demangled.end()) 163 { 164 // We have already demangled this string, we can just use our saved result! 165 m_demangled.SetCString(pos->second); 166 } 167 else 168 { 169 // We didn't already mangle this name, demangle it and if all goes well 170 // add it to our map. 171 char *demangled_name = abi::__cxa_demangle (mangled, NULL, NULL, NULL); 172 173 if (demangled_name) 174 { 175 m_demangled.SetCString (demangled_name); 176 // Now that the name has been uniqued, add the uniqued C string 177 // pointer from m_mangled as the key to the uniqued C string 178 // pointer in m_demangled. 179 g_mangled_to_demangled.insert (std::make_pair (mangled, m_demangled.GetCString())); 180 free (demangled_name); 181 } 182 else 183 { 184 // Set the demangled string to the empty string to indicate we 185 // tried to parse it once and failed. 186 m_demangled.SetCString(""); 187 } 188 } 189 } 190 } 191 192 return m_demangled; 193 } 194 195 //---------------------------------------------------------------------- 196 // Mangled name get accessor 197 //---------------------------------------------------------------------- 198 ConstString& 199 Mangled::GetMangledName () 200 { 201 return m_mangled; 202 } 203 204 //---------------------------------------------------------------------- 205 // Mangled name const get accessor 206 //---------------------------------------------------------------------- 207 const ConstString& 208 Mangled::GetMangledName () const 209 { 210 return m_mangled; 211 } 212 213 //---------------------------------------------------------------------- 214 // Get the demangled name if there is one, else return the mangled name. 215 //---------------------------------------------------------------------- 216 const ConstString& 217 Mangled::GetName (Mangled::NamePreference preference) const 218 { 219 if (preference == ePreferDemangled) 220 { 221 // Call the accessor to make sure we get a demangled name in case 222 // it hasn't been demangled yet... 223 if (GetDemangledName()) 224 return m_demangled; 225 return m_mangled; 226 } 227 else 228 { 229 if (m_mangled) 230 return m_mangled; 231 return GetDemangledName(); 232 } 233 } 234 235 //---------------------------------------------------------------------- 236 // Generate the tokens from the demangled name. 237 // 238 // Returns the number of tokens that were parsed. 239 //---------------------------------------------------------------------- 240 size_t 241 Mangled::GetTokens (Mangled::TokenList &tokens) const 242 { 243 tokens.Clear(); 244 const ConstString& demangled = GetDemangledName(); 245 if (demangled && !demangled.IsEmpty()) 246 tokens.Parse(demangled.AsCString()); 247 248 return tokens.Size(); 249 } 250 251 //---------------------------------------------------------------------- 252 // Dump a Mangled object to stream "s". We don't force our 253 // demangled name to be computed currently (we don't use the accessor). 254 //---------------------------------------------------------------------- 255 void 256 Mangled::Dump (Stream *s) const 257 { 258 if (m_mangled) 259 { 260 *s << ", mangled = " << m_mangled; 261 } 262 if (m_demangled) 263 { 264 const char * demangled = m_demangled.AsCString(); 265 s->Printf(", demangled = %s", demangled[0] ? demangled : "<error>"); 266 } 267 } 268 269 //---------------------------------------------------------------------- 270 // Dumps a debug version of this string with extra object and state 271 // information to stream "s". 272 //---------------------------------------------------------------------- 273 void 274 Mangled::DumpDebug (Stream *s) const 275 { 276 s->Printf("%*p: Mangled mangled = ", (int)sizeof(void*) * 2, this); 277 m_mangled.DumpDebug(s); 278 s->Printf(", demangled = "); 279 m_demangled.DumpDebug(s); 280 } 281 282 //---------------------------------------------------------------------- 283 // Return the size in byte that this object takes in memory. The size 284 // includes the size of the objects it owns, and not the strings that 285 // it references because they are shared strings. 286 //---------------------------------------------------------------------- 287 size_t 288 Mangled::MemorySize () const 289 { 290 return m_mangled.MemorySize() + m_demangled.MemorySize(); 291 } 292 293 //---------------------------------------------------------------------- 294 // Dump OBJ to the supplied stream S. 295 //---------------------------------------------------------------------- 296 Stream& 297 operator << (Stream& s, const Mangled& obj) 298 { 299 if (obj.GetMangledName()) 300 s << "mangled = '" << obj.GetMangledName() << "'"; 301 302 const ConstString& demangled = obj.GetDemangledName(); 303 if (demangled) 304 s << ", demangled = '" << demangled << '\''; 305 else 306 s << ", demangled = <error>"; 307 return s; 308 } 309 310 311 312 313 #pragma mark Mangled::Token 314 315 //-------------------------------------------------------------- 316 // Default constructor 317 //-------------------------------------------------------------- 318 Mangled::Token::Token () : 319 type(eInvalid), 320 value() 321 { 322 } 323 324 //-------------------------------------------------------------- 325 // Equal to operator 326 //-------------------------------------------------------------- 327 bool 328 Mangled::Token::operator== (const Token& rhs) const 329 { 330 return type == rhs.type && value == rhs.value; 331 } 332 333 //-------------------------------------------------------------- 334 // Dump the token to a stream "s" 335 //-------------------------------------------------------------- 336 void 337 Mangled::Token::Dump (Stream *s) const 338 { 339 switch (type) 340 { 341 case eInvalid: s->PutCString("invalid "); break; 342 case eNameSpace: s->PutCString("namespace "); break; 343 case eMethodName: s->PutCString("method "); break; 344 case eType: s->PutCString("type "); break; 345 case eTemplate: s->PutCString("template "); break; 346 case eTemplateBeg: s->PutCString("template < "); break; 347 case eTemplateEnd: s->PutCString("template > "); break; 348 case eParamsBeg: s->PutCString("params ( "); break; 349 case eParamsEnd: s->PutCString("params ) "); break; 350 case eQualifier: s->PutCString("qualifier "); break; 351 case eError: s->PutCString("ERROR "); break; 352 default: 353 s->Printf("type = %i", type); 354 break; 355 } 356 value.DumpDebug(s); 357 } 358 359 //-------------------------------------------------------------- 360 // Returns true if this token is a wildcard 361 //-------------------------------------------------------------- 362 bool 363 Mangled::Token::IsWildcard () const 364 { 365 static ConstString g_wildcard_str("*"); 366 return value == g_wildcard_str; 367 } 368 369 370 //---------------------------------------------------------------------- 371 // Dump "obj" to the supplied stream "s" 372 //---------------------------------------------------------------------- 373 Stream& 374 lldb_private::operator << (Stream& s, const Mangled::Token& obj) 375 { 376 obj.Dump(&s); 377 return s; 378 } 379 380 381 #pragma mark Mangled::TokenList 382 //---------------------------------------------------------------------- 383 // Mangled::TokenList 384 //---------------------------------------------------------------------- 385 386 //-------------------------------------------------------------- 387 // Default constructor. If demangled is non-NULL and not-empty 388 // the token list will parse up the demangled string it is 389 // given, else the object will initialize an empty token list. 390 //-------------------------------------------------------------- 391 Mangled::TokenList::TokenList (const char *demangled) : 392 m_tokens() 393 { 394 if (demangled && demangled[0]) 395 { 396 Parse(demangled); 397 } 398 } 399 400 //---------------------------------------------------------------------- 401 // Destructor 402 //---------------------------------------------------------------------- 403 Mangled::TokenList::~TokenList () 404 { 405 } 406 407 //---------------------------------------------------------------------- 408 // Parses "demangled" into tokens. This allows complex 409 // comparisons to be done. Comparisons can include wildcards at 410 // the namespace, method name, template, and template and 411 // parameter type levels. 412 // 413 // Example queries include: 414 // "std::basic_string<*>" // Find all std::basic_string variants 415 // "std::basic_string<*>::erase(*)" // Find all std::basic_string::erase variants with any number of parameters 416 // "*::clear()" // Find all functions with a method name of 417 // // "clear" that are in any namespace that 418 // // have no parameters 419 // "::printf" // Find the printf function in the global namespace 420 // "printf" // Ditto 421 // "foo::*(int)" // Find all functions in the class or namespace "foo" that take a single integer argument 422 // 423 // Returns the number of tokens that were decoded, or zero when 424 // we fail. 425 //---------------------------------------------------------------------- 426 size_t 427 Mangled::TokenList::Parse (const char *s) 428 { 429 m_tokens.clear(); 430 431 Token token; 432 token.type = eNameSpace; 433 434 TokenType max_type = eInvalid; 435 const char *p = s; 436 size_t span = 0; 437 size_t sep_size = 0; 438 439 while (*p != '\0') 440 { 441 p = p + span + sep_size; 442 while (isspace(*p)) 443 ++p; 444 445 if (*p == '\0') 446 break; 447 448 span = strcspn(p, ":<>(),"); 449 sep_size = 1; 450 token.type = eInvalid; 451 switch (p[span]) 452 { 453 case '\0': 454 break; 455 456 case ':': 457 if (p[span+1] == ':') 458 { 459 sep_size = 2; 460 if (span > 0) 461 { 462 token.type = eNameSpace; 463 token.value.SetCStringWithLength (p, span); 464 m_tokens.push_back(token); 465 } 466 else 467 continue; 468 } 469 break; 470 471 case '(': 472 if (span > 0) 473 { 474 token.type = eMethodName; 475 token.value.SetCStringWithLength (p, span); 476 m_tokens.push_back(token); 477 } 478 479 token.type = eParamsBeg; 480 token.value.Clear(); 481 m_tokens.push_back(token); 482 break; 483 484 case ',': 485 if (span > 0) 486 { 487 token.type = eType; 488 token.value.SetCStringWithLength (p, span); 489 m_tokens.push_back(token); 490 } 491 else 492 { 493 continue; 494 } 495 break; 496 497 case ')': 498 if (span > 0) 499 { 500 token.type = eType; 501 token.value.SetCStringWithLength (p, span); 502 m_tokens.push_back(token); 503 } 504 505 token.type = eParamsEnd; 506 token.value.Clear(); 507 m_tokens.push_back(token); 508 break; 509 510 case '<': 511 if (span > 0) 512 { 513 token.type = eTemplate; 514 token.value.SetCStringWithLength (p, span); 515 m_tokens.push_back(token); 516 } 517 518 token.type = eTemplateBeg; 519 token.value.Clear(); 520 m_tokens.push_back(token); 521 break; 522 523 case '>': 524 if (span > 0) 525 { 526 token.type = eType; 527 token.value.SetCStringWithLength (p, span); 528 m_tokens.push_back(token); 529 } 530 531 token.type = eTemplateEnd; 532 token.value.Clear(); 533 m_tokens.push_back(token); 534 break; 535 } 536 537 if (max_type < token.type) 538 max_type = token.type; 539 540 if (token.type == eInvalid) 541 { 542 if (max_type >= eParamsEnd) 543 { 544 token.type = eQualifier; 545 token.value.SetCString(p); 546 m_tokens.push_back(token); 547 } 548 else if (max_type >= eParamsBeg) 549 { 550 token.type = eType; 551 token.value.SetCString(p); 552 m_tokens.push_back(token); 553 } 554 else 555 { 556 token.type = eMethodName; 557 token.value.SetCString(p); 558 m_tokens.push_back(token); 559 } 560 break; 561 } 562 } 563 return m_tokens.size(); 564 } 565 566 567 //---------------------------------------------------------------------- 568 // Clear the token list. 569 //---------------------------------------------------------------------- 570 void 571 Mangled::TokenList::Clear () 572 { 573 m_tokens.clear(); 574 } 575 576 //---------------------------------------------------------------------- 577 // Dump the token list to the stream "s" 578 //---------------------------------------------------------------------- 579 void 580 Mangled::TokenList::Dump (Stream *s) const 581 { 582 collection::const_iterator pos; 583 collection::const_iterator beg = m_tokens.begin(); 584 collection::const_iterator end = m_tokens.end(); 585 for (pos = beg; pos != end; ++pos) 586 { 587 s->Indent("token["); 588 *s << (uint32_t)std::distance(beg, pos) << "] = " << *pos << "\n"; 589 } 590 } 591 592 //---------------------------------------------------------------------- 593 // Find the first token in the list that has "token_type" as its 594 // type 595 //---------------------------------------------------------------------- 596 const Mangled::Token * 597 Mangled::TokenList::Find (TokenType token_type) const 598 { 599 collection::const_iterator pos; 600 collection::const_iterator beg = m_tokens.begin(); 601 collection::const_iterator end = m_tokens.end(); 602 for (pos = beg; pos != end; ++pos) 603 { 604 if (pos->type == token_type) 605 return &(*pos); 606 } 607 return NULL; 608 } 609 610 //---------------------------------------------------------------------- 611 // Return the token at index "idx", or NULL if the index is 612 // out of range. 613 //---------------------------------------------------------------------- 614 const Mangled::Token * 615 Mangled::TokenList::GetTokenAtIndex (uint32_t idx) const 616 { 617 if (idx < m_tokens.size()) 618 return &m_tokens[idx]; 619 return NULL; 620 } 621 622 623 //---------------------------------------------------------------------- 624 // Given a token list, see if it matches this object's tokens. 625 // "token_list" can contain wild card values to enable powerful 626 // matching. Matching the std::string::erase(*) example that was 627 // tokenized above we could use a token list such as: 628 // 629 // token name 630 // ----------- ---------------------------------------- 631 // eNameSpace "std" 632 // eTemplate "basic_string" 633 // eTemplateBeg 634 // eInvalid "*" 635 // eTemplateEnd 636 // eMethodName "erase" 637 // eParamsBeg 638 // eInvalid "*" 639 // eParamsEnd 640 // 641 // Returns true if it "token_list" matches this object's tokens, 642 // false otherwise. 643 //---------------------------------------------------------------------- 644 bool 645 Mangled::TokenList::MatchesQuery (const Mangled::TokenList &match) const 646 { 647 size_t match_count = 0; 648 collection::const_iterator pos; 649 collection::const_iterator pos_end = m_tokens.end(); 650 651 collection::const_iterator match_pos; 652 collection::const_iterator match_pos_end = match.m_tokens.end(); 653 collection::const_iterator match_wildcard_pos = match_pos_end; 654 collection::const_iterator match_next_pos = match_pos_end; 655 656 size_t template_scope_depth = 0; 657 658 for (pos = m_tokens.begin(), match_pos = match.m_tokens.begin(); 659 pos != pos_end && match_pos != match_pos_end; 660 ++match_pos) 661 { 662 match_next_pos = match_pos + 1; 663 // Is this a wildcard? 664 if (match_pos->IsWildcard()) 665 { 666 if (match_wildcard_pos != match_pos_end) 667 return false; // Can't have two wildcards in effect at once. 668 669 match_wildcard_pos = match_pos; 670 // Are we at the end of the MATCH token list? 671 if (match_next_pos == match_pos_end) 672 { 673 // There is nothing more to match, return if we have any matches so far... 674 return match_count > 0; 675 } 676 } 677 678 if (match_pos->type == eInvalid || match_pos->type == eError) 679 { 680 return false; 681 } 682 else 683 { 684 if (match_pos->type == eTemplateBeg) 685 { 686 ++template_scope_depth; 687 } 688 else if (match_pos->type == eTemplateEnd) 689 { 690 assert(template_scope_depth > 0); 691 --template_scope_depth; 692 } 693 694 // Do we have a wildcard going right now? 695 if (match_wildcard_pos == match_pos_end) 696 { 697 // No wildcard matching right now, just check and see if things match 698 if (*pos == *match_pos) 699 ++match_count; 700 else 701 return false; 702 } 703 else 704 { 705 // We have a wildcard match going 706 707 // For template types we need to make sure to match the template depths... 708 const size_t start_wildcard_template_scope_depth = template_scope_depth; 709 size_t curr_wildcard_template_scope_depth = template_scope_depth; 710 while (pos != pos_end) 711 { 712 if (match_wildcard_pos->type == eNameSpace && pos->type == eParamsBeg) 713 return false; 714 715 if (start_wildcard_template_scope_depth == curr_wildcard_template_scope_depth) 716 { 717 if (*pos == *match_next_pos) 718 { 719 ++match_count; 720 match_pos = match_next_pos; 721 match_wildcard_pos = match_pos_end; 722 break; 723 } 724 } 725 if (pos->type == eTemplateBeg) 726 ++curr_wildcard_template_scope_depth; 727 else if (pos->type == eTemplateEnd) 728 --curr_wildcard_template_scope_depth; 729 730 731 ++pos; 732 } 733 } 734 } 735 736 if (pos != pos_end) 737 ++pos; 738 } 739 if (match_pos != match_pos_end) 740 return false; 741 742 return match_count > 0; 743 } 744 745 746 //---------------------------------------------------------------------- 747 // Return the number of tokens in the token collection 748 //---------------------------------------------------------------------- 749 size_t 750 Mangled::TokenList::Size () const 751 { 752 return m_tokens.size(); 753 } 754 755 756 //---------------------------------------------------------------------- 757 // Stream out the tokens 758 //---------------------------------------------------------------------- 759 Stream& 760 lldb_private::operator << (Stream& s, const Mangled::TokenList& obj) 761 { 762 obj.Dump(&s); 763 return s; 764 } 765