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