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