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