summaryrefslogtreecommitdiffstats
path: root/lldb/source/Core/Mangled.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Core/Mangled.cpp')
-rw-r--r--lldb/source/Core/Mangled.cpp733
1 files changed, 733 insertions, 0 deletions
diff --git a/lldb/source/Core/Mangled.cpp b/lldb/source/Core/Mangled.cpp
new file mode 100644
index 00000000000..38667a86def
--- /dev/null
+++ b/lldb/source/Core/Mangled.cpp
@@ -0,0 +1,733 @@
+//===-- Mangled.cpp ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <cxxabi.h>
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Mangled.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/Timer.h"
+
+using namespace lldb_private;
+
+#pragma mark Mangled
+//----------------------------------------------------------------------
+// Default constructor
+//----------------------------------------------------------------------
+Mangled::Mangled () :
+ m_mangled(),
+ m_demangled()
+{
+}
+
+//----------------------------------------------------------------------
+// Constructor with an optional string and a boolean indicating if it is
+// the mangled version.
+//----------------------------------------------------------------------
+Mangled::Mangled (const char *s, bool mangled) :
+ m_mangled(),
+ m_demangled()
+{
+ if (s && s[0])
+ {
+ SetValue(s, mangled);
+ }
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+Mangled::~Mangled ()
+{
+}
+
+//----------------------------------------------------------------------
+// Convert to pointer operator. This allows code to check any Mangled
+// objects to see if they contain anything valid using code such as:
+//
+// Mangled mangled(...);
+// if (mangled)
+// { ...
+//----------------------------------------------------------------------
+Mangled::operator void* () const
+{
+ return (m_mangled) ? const_cast<Mangled*>(this) : NULL;
+}
+
+//----------------------------------------------------------------------
+// Logical NOT operator. This allows code to check any Mangled
+// objects to see if they are invalid using code such as:
+//
+// Mangled mangled(...);
+// if (!file_spec)
+// { ...
+//----------------------------------------------------------------------
+bool
+Mangled::operator! () const
+{
+ return !m_mangled;
+}
+
+//----------------------------------------------------------------------
+// Clear the mangled and demangled values.
+//----------------------------------------------------------------------
+void
+Mangled::Clear ()
+{
+ m_mangled.Clear();
+ m_demangled.Clear();
+}
+
+
+//----------------------------------------------------------------------
+// Compare the the string values.
+//----------------------------------------------------------------------
+int
+Mangled::Compare (const Mangled& a, const Mangled& b)
+{
+ return ConstString::Compare(a.GetName(), a.GetName());
+}
+
+
+
+//----------------------------------------------------------------------
+// Set the string value in this objects. If "mangled" is true, then
+// the mangled named is set with the new value in "s", else the
+// demangled name is set.
+//----------------------------------------------------------------------
+void
+Mangled::SetValue (const char *s, bool mangled)
+{
+ m_mangled.Clear();
+ m_demangled.Clear();
+
+ if (s)
+ {
+ if (mangled)
+ m_mangled.SetCString (s);
+ else
+ m_demangled.SetCString(s);
+ }
+}
+
+
+//----------------------------------------------------------------------
+// Generate the demangled name on demand using this accessor. Code in
+// this class will need to use this accessor if it wishes to decode
+// the demangled name. The result is cached and will be kept until a
+// new string value is supplied to this object, or until the end of the
+// object's lifetime.
+//----------------------------------------------------------------------
+const ConstString&
+Mangled::GetDemangledName () const
+{
+ // Check to make sure we have a valid mangled name and that we
+ // haven't already decoded our mangled name.
+ if (m_mangled && !m_demangled)
+ {
+ // We need to generate and cache the demangled name.
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "Mangled::GetDemangledName (m_mangled = %s)",
+ m_mangled.GetCString());
+
+ // We already know mangled is valid from the above check,
+ // lets just make sure it isn't empty...
+ const char * mangled = m_mangled.AsCString();
+ if (mangled[0])
+ {
+ // The first time the demangling routine is called, it will
+ // return a buffer value and length and we will continue to
+ // re-use that buffer so we don't always have to malloc/free
+ // a buffer for each demangle. The buffer can be realloc'ed
+ // by abi::__cxa_demangle, so we may need to make it thread
+ // specific if we ever start doing multi-threaded calls to
+ // this function. g_demangle_buf will currently leak one
+ // malloc entry that can vary in size. If we need to reclaim
+ // this memory, we will need to add some code to free this
+ // buffer at exit time.
+ static char *g_demangle_buf = NULL;
+ static size_t g_demangle_buf_len = 0;
+ int status = 0;
+ g_demangle_buf = abi::__cxa_demangle(mangled, g_demangle_buf, &g_demangle_buf_len, &status);
+ if (g_demangle_buf != NULL)
+ {
+ m_demangled.SetCString(g_demangle_buf);
+ }
+ else
+ {
+ // Set the demangled string to the empty string to indicate we
+ // tried to parse it once and failed.
+ m_demangled.SetCString("");
+ }
+ }
+ }
+
+ return m_demangled;
+}
+
+//----------------------------------------------------------------------
+// Mangled name get accessor
+//----------------------------------------------------------------------
+ConstString&
+Mangled::GetMangledName ()
+{
+ return m_mangled;
+}
+
+//----------------------------------------------------------------------
+// Mangled name const get accessor
+//----------------------------------------------------------------------
+const ConstString&
+Mangled::GetMangledName () const
+{
+ return m_mangled;
+}
+
+//----------------------------------------------------------------------
+// Get the demangled name if there is one, else return the mangled name.
+//----------------------------------------------------------------------
+const ConstString&
+Mangled::GetName () const
+{
+ const ConstString& name = GetDemangledName();
+ if (name && !name.IsEmpty())
+ return name;
+ return m_mangled;
+}
+
+//----------------------------------------------------------------------
+// Generate the tokens from the demangled name.
+//
+// Returns the number of tokens that were parsed.
+//----------------------------------------------------------------------
+size_t
+Mangled::GetTokens (Mangled::TokenList &tokens) const
+{
+ tokens.Clear();
+ const ConstString& demangled = GetDemangledName();
+ if (demangled && !demangled.IsEmpty())
+ tokens.Parse(demangled.AsCString());
+
+ return tokens.Size();
+}
+
+//----------------------------------------------------------------------
+// Dump a Mangled object to stream "s". We don't force our
+// demangled name to be computed currently (we don't use the accessor).
+//----------------------------------------------------------------------
+void
+Mangled::Dump (Stream *s) const
+{
+ if (m_mangled)
+ {
+ *s << ", mangled = " << m_mangled;
+ }
+ if (m_demangled)
+ {
+ const char * demangled = m_demangled.AsCString();
+ s->Printf(", demangled = %s", demangled[0] ? demangled : "<error>");
+ }
+}
+
+//----------------------------------------------------------------------
+// Dumps a debug version of this string with extra object and state
+// information to stream "s".
+//----------------------------------------------------------------------
+void
+Mangled::DumpDebug (Stream *s) const
+{
+ s->Printf("%*p: Mangled mangled = ", (int)sizeof(void*) * 2, this);
+ m_mangled.DumpDebug(s);
+ s->Printf(", demangled = ");
+ m_demangled.DumpDebug(s);
+}
+
+//----------------------------------------------------------------------
+// Return the size in byte that this object takes in memory. The size
+// includes the size of the objects it owns, and not the strings that
+// it references because they are shared strings.
+//----------------------------------------------------------------------
+size_t
+Mangled::MemorySize () const
+{
+ return m_mangled.MemorySize() + m_demangled.MemorySize();
+}
+
+//----------------------------------------------------------------------
+// Dump OBJ to the supplied stream S.
+//----------------------------------------------------------------------
+Stream&
+operator << (Stream& s, const Mangled& obj)
+{
+ if (obj.GetMangledName())
+ s << "mangled = '" << obj.GetMangledName() << "'";
+
+ const ConstString& demangled = obj.GetDemangledName();
+ if (demangled)
+ s << ", demangled = '" << demangled << '\'';
+ else
+ s << ", demangled = <error>";
+ return s;
+}
+
+
+
+
+#pragma mark Mangled::Token
+
+//--------------------------------------------------------------
+// Default constructor
+//--------------------------------------------------------------
+Mangled::Token::Token () :
+ type(eInvalid),
+ value()
+{
+}
+
+//--------------------------------------------------------------
+// Equal to operator
+//--------------------------------------------------------------
+bool
+Mangled::Token::operator== (const Token& rhs) const
+{
+ return type == rhs.type && value == rhs.value;
+}
+
+//--------------------------------------------------------------
+// Dump the token to a stream "s"
+//--------------------------------------------------------------
+void
+Mangled::Token::Dump (Stream *s) const
+{
+ switch (type)
+ {
+ case eInvalid: s->PutCString("invalid "); break;
+ case eNameSpace: s->PutCString("namespace "); break;
+ case eMethodName: s->PutCString("method "); break;
+ case eType: s->PutCString("type "); break;
+ case eTemplate: s->PutCString("template "); break;
+ case eTemplateBeg: s->PutCString("template < "); break;
+ case eTemplateEnd: s->PutCString("template > "); break;
+ case eParamsBeg: s->PutCString("params ( "); break;
+ case eParamsEnd: s->PutCString("params ) "); break;
+ case eQualifier: s->PutCString("qualifier "); break;
+ case eError: s->PutCString("ERROR "); break;
+ default:
+ s->Printf("type = %i", type);
+ break;
+ }
+ value.DumpDebug(s);
+}
+
+//--------------------------------------------------------------
+// Returns true if this token is a wildcard
+//--------------------------------------------------------------
+bool
+Mangled::Token::IsWildcard () const
+{
+ static ConstString g_wildcard_str("*");
+ return value == g_wildcard_str;
+}
+
+
+//----------------------------------------------------------------------
+// Dump "obj" to the supplied stream "s"
+//----------------------------------------------------------------------
+Stream&
+lldb_private::operator << (Stream& s, const Mangled::Token& obj)
+{
+ obj.Dump(&s);
+ return s;
+}
+
+
+#pragma mark Mangled::TokenList
+//----------------------------------------------------------------------
+// Mangled::TokenList
+//----------------------------------------------------------------------
+
+//--------------------------------------------------------------
+// Default constructor. If demangled is non-NULL and not-empty
+// the token list will parse up the demangled string it is
+// given, else the object will initialize an empty token list.
+//--------------------------------------------------------------
+Mangled::TokenList::TokenList (const char *demangled) :
+ m_tokens()
+{
+ if (demangled && demangled[0])
+ {
+ Parse(demangled);
+ }
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+Mangled::TokenList::~TokenList ()
+{
+}
+
+//----------------------------------------------------------------------
+// Parses "demangled" into tokens. This allows complex
+// comparisons to be done. Comparisons can include wildcards at
+// the namespace, method name, template, and template and
+// parameter type levels.
+//
+// Example queries include:
+// "std::basic_string<*>" // Find all std::basic_string variants
+// "std::basic_string<*>::erase(*)" // Find all std::basic_string::erase variants with any number of parameters
+// "*::clear()" // Find all functions with a method name of
+// // "clear" that are in any namespace that
+// // have no parameters
+// "::printf" // Find the printf function in the global namespace
+// "printf" // Ditto
+// "foo::*(int)" // Find all functions in the class or namespace "foo" that take a single integer argument
+//
+// Returns the number of tokens that were decoded, or zero when
+// we fail.
+//----------------------------------------------------------------------
+size_t
+Mangled::TokenList::Parse (const char *s)
+{
+ m_tokens.clear();
+
+ Token token;
+ token.type = eNameSpace;
+
+ TokenType max_type = eInvalid;
+ const char *p = s;
+ size_t span = 0;
+ size_t sep_size = 0;
+
+ while (*p != '\0')
+ {
+ p = p + span + sep_size;
+ while (isspace(*p))
+ ++p;
+
+ if (*p == '\0')
+ break;
+
+ span = strcspn(p, ":<>(),");
+ sep_size = 1;
+ token.type = eInvalid;
+ switch (p[span])
+ {
+ case '\0':
+ break;
+
+ case ':':
+ if (p[span+1] == ':')
+ {
+ sep_size = 2;
+ if (span > 0)
+ {
+ token.type = eNameSpace;
+ token.value.SetCStringWithLength (p, span);
+ m_tokens.push_back(token);
+ }
+ else
+ continue;
+ }
+ break;
+
+ case '(':
+ if (span > 0)
+ {
+ token.type = eMethodName;
+ token.value.SetCStringWithLength (p, span);
+ m_tokens.push_back(token);
+ }
+
+ token.type = eParamsBeg;
+ token.value.Clear();
+ m_tokens.push_back(token);
+ break;
+
+ case ',':
+ if (span > 0)
+ {
+ token.type = eType;
+ token.value.SetCStringWithLength (p, span);
+ m_tokens.push_back(token);
+ }
+ else
+ {
+ continue;
+ }
+ break;
+
+ case ')':
+ if (span > 0)
+ {
+ token.type = eType;
+ token.value.SetCStringWithLength (p, span);
+ m_tokens.push_back(token);
+ }
+
+ token.type = eParamsEnd;
+ token.value.Clear();
+ m_tokens.push_back(token);
+ break;
+
+ case '<':
+ if (span > 0)
+ {
+ token.type = eTemplate;
+ token.value.SetCStringWithLength (p, span);
+ m_tokens.push_back(token);
+ }
+
+ token.type = eTemplateBeg;
+ token.value.Clear();
+ m_tokens.push_back(token);
+ break;
+
+ case '>':
+ if (span > 0)
+ {
+ token.type = eType;
+ token.value.SetCStringWithLength (p, span);
+ m_tokens.push_back(token);
+ }
+
+ token.type = eTemplateEnd;
+ token.value.Clear();
+ m_tokens.push_back(token);
+ break;
+ }
+
+ if (max_type < token.type)
+ max_type = token.type;
+
+ if (token.type == eInvalid)
+ {
+ if (max_type >= eParamsEnd)
+ {
+ token.type = eQualifier;
+ token.value.SetCString(p);
+ m_tokens.push_back(token);
+ }
+ else if (max_type >= eParamsBeg)
+ {
+ token.type = eType;
+ token.value.SetCString(p);
+ m_tokens.push_back(token);
+ }
+ else
+ {
+ token.type = eMethodName;
+ token.value.SetCString(p);
+ m_tokens.push_back(token);
+ }
+ break;
+ }
+ }
+ return m_tokens.size();
+}
+
+
+//----------------------------------------------------------------------
+// Clear the token list.
+//----------------------------------------------------------------------
+void
+Mangled::TokenList::Clear ()
+{
+ m_tokens.clear();
+}
+
+//----------------------------------------------------------------------
+// Dump the token list to the stream "s"
+//----------------------------------------------------------------------
+void
+Mangled::TokenList::Dump (Stream *s) const
+{
+ collection::const_iterator pos;
+ collection::const_iterator beg = m_tokens.begin();
+ collection::const_iterator end = m_tokens.end();
+ for (pos = beg; pos != end; ++pos)
+ {
+ s->Indent("token[");
+ *s << (uint32_t)std::distance(beg, pos) << "] = " << *pos << "\n";
+ }
+}
+
+//----------------------------------------------------------------------
+// Find the first token in the list that has "token_type" as its
+// type
+//----------------------------------------------------------------------
+const Mangled::Token *
+Mangled::TokenList::Find (TokenType token_type) const
+{
+ collection::const_iterator pos;
+ collection::const_iterator beg = m_tokens.begin();
+ collection::const_iterator end = m_tokens.end();
+ for (pos = beg; pos != end; ++pos)
+ {
+ if (pos->type == token_type)
+ return &(*pos);
+ }
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// Return the token at index "idx", or NULL if the index is
+// out of range.
+//----------------------------------------------------------------------
+const Mangled::Token *
+Mangled::TokenList::GetTokenAtIndex (uint32_t idx) const
+{
+ if (idx < m_tokens.size())
+ return &m_tokens[idx];
+ return NULL;
+}
+
+
+//----------------------------------------------------------------------
+// Given a token list, see if it matches this object's tokens.
+// "token_list" can contain wild card values to enable powerful
+// matching. Matching the std::string::erase(*) example that was
+// tokenized above we could use a token list such as:
+//
+// token name
+// ----------- ----------------------------------------
+// eNameSpace "std"
+// eTemplate "basic_string"
+// eTemplateBeg
+// eInvalid "*"
+// eTemplateEnd
+// eMethodName "erase"
+// eParamsBeg
+// eInvalid "*"
+// eParamsEnd
+//
+// Returns true if it "token_list" matches this object's tokens,
+// false otherwise.
+//----------------------------------------------------------------------
+bool
+Mangled::TokenList::MatchesQuery (const Mangled::TokenList &match) const
+{
+ size_t match_count = 0;
+ collection::const_iterator pos;
+ collection::const_iterator pos_end = m_tokens.end();
+
+ collection::const_iterator match_pos;
+ collection::const_iterator match_pos_end = match.m_tokens.end();
+ collection::const_iterator match_wildcard_pos = match_pos_end;
+ collection::const_iterator match_next_pos = match_pos_end;
+
+ size_t template_scope_depth = 0;
+
+ for (pos = m_tokens.begin(), match_pos = match.m_tokens.begin();
+ pos != pos_end && match_pos != match_pos_end;
+ ++match_pos)
+ {
+ match_next_pos = match_pos + 1;
+ // Is this a wildcard?
+ if (match_pos->IsWildcard())
+ {
+ if (match_wildcard_pos != match_pos_end)
+ return false; // Can't have two wildcards in effect at once.
+
+ match_wildcard_pos = match_pos;
+ // Are we at the end of the MATCH token list?
+ if (match_next_pos == match_pos_end)
+ {
+ // There is nothing more to match, return if we have any matches so far...
+ return match_count > 0;
+ }
+ }
+
+ if (match_pos->type == eInvalid || match_pos->type == eError)
+ {
+ return false;
+ }
+ else
+ {
+ if (match_pos->type == eTemplateBeg)
+ {
+ ++template_scope_depth;
+ }
+ else if (match_pos->type == eTemplateEnd)
+ {
+ assert(template_scope_depth > 0);
+ --template_scope_depth;
+ }
+
+ // Do we have a wildcard going right now?
+ if (match_wildcard_pos == match_pos_end)
+ {
+ // No wildcard matching right now, just check and see if things match
+ if (*pos == *match_pos)
+ ++match_count;
+ else
+ return false;
+ }
+ else
+ {
+ // We have a wildcard match going
+
+ // For template types we need to make sure to match the template depths...
+ const size_t start_wildcard_template_scope_depth = template_scope_depth;
+ size_t curr_wildcard_template_scope_depth = template_scope_depth;
+ while (pos != pos_end)
+ {
+ if (match_wildcard_pos->type == eNameSpace && pos->type == eParamsBeg)
+ return false;
+
+ if (start_wildcard_template_scope_depth == curr_wildcard_template_scope_depth)
+ {
+ if (*pos == *match_next_pos)
+ {
+ ++match_count;
+ match_pos = match_next_pos;
+ match_wildcard_pos = match_pos_end;
+ break;
+ }
+ }
+ if (pos->type == eTemplateBeg)
+ ++curr_wildcard_template_scope_depth;
+ else if (pos->type == eTemplateEnd)
+ --curr_wildcard_template_scope_depth;
+
+
+ ++pos;
+ }
+ }
+ }
+
+ if (pos != pos_end)
+ ++pos;
+ }
+ if (match_pos != match_pos_end)
+ return false;
+
+ return match_count > 0;
+}
+
+
+//----------------------------------------------------------------------
+// Return the number of tokens in the token collection
+//----------------------------------------------------------------------
+size_t
+Mangled::TokenList::Size () const
+{
+ return m_tokens.size();
+}
+
+
+//----------------------------------------------------------------------
+// Stream out the tokens
+//----------------------------------------------------------------------
+Stream&
+lldb_private::operator << (Stream& s, const Mangled::TokenList& obj)
+{
+ obj.Dump(&s);
+ return s;
+}
OpenPOWER on IntegriCloud