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