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