CPlusPlusLanguage: Use new demangler API to implement type substitution

Summary:
Now that llvm demangler supports more generic customization, we can
implement type substitution directly on top of this API. This will allow
us to remove the specialized hooks which were added to the demangler to
support this use case.

Reviewers: sgraenitz, erik.pilkington, JDevlieghere

Subscribers: lldb-commits

Differential Revision: https://reviews.llvm.org/D54074

llvm-svn: 346233
This commit is contained in:
Pavel Labath 2018-11-06 15:41:37 +00:00
parent be985e33f0
commit e0d2733bf6
2 changed files with 85 additions and 66 deletions

View File

@ -21,7 +21,7 @@
// Other libraries and framework includes // Other libraries and framework includes
#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringRef.h"
#include "llvm/Demangle/Demangle.h" #include "llvm/Demangle/ItaniumDemangle.h"
// Project includes // Project includes
#include "lldb/Core/PluginManager.h" #include "lldb/Core/PluginManager.h"
@ -279,72 +279,89 @@ bool CPlusPlusLanguage::ExtractContextAndIdentifier(
return false; return false;
} }
/// Given a mangled function `mangled`, replace all the primitive function type namespace {
/// arguments of `search` with type `replace`. class NodeAllocator {
static ConstString SubsPrimitiveParmItanium(llvm::StringRef mangled, llvm::BumpPtrAllocator Alloc;
llvm::StringRef search,
llvm::StringRef replace) {
class PrimitiveParmSubs {
llvm::StringRef mangled;
llvm::StringRef search;
llvm::StringRef replace;
ptrdiff_t read_pos;
std::string output;
std::back_insert_iterator<std::string> writer;
public: public:
PrimitiveParmSubs(llvm::StringRef m, llvm::StringRef s, llvm::StringRef r) void reset() { Alloc.Reset(); }
: mangled(m), search(s), replace(r), read_pos(0),
writer(std::back_inserter(output)) {}
void Substitute(llvm::StringRef tail) { template <typename T, typename... Args> T *makeNode(Args &&... args) {
assert(tail.data() >= mangled.data() && return new (Alloc.Allocate(sizeof(T), alignof(T)))
tail.data() < mangled.data() + mangled.size() && T(std::forward<Args>(args)...);
"tail must point into range of mangled");
if (tail.startswith(search)) {
auto reader = mangled.begin() + read_pos;
ptrdiff_t read_len = tail.data() - (mangled.data() + read_pos);
// First write the unmatched part of the original. Then write the
// replacement string. Finally skip the search string in the original.
writer = std::copy(reader, reader + read_len, writer);
writer = std::copy(replace.begin(), replace.end(), writer);
read_pos += read_len + search.size();
}
}
ConstString Finalize() {
// If we did a substitution, write the remaining part of the original.
if (read_pos > 0) {
writer = std::copy(mangled.begin() + read_pos, mangled.end(), writer);
read_pos = mangled.size();
}
return ConstString(output);
}
static void Callback(void *context, const char *match) {
((PrimitiveParmSubs *)context)->Substitute(llvm::StringRef(match));
}
};
// The demangler will call back for each instance of a primitive type,
// allowing us to perform substitution
PrimitiveParmSubs parmSubs(mangled, search, replace);
assert(mangled.data()[mangled.size()] == '\0' && "Expect C-String");
bool err = llvm::itaniumFindTypesInMangledName(mangled.data(), &parmSubs,
PrimitiveParmSubs::Callback);
ConstString result = parmSubs.Finalize();
if (Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)) {
if (err)
LLDB_LOG(log, "Failed to substitute mangling in {0}", mangled);
else if (result)
LLDB_LOG(log, "Substituted mangling {0} -> {1}", mangled, result);
} }
return result; void *allocateNodeArray(size_t sz) {
return Alloc.Allocate(sizeof(llvm::itanium_demangle::Node *) * sz,
alignof(llvm::itanium_demangle::Node *));
}
};
/// Given a mangled function `Mangled`, replace all the primitive function type
/// arguments of `Search` with type `Replace`.
class TypeSubstitutor
: public llvm::itanium_demangle::AbstractManglingParser<TypeSubstitutor,
NodeAllocator> {
/// Input character until which we have constructed the respective output
/// already
const char *Written;
llvm::StringRef Search;
llvm::StringRef Replace;
llvm::SmallString<128> Result;
/// Whether we have performed any substitutions.
bool Substituted;
void reset(llvm::StringRef Mangled, llvm::StringRef Search,
llvm::StringRef Replace) {
AbstractManglingParser::reset(Mangled.begin(), Mangled.end());
Written = Mangled.begin();
this->Search = Search;
this->Replace = Replace;
Result.clear();
Substituted = false;
}
void appendUnchangedInput() {
Result += llvm::StringRef(Written, First - Written);
Written = First;
}
public:
TypeSubstitutor() : AbstractManglingParser(nullptr, nullptr) {}
ConstString substitute(llvm::StringRef Mangled, llvm::StringRef From,
llvm::StringRef To) {
Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE);
reset(Mangled, From, To);
if (parse() == nullptr) {
LLDB_LOG(log, "Failed to substitute mangling in {0}", Mangled);
return ConstString();
}
if (!Substituted)
return ConstString();
// Append any trailing unmodified input.
appendUnchangedInput();
LLDB_LOG(log, "Substituted mangling {0} -> {1}", Mangled, Result);
return ConstString(Result);
}
llvm::itanium_demangle::Node *parseType() {
if (llvm::StringRef(First, numLeft()).startswith(Search)) {
// We found a match. Append unmodified input up to this point.
appendUnchangedInput();
// And then perform the replacement.
Result += Replace;
Written += Search.size();
Substituted = true;
}
return AbstractManglingParser::parseType();
}
};
} }
uint32_t CPlusPlusLanguage::FindAlternateFunctionManglings( uint32_t CPlusPlusLanguage::FindAlternateFunctionManglings(
@ -373,23 +390,24 @@ uint32_t CPlusPlusLanguage::FindAlternateFunctionManglings(
alternates.insert(ConstString(fixed_scratch)); alternates.insert(ConstString(fixed_scratch));
} }
TypeSubstitutor TS;
// `char` is implementation defined as either `signed` or `unsigned`. As a // `char` is implementation defined as either `signed` or `unsigned`. As a
// result a char parameter has 3 possible manglings: 'c'-char, 'a'-signed // 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 // char, 'h'-unsigned char. If we're looking for symbols with a signed char
// parameter, try finding matches which have the general case 'c'. // parameter, try finding matches which have the general case 'c'.
if (ConstString char_fixup = if (ConstString char_fixup =
SubsPrimitiveParmItanium(mangled_name.GetStringRef(), "a", "c")) TS.substitute(mangled_name.GetStringRef(), "a", "c"))
alternates.insert(char_fixup); alternates.insert(char_fixup);
// long long parameter mangling 'x', may actually just be a long 'l' argument // long long parameter mangling 'x', may actually just be a long 'l' argument
if (ConstString long_fixup = if (ConstString long_fixup =
SubsPrimitiveParmItanium(mangled_name.GetStringRef(), "x", "l")) TS.substitute(mangled_name.GetStringRef(), "x", "l"))
alternates.insert(long_fixup); alternates.insert(long_fixup);
// unsigned long long parameter mangling 'y', may actually just be unsigned // unsigned long long parameter mangling 'y', may actually just be unsigned
// long 'm' argument // long 'm' argument
if (ConstString ulong_fixup = if (ConstString ulong_fixup =
SubsPrimitiveParmItanium(mangled_name.GetStringRef(), "y", "m")) TS.substitute(mangled_name.GetStringRef(), "y", "m"))
alternates.insert(ulong_fixup); alternates.insert(ulong_fixup);
return alternates.size() - start_size; return alternates.size() - start_size;

View File

@ -191,4 +191,5 @@ TEST(CPlusPlusLanguage, FindAlternateFunctionManglings) {
EXPECT_THAT(FindAlternate("_ZN1A1fEx"), Contains("_ZN1A1fEl")); EXPECT_THAT(FindAlternate("_ZN1A1fEx"), Contains("_ZN1A1fEl"));
EXPECT_THAT(FindAlternate("_ZN1A1fEy"), Contains("_ZN1A1fEm")); EXPECT_THAT(FindAlternate("_ZN1A1fEy"), Contains("_ZN1A1fEm"));
EXPECT_THAT(FindAlternate("_ZN1A1fEai"), Contains("_ZN1A1fEci")); EXPECT_THAT(FindAlternate("_ZN1A1fEai"), Contains("_ZN1A1fEci"));
EXPECT_THAT(FindAlternate("_bogus"), IsEmpty());
} }