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