#include <stdlib.h>
#include <string.h>
+#include <functional>
+
+#include "lldb/Core/FastDemangle.h"
#include "lldb/lldb-private.h"
//#define DEBUG_FAILURES 1
/// @param storage_size Number of bytes of space available scratch memory
/// referenced by storage_ptr
- SymbolDemangler(void *storage_ptr, int storage_size) {
+ SymbolDemangler(void *storage_ptr, size_t storage_size,
+ std::function<void(const char *)> builtins_hook = nullptr)
+ : m_builtins_hook(builtins_hook) {
// Use up to 1/8th of the provided space for rewrite ranges
m_rewrite_ranges_size = (storage_size >> 3) / sizeof(BufferRange);
m_rewrite_ranges = (BufferRange *)storage_ptr;
// ::= u <source-name> # vendor extended type
const char *TryParseBuiltinType() {
+ if (m_builtins_hook)
+ m_builtins_hook(m_read_ptr);
+
switch (*m_read_ptr++) {
case 'v':
return "void";
return RewriteTemplateArg(count + 1);
}
+ // <vector-type>
+ // Dv <dimension number> _ <vector type>
+ bool TryParseVectorType() {
+ const int dimension = TryParseNumber();
+ if (dimension == -1)
+ return false;
+
+ if (*m_read_ptr++ != '_')
+ return false;
+
+ char vec_dimens[32] = {'\0'};
+ ::snprintf(vec_dimens, sizeof vec_dimens - 1, " __vector(%d)", dimension);
+ ParseType();
+ Write(vec_dimens);
+ return true;
+ }
+
// <type> ::= <builtin-type>
// ::= <function-type>
// ::= <class-enum-type>
if (!ParseType())
return false;
break;
+ case 'v':
+ if (!TryParseVectorType())
+ return false;
+ break;
case 'T':
case 't':
- case 'v':
default:
#ifdef DEBUG_FAILURES
printf("*** Unsupported type: %.3s\n", failed_type);
char *m_write_ptr;
int m_next_template_arg_index;
int m_next_substitute_index;
+ std::function<void(const char *s)> m_builtins_hook;
};
} // Anonymous namespace
return demangler.GetDemangledCopy(mangled_name);
}
-char *FastDemangle(const char *mangled_name, long mangled_name_length) {
+char *FastDemangle(const char *mangled_name, size_t mangled_name_length,
+ std::function<void(const char *s)> builtins_hook) {
char buffer[16384];
- SymbolDemangler demangler(buffer, sizeof(buffer));
+ SymbolDemangler demangler(buffer, sizeof(buffer), builtins_hook);
return demangler.GetDemangledCopy(mangled_name, mangled_name_length);
}
} // lldb_private namespace
}
}
- // Maybe we're looking for a const symbol but the debug info told us it was
- // const...
- if (!strncmp(name.GetCString(), "_ZN", 3) &&
- strncmp(name.GetCString(), "_ZNK", 4)) {
- std::string fixed_scratch("_ZNK");
- fixed_scratch.append(name.GetCString() + 3);
- CPP_specs.push_back(ConstString(fixed_scratch.c_str()));
- }
-
- // Maybe we're looking for a static symbol but we thought it was global...
- if (!strncmp(name.GetCString(), "_Z", 2) &&
- strncmp(name.GetCString(), "_ZL", 3)) {
- std::string fixed_scratch("_ZL");
- fixed_scratch.append(name.GetCString() + 2);
- CPP_specs.push_back(ConstString(fixed_scratch.c_str()));
- }
+ std::set<ConstString> alternates;
+ CPlusPlusLanguage::FindAlternateFunctionManglings(name, alternates);
+ CPP_specs.insert(CPP_specs.end(), alternates.begin(), alternates.end());
}
}
#include "CPlusPlusLanguage.h"
// C Includes
-// C++ Includes
#include <cctype>
#include <cstring>
+
+// C++ Includes
#include <functional>
+#include <memory>
#include <mutex>
+#include <set>
// Other libraries and framework includes
#include "llvm/ADT/StringRef.h"
// Project includes
#include "lldb/Core/ConstString.h"
+#include "lldb/Core/FastDemangle.h"
+#include "lldb/Core/Log.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/RegularExpression.h"
#include "lldb/Core/UniqueCStringMap.h"
return count;
}
+/// Given a mangled function `mangled`, replace all the primitive function type
+/// arguments of `search` with type `replace`.
+static ConstString SubsPrimitiveParmItanium(llvm::StringRef mangled,
+ llvm::StringRef search,
+ llvm::StringRef replace) {
+ Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
+
+ const size_t max_len =
+ mangled.size() + mangled.count(search) * replace.size() + 1;
+
+ // Make a temporary buffer to fix up the mangled parameter types and copy the
+ // original there
+ std::string output_buf;
+ output_buf.reserve(max_len);
+ output_buf.insert(0, mangled.str());
+ ptrdiff_t replaced_offset = 0;
+
+ auto swap_parms_hook = [&](const char *parsee) {
+ if (!parsee || !*parsee)
+ return;
+
+ // Check whether we've found a substitutee
+ llvm::StringRef s(parsee);
+ if (s.startswith(search)) {
+ // account for the case where a replacement is of a different length to
+ // the original
+ replaced_offset += replace.size() - search.size();
+
+ ptrdiff_t replace_idx = (mangled.size() - s.size()) + replaced_offset;
+ output_buf.erase(replace_idx, search.size());
+ output_buf.insert(replace_idx, replace.str());
+ }
+ };
+
+ // FastDemangle will call our hook for each instance of a primitive type,
+ // allowing us to perform substitution
+ const char *const demangled =
+ FastDemangle(mangled.str().c_str(), mangled.size(), swap_parms_hook);
+
+ if (log)
+ log->Printf("substituted mangling for %s:{%s} %s:{%s}\n",
+ mangled.str().c_str(), demangled, output_buf.c_str(),
+ FastDemangle(output_buf.c_str()));
+
+ return output_buf == mangled ? ConstString() : ConstString(output_buf);
+}
+
+uint32_t CPlusPlusLanguage::FindAlternateFunctionManglings(
+ const ConstString mangled_name, std::set<ConstString> &alternates) {
+ const auto start_size = alternates.size();
+ /// Get a basic set of alternative manglings for the given symbol `name`, by
+ /// making a few basic possible substitutions on basic types, storage duration
+ /// and `const`ness for the given symbol. The output parameter `alternates`
+ /// is filled with a best-guess, non-exhaustive set of different manglings
+ /// for the given name.
+
+ // Maybe we're looking for a const symbol but the debug info told us it was
+ // non-const...
+ if (!strncmp(mangled_name.GetCString(), "_ZN", 3) &&
+ strncmp(mangled_name.GetCString(), "_ZNK", 4)) {
+ std::string fixed_scratch("_ZNK");
+ fixed_scratch.append(mangled_name.GetCString() + 3);
+ alternates.insert(ConstString(fixed_scratch));
+ }
+
+ // Maybe we're looking for a static symbol but we thought it was global...
+ if (!strncmp(mangled_name.GetCString(), "_Z", 2) &&
+ strncmp(mangled_name.GetCString(), "_ZL", 3)) {
+ std::string fixed_scratch("_ZL");
+ fixed_scratch.append(mangled_name.GetCString() + 2);
+ alternates.insert(ConstString(fixed_scratch));
+ }
+
+ // `char` is implementation defined as either `signed` or `unsigned`. As a
+ // result a char parameter has 3 possible manglings: 'c'-char, 'a'-signed
+ // char, 'h'-unsigned char. If we're looking for symbols with a signed char
+ // parameter, try finding matches which have the general case 'c'.
+ if (ConstString char_fixup =
+ SubsPrimitiveParmItanium(mangled_name.GetStringRef(), "a", "c"))
+ alternates.insert(char_fixup);
+
+ // long long parameter mangling 'x', may actually just be a long 'l' argument
+ if (ConstString long_fixup =
+ SubsPrimitiveParmItanium(mangled_name.GetStringRef(), "x", "l"))
+ alternates.insert(long_fixup);
+
+ // unsigned long long parameter mangling 'y', may actually just be unsigned
+ // long 'm' argument
+ if (ConstString ulong_fixup =
+ SubsPrimitiveParmItanium(mangled_name.GetStringRef(), "y", "m"))
+ alternates.insert(ulong_fixup);
+
+ return alternates.size() - start_size;
+}
+
static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
if (!cpp_category_sp)
return;
return candidate;
}
};
-
+
return std::unique_ptr<TypeScavenger>(new CPlusPlusTypeScavenger());
}