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