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