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 //----------------------------------------------------------------------
195 // Mangled name get accessor
196 //----------------------------------------------------------------------
197 ConstString&
198 Mangled::GetMangledName ()
199 {
200     return m_mangled;
201 }
202 
203 //----------------------------------------------------------------------
204 // Mangled name const get accessor
205 //----------------------------------------------------------------------
206 const ConstString&
207 Mangled::GetMangledName () const
208 {
209     return m_mangled;
210 }
211 
212 //----------------------------------------------------------------------
213 // Get the demangled name if there is one, else return the mangled name.
214 //----------------------------------------------------------------------
215 const ConstString&
216 Mangled::GetName (Mangled::NamePreference preference) const
217 {
218     if (preference == ePreferDemangled)
219     {
220         // Call the accessor to make sure we get a demangled name in case
221         // it hasn't been demangled yet...
222         if (GetDemangledName())
223             return m_demangled;
224         return m_mangled;
225     }
226     else
227     {
228         if (m_mangled)
229             return m_mangled;
230         return GetDemangledName();
231     }
232 }
233 
234 //----------------------------------------------------------------------
235 // Generate the tokens from the demangled name.
236 //
237 // Returns the number of tokens that were parsed.
238 //----------------------------------------------------------------------
239 size_t
240 Mangled::GetTokens (Mangled::TokenList &tokens) const
241 {
242     tokens.Clear();
243     const ConstString& demangled = GetDemangledName();
244     if (demangled && !demangled.IsEmpty())
245         tokens.Parse(demangled.AsCString());
246 
247     return tokens.Size();
248 }
249 
250 //----------------------------------------------------------------------
251 // Dump a Mangled object to stream "s". We don't force our
252 // demangled name to be computed currently (we don't use the accessor).
253 //----------------------------------------------------------------------
254 void
255 Mangled::Dump (Stream *s) const
256 {
257     if (m_mangled)
258     {
259         *s << ", mangled = " << m_mangled;
260     }
261     if (m_demangled)
262     {
263         const char * demangled = m_demangled.AsCString();
264         s->Printf(", demangled = %s", demangled[0] ? demangled : "<error>");
265     }
266 }
267 
268 //----------------------------------------------------------------------
269 // Dumps a debug version of this string with extra object and state
270 // information to stream "s".
271 //----------------------------------------------------------------------
272 void
273 Mangled::DumpDebug (Stream *s) const
274 {
275     s->Printf("%*p: Mangled mangled = ", (int)sizeof(void*) * 2, this);
276     m_mangled.DumpDebug(s);
277     s->Printf(", demangled = ");
278     m_demangled.DumpDebug(s);
279 }
280 
281 //----------------------------------------------------------------------
282 // Return the size in byte that this object takes in memory. The size
283 // includes the size of the objects it owns, and not the strings that
284 // it references because they are shared strings.
285 //----------------------------------------------------------------------
286 size_t
287 Mangled::MemorySize () const
288 {
289     return m_mangled.MemorySize() + m_demangled.MemorySize();
290 }
291 
292 //----------------------------------------------------------------------
293 // Dump OBJ to the supplied stream S.
294 //----------------------------------------------------------------------
295 Stream&
296 operator << (Stream& s, const Mangled& obj)
297 {
298     if (obj.GetMangledName())
299         s << "mangled = '" << obj.GetMangledName() << "'";
300 
301     const ConstString& demangled = obj.GetDemangledName();
302     if (demangled)
303         s << ", demangled = '" << demangled << '\'';
304     else
305         s << ", demangled = <error>";
306     return s;
307 }
308 
309 
310 
311 
312 #pragma mark Mangled::Token
313 
314 //--------------------------------------------------------------
315 // Default constructor
316 //--------------------------------------------------------------
317 Mangled::Token::Token () :
318     type(eInvalid),
319     value()
320 {
321 }
322 
323 //--------------------------------------------------------------
324 // Equal to operator
325 //--------------------------------------------------------------
326 bool
327 Mangled::Token::operator== (const Token& rhs) const
328 {
329     return type == rhs.type && value == rhs.value;
330 }
331 
332 //--------------------------------------------------------------
333 // Dump the token to a stream "s"
334 //--------------------------------------------------------------
335 void
336 Mangled::Token::Dump (Stream *s) const
337 {
338     switch (type)
339     {
340     case eInvalid:      s->PutCString("invalid    "); break;
341     case eNameSpace:    s->PutCString("namespace  "); break;
342     case eMethodName:   s->PutCString("method     "); break;
343     case eType:         s->PutCString("type       "); break;
344     case eTemplate:     s->PutCString("template   "); break;
345     case eTemplateBeg:  s->PutCString("template < "); break;
346     case eTemplateEnd:  s->PutCString("template > "); break;
347     case eParamsBeg:    s->PutCString("params   ( "); break;
348     case eParamsEnd:    s->PutCString("params   ) "); break;
349     case eQualifier:    s->PutCString("qualifier  "); break;
350     case eError:        s->PutCString("ERROR      "); break;
351     default:
352         s->Printf("type = %i", type);
353         break;
354     }
355     value.DumpDebug(s);
356 }
357 
358 //--------------------------------------------------------------
359 // Returns true if this token is a wildcard
360 //--------------------------------------------------------------
361 bool
362 Mangled::Token::IsWildcard () const
363 {
364     static ConstString g_wildcard_str("*");
365     return value == g_wildcard_str;
366 }
367 
368 
369 //----------------------------------------------------------------------
370 // Dump "obj" to the supplied stream "s"
371 //----------------------------------------------------------------------
372 Stream&
373 lldb_private::operator << (Stream& s, const Mangled::Token& obj)
374 {
375     obj.Dump(&s);
376     return s;
377 }
378 
379 
380 #pragma mark Mangled::TokenList
381 //----------------------------------------------------------------------
382 // Mangled::TokenList
383 //----------------------------------------------------------------------
384 
385 //--------------------------------------------------------------
386 // Default constructor. If demangled is non-NULL and not-empty
387 // the token list will parse up the demangled string it is
388 // given, else the object will initialize an empty token list.
389 //--------------------------------------------------------------
390 Mangled::TokenList::TokenList (const char *demangled) :
391     m_tokens()
392 {
393     if (demangled && demangled[0])
394     {
395         Parse(demangled);
396     }
397 }
398 
399 //----------------------------------------------------------------------
400 // Destructor
401 //----------------------------------------------------------------------
402 Mangled::TokenList::~TokenList ()
403 {
404 }
405 
406 //----------------------------------------------------------------------
407 // Parses "demangled" into tokens. This allows complex
408 // comparisons to be done. Comparisons can include wildcards at
409 // the namespace, method name, template, and template and
410 // parameter type levels.
411 //
412 // Example queries include:
413 // "std::basic_string<*>"   // Find all std::basic_string variants
414 // "std::basic_string<*>::erase(*)" // Find all std::basic_string::erase variants with any number of parameters
415 // "*::clear()"             // Find all functions with a method name of
416 //                          // "clear" that are in any namespace that
417 //                          // have no parameters
418 // "::printf"               // Find the printf function in the global namespace
419 // "printf"                 // Ditto
420 // "foo::*(int)"            // Find all functions in the class or namespace "foo" that take a single integer argument
421 //
422 // Returns the number of tokens that were decoded, or zero when
423 // we fail.
424 //----------------------------------------------------------------------
425 size_t
426 Mangled::TokenList::Parse (const char *s)
427 {
428     m_tokens.clear();
429 
430     Token token;
431     token.type = eNameSpace;
432 
433     TokenType max_type = eInvalid;
434     const char *p = s;
435     size_t span = 0;
436     size_t sep_size = 0;
437 
438     while (*p != '\0')
439     {
440         p = p + span + sep_size;
441         while (isspace(*p))
442             ++p;
443 
444         if (*p == '\0')
445             break;
446 
447         span = strcspn(p, ":<>(),");
448         sep_size = 1;
449         token.type = eInvalid;
450         switch (p[span])
451         {
452         case '\0':
453             break;
454 
455         case ':':
456             if (p[span+1] == ':')
457             {
458                 sep_size = 2;
459                 if (span > 0)
460                 {
461                     token.type = eNameSpace;
462                     token.value.SetCStringWithLength (p, span);
463                     m_tokens.push_back(token);
464                 }
465                 else
466                     continue;
467             }
468             break;
469 
470         case '(':
471             if (span > 0)
472             {
473                 token.type = eMethodName;
474                 token.value.SetCStringWithLength (p, span);
475                 m_tokens.push_back(token);
476             }
477 
478             token.type = eParamsBeg;
479             token.value.Clear();
480             m_tokens.push_back(token);
481             break;
482 
483         case ',':
484             if (span > 0)
485             {
486                 token.type = eType;
487                 token.value.SetCStringWithLength (p, span);
488                 m_tokens.push_back(token);
489             }
490             else
491             {
492                 continue;
493             }
494             break;
495 
496         case ')':
497             if (span > 0)
498             {
499                 token.type = eType;
500                 token.value.SetCStringWithLength (p, span);
501                 m_tokens.push_back(token);
502             }
503 
504             token.type = eParamsEnd;
505             token.value.Clear();
506             m_tokens.push_back(token);
507             break;
508 
509         case '<':
510             if (span > 0)
511             {
512                 token.type = eTemplate;
513                 token.value.SetCStringWithLength (p, span);
514                 m_tokens.push_back(token);
515             }
516 
517             token.type = eTemplateBeg;
518             token.value.Clear();
519             m_tokens.push_back(token);
520             break;
521 
522         case '>':
523             if (span > 0)
524             {
525                 token.type = eType;
526                 token.value.SetCStringWithLength (p, span);
527                 m_tokens.push_back(token);
528             }
529 
530             token.type = eTemplateEnd;
531             token.value.Clear();
532             m_tokens.push_back(token);
533             break;
534         }
535 
536         if (max_type < token.type)
537             max_type = token.type;
538 
539         if (token.type == eInvalid)
540         {
541             if (max_type >= eParamsEnd)
542             {
543                 token.type = eQualifier;
544                 token.value.SetCString(p);
545                 m_tokens.push_back(token);
546             }
547             else if (max_type >= eParamsBeg)
548             {
549                 token.type = eType;
550                 token.value.SetCString(p);
551                 m_tokens.push_back(token);
552             }
553             else
554             {
555                 token.type = eMethodName;
556                 token.value.SetCString(p);
557                 m_tokens.push_back(token);
558             }
559             break;
560         }
561     }
562     return m_tokens.size();
563 }
564 
565 
566 //----------------------------------------------------------------------
567 // Clear the token list.
568 //----------------------------------------------------------------------
569 void
570 Mangled::TokenList::Clear ()
571 {
572     m_tokens.clear();
573 }
574 
575 //----------------------------------------------------------------------
576 // Dump the token list to the stream "s"
577 //----------------------------------------------------------------------
578 void
579 Mangled::TokenList::Dump (Stream *s) const
580 {
581     collection::const_iterator pos;
582     collection::const_iterator beg = m_tokens.begin();
583     collection::const_iterator end = m_tokens.end();
584     for (pos = beg; pos != end; ++pos)
585     {
586         s->Indent("token[");
587         *s << (uint32_t)std::distance(beg, pos) << "] = " << *pos << "\n";
588     }
589 }
590 
591 //----------------------------------------------------------------------
592 // Find the first token in the list that has "token_type" as its
593 // type
594 //----------------------------------------------------------------------
595 const Mangled::Token *
596 Mangled::TokenList::Find (TokenType token_type) const
597 {
598     collection::const_iterator pos;
599     collection::const_iterator beg = m_tokens.begin();
600     collection::const_iterator end = m_tokens.end();
601     for (pos = beg; pos != end; ++pos)
602     {
603         if (pos->type == token_type)
604             return &(*pos);
605     }
606     return NULL;
607 }
608 
609 //----------------------------------------------------------------------
610 // Return the token at index "idx", or NULL if the index is
611 // out of range.
612 //----------------------------------------------------------------------
613 const Mangled::Token *
614 Mangled::TokenList::GetTokenAtIndex (uint32_t idx) const
615 {
616     if (idx < m_tokens.size())
617         return &m_tokens[idx];
618     return NULL;
619 }
620 
621 
622 //----------------------------------------------------------------------
623 // Given a token list, see if it matches this object's tokens.
624 // "token_list" can contain wild card values to enable powerful
625 // matching. Matching the std::string::erase(*) example that was
626 // tokenized above we could use a token list such as:
627 //
628 //      token           name
629 //      -----------     ----------------------------------------
630 //      eNameSpace      "std"
631 //      eTemplate       "basic_string"
632 //      eTemplateBeg
633 //      eInvalid        "*"
634 //      eTemplateEnd
635 //      eMethodName     "erase"
636 //      eParamsBeg
637 //      eInvalid        "*"
638 //      eParamsEnd
639 //
640 // Returns true if it "token_list" matches this object's tokens,
641 // false otherwise.
642 //----------------------------------------------------------------------
643 bool
644 Mangled::TokenList::MatchesQuery (const Mangled::TokenList &match) const
645 {
646     size_t match_count = 0;
647     collection::const_iterator pos;
648     collection::const_iterator pos_end = m_tokens.end();
649 
650     collection::const_iterator match_pos;
651     collection::const_iterator match_pos_end = match.m_tokens.end();
652     collection::const_iterator match_wildcard_pos = match_pos_end;
653     collection::const_iterator match_next_pos = match_pos_end;
654 
655     size_t template_scope_depth = 0;
656 
657     for (pos = m_tokens.begin(), match_pos = match.m_tokens.begin();
658          pos != pos_end && match_pos != match_pos_end;
659          ++match_pos)
660     {
661         match_next_pos = match_pos + 1;
662         // Is this a wildcard?
663         if (match_pos->IsWildcard())
664         {
665             if (match_wildcard_pos != match_pos_end)
666                 return false;   // Can't have two wildcards in effect at once.
667 
668             match_wildcard_pos = match_pos;
669             // Are we at the end of the MATCH token list?
670             if (match_next_pos == match_pos_end)
671             {
672                 // There is nothing more to match, return if we have any matches so far...
673                 return match_count > 0;
674             }
675         }
676 
677         if (match_pos->type == eInvalid || match_pos->type == eError)
678         {
679             return false;
680         }
681         else
682         {
683             if (match_pos->type == eTemplateBeg)
684             {
685                 ++template_scope_depth;
686             }
687             else if (match_pos->type == eTemplateEnd)
688             {
689                 assert(template_scope_depth > 0);
690                 --template_scope_depth;
691             }
692 
693             // Do we have a wildcard going right now?
694             if (match_wildcard_pos == match_pos_end)
695             {
696                 // No wildcard matching right now, just check and see if things match
697                 if (*pos == *match_pos)
698                     ++match_count;
699                 else
700                     return false;
701             }
702             else
703             {
704                 // We have a wildcard match going
705 
706                 // For template types we need to make sure to match the template depths...
707                 const size_t start_wildcard_template_scope_depth = template_scope_depth;
708                 size_t curr_wildcard_template_scope_depth = template_scope_depth;
709                 while (pos != pos_end)
710                 {
711                     if (match_wildcard_pos->type == eNameSpace && pos->type == eParamsBeg)
712                         return false;
713 
714                     if (start_wildcard_template_scope_depth == curr_wildcard_template_scope_depth)
715                     {
716                         if (*pos == *match_next_pos)
717                         {
718                             ++match_count;
719                             match_pos = match_next_pos;
720                             match_wildcard_pos = match_pos_end;
721                             break;
722                         }
723                     }
724                     if (pos->type == eTemplateBeg)
725                         ++curr_wildcard_template_scope_depth;
726                     else if (pos->type == eTemplateEnd)
727                         --curr_wildcard_template_scope_depth;
728 
729 
730                     ++pos;
731                 }
732             }
733         }
734 
735         if (pos != pos_end)
736             ++pos;
737     }
738     if (match_pos != match_pos_end)
739         return false;
740 
741     return match_count > 0;
742 }
743 
744 
745 //----------------------------------------------------------------------
746 // Return the number of tokens in the token collection
747 //----------------------------------------------------------------------
748 size_t
749 Mangled::TokenList::Size () const
750 {
751     return m_tokens.size();
752 }
753 
754 
755 //----------------------------------------------------------------------
756 // Stream out the tokens
757 //----------------------------------------------------------------------
758 Stream&
759 lldb_private::operator << (Stream& s, const Mangled::TokenList& obj)
760 {
761     obj.Dump(&s);
762     return s;
763 }
764