blob: d69753d79fbcc719898b194f7c31ae0a4e6a27dc [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- 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
Greg Claytone41e5892010-09-03 23:26:12 +000012#include "llvm/ADT/DenseMap.h"
13
Chris Lattner30fdc8d2010-06-08 16:52:24 +000014#include "lldb/Core/ConstString.h"
15#include "lldb/Core/Mangled.h"
16#include "lldb/Core/Stream.h"
17#include "lldb/Core/Timer.h"
Eli Friedman88966972010-06-09 08:50:27 +000018#include <ctype.h>
19#include <string.h>
Chris Lattner30fdc8d2010-06-08 16:52:24 +000020
21using namespace lldb_private;
22
23#pragma mark Mangled
24//----------------------------------------------------------------------
25// Default constructor
26//----------------------------------------------------------------------
27Mangled::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//----------------------------------------------------------------------
37Mangled::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//----------------------------------------------------------------------
50Mangled::~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//----------------------------------------------------------------------
62Mangled::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//----------------------------------------------------------------------
75bool
76Mangled::operator! () const
77{
78 return !m_mangled;
79}
80
81//----------------------------------------------------------------------
82// Clear the mangled and demangled values.
83//----------------------------------------------------------------------
84void
85Mangled::Clear ()
86{
87 m_mangled.Clear();
88 m_demangled.Clear();
89}
90
91
92//----------------------------------------------------------------------
93// Compare the the string values.
94//----------------------------------------------------------------------
95int
96Mangled::Compare (const Mangled& a, const Mangled& b)
97{
Jim Ingham89bf5e92010-09-15 00:13:44 +000098 return ConstString::Compare(a.GetName(ePreferMangled), a.GetName(ePreferMangled));
Chris Lattner30fdc8d2010-06-08 16:52:24 +000099}
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//----------------------------------------------------------------------
108void
109Mangled::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
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000123//----------------------------------------------------------------------
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//----------------------------------------------------------------------
130const ConstString&
131Mangled::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 {
Greg Claytone41e5892010-09-03 23:26:12 +0000147 // 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;
Benjamin Kramer53a61dc2010-06-22 15:28:29 +0000159
Greg Claytone41e5892010-09-03 23:26:12 +0000160 // 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())
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000163 {
Greg Claytone41e5892010-09-03 23:26:12 +0000164 // We have already demangled this string, we can just use our saved result!
165 m_demangled.SetCString(pos->second);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000166 }
167 else
168 {
Greg Claytone41e5892010-09-03 23:26:12 +0000169 // 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 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000188 }
189 }
190 }
191
192 return m_demangled;
193}
194
195//----------------------------------------------------------------------
196// Mangled name get accessor
197//----------------------------------------------------------------------
198ConstString&
199Mangled::GetMangledName ()
200{
201 return m_mangled;
202}
203
204//----------------------------------------------------------------------
205// Mangled name const get accessor
206//----------------------------------------------------------------------
207const ConstString&
208Mangled::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//----------------------------------------------------------------------
216const ConstString&
Jim Ingham08b87e02010-09-14 22:03:00 +0000217Mangled::GetName (Mangled::NamePreference preference) const
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000218{
Greg Clayton87425432010-09-14 23:44:49 +0000219 if (preference == ePreferDemangled)
Jim Ingham08b87e02010-09-14 22:03:00 +0000220 {
Greg Claytond0b89f82010-09-14 23:48:44 +0000221 // 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;
Greg Clayton87425432010-09-14 23:44:49 +0000225 return m_mangled;
226 }
227 else
228 {
Greg Claytond0b89f82010-09-14 23:48:44 +0000229 if (m_mangled)
230 return m_mangled;
231 return GetDemangledName();
Jim Ingham08b87e02010-09-14 22:03:00 +0000232 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000233}
234
235//----------------------------------------------------------------------
236// Generate the tokens from the demangled name.
237//
238// Returns the number of tokens that were parsed.
239//----------------------------------------------------------------------
240size_t
241Mangled::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//----------------------------------------------------------------------
255void
256Mangled::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//----------------------------------------------------------------------
273void
274Mangled::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//----------------------------------------------------------------------
287size_t
288Mangled::MemorySize () const
289{
290 return m_mangled.MemorySize() + m_demangled.MemorySize();
291}
292
293//----------------------------------------------------------------------
294// Dump OBJ to the supplied stream S.
295//----------------------------------------------------------------------
296Stream&
297operator << (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//--------------------------------------------------------------
318Mangled::Token::Token () :
319 type(eInvalid),
320 value()
321{
322}
323
324//--------------------------------------------------------------
325// Equal to operator
326//--------------------------------------------------------------
327bool
328Mangled::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//--------------------------------------------------------------
336void
337Mangled::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//--------------------------------------------------------------
362bool
363Mangled::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//----------------------------------------------------------------------
373Stream&
374lldb_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//--------------------------------------------------------------
391Mangled::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//----------------------------------------------------------------------
403Mangled::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//----------------------------------------------------------------------
426size_t
427Mangled::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//----------------------------------------------------------------------
570void
571Mangled::TokenList::Clear ()
572{
573 m_tokens.clear();
574}
575
576//----------------------------------------------------------------------
577// Dump the token list to the stream "s"
578//----------------------------------------------------------------------
579void
580Mangled::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//----------------------------------------------------------------------
596const Mangled::Token *
597Mangled::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//----------------------------------------------------------------------
614const Mangled::Token *
615Mangled::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//----------------------------------------------------------------------
644bool
645Mangled::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//----------------------------------------------------------------------
749size_t
750Mangled::TokenList::Size () const
751{
752 return m_tokens.size();
753}
754
755
756//----------------------------------------------------------------------
757// Stream out the tokens
758//----------------------------------------------------------------------
759Stream&
760lldb_private::operator << (Stream& s, const Mangled::TokenList& obj)
761{
762 obj.Dump(&s);
763 return s;
764}