https://github.com/Nerixyz created https://github.com/llvm/llvm-project/pull/196509
`CPlusPlusLanguage::GetDemangledFunctionNameWithoutArguments` didn't support demangled names from the Microsoft ABI. For one, the mangled name was ignored (only Itanium was supported). Secondly, `CPlusPlusNameParser` didn't account for `class`/`struct` being in type names. This needs more tests, and maybe it should be split into two PRs. >From a6cb684f22e14de1c3087f08f31d11baa0e455af Mon Sep 17 00:00:00 2001 From: Nerixyz <[email protected]> Date: Fri, 8 May 2026 13:00:26 +0200 Subject: [PATCH] [lldb] Support parsing MS demangled names --- .../Language/CPlusPlus/CPlusPlusLanguage.cpp | 68 ++++++++++++++----- .../CPlusPlus/CPlusPlusNameParser.cpp | 14 ++++ .../CPlusPlus/CPlusPlusLanguageTest.cpp | 4 ++ 3 files changed, 68 insertions(+), 18 deletions(-) diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp index 7e68d25c0110f..20fc95ad2f123 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -111,28 +111,60 @@ bool CPlusPlusLanguage::SymbolNameFitsToLanguage(const Mangled &mangled) const { mangling_scheme == Mangled::eManglingSchemeMSVC; } +static bool IsPossibleMangledFunction(llvm::StringRef name) { + // Itanium + if (name.starts_with("_Z")) { + return name.size() >= 3 && + name[2] != 'T' && // avoid virtual table, VTT structure, + // typeinfo structure, and typeinfo + // mangled_name + name[2] != 'G' && // avoid guard variables + name[2] != 'Z'; // named local entities (if we + // eventually handle eSymbolTypeData, + // we will want this back) + } + // Microsoft + if (name.starts_with('?')) { + // Avoid any special intrinsics. This matches consumeSpecialIntrinsicKind() + // from MicrosoftDemangle. + if (name.size() < 4 || name[1] != '?' || name[2] != '_') + return true; + + switch (name[3]) { + case '7': // vftable + case '8': // vbtable + case '9': // vcall thunk + case 'A': // typeof + case 'B': // local static guard + case 'C': // string literal symbol + case 'P': // udt returning + case 'R': // rtti + case 'S': // local vftable + return false; + case '_': + return name.size() < 5 || name[4] != 'E' || // dynamic initializer + name[4] != 'F' || // dynamic atexit destructor + name[4] != 'J'; // local static thread guard + } + return true; + } + + return false; +} + ConstString CPlusPlusLanguage::GetDemangledFunctionNameWithoutArguments( Mangled mangled) const { const char *mangled_name_cstr = mangled.GetMangledName().GetCString(); ConstString demangled_name = mangled.GetDemangledName(); - if (demangled_name && mangled_name_cstr && mangled_name_cstr[0]) { - if (mangled_name_cstr[0] == '_' && mangled_name_cstr[1] == 'Z' && - (mangled_name_cstr[2] != 'T' && // avoid virtual table, VTT structure, - // typeinfo structure, and typeinfo - // mangled_name - mangled_name_cstr[2] != 'G' && // avoid guard variables - mangled_name_cstr[2] != 'Z')) // named local entities (if we - // eventually handle eSymbolTypeData, - // we will want this back) - { - CxxMethodName cxx_method(demangled_name); - if (!cxx_method.GetBasename().empty()) { - std::string shortname; - if (!cxx_method.GetContext().empty()) - shortname = cxx_method.GetContext().str() + "::"; - shortname += cxx_method.GetBasename().str(); - return ConstString(shortname); - } + if (demangled_name && mangled_name_cstr && + IsPossibleMangledFunction(mangled_name_cstr)) { + CxxMethodName cxx_method(demangled_name); + if (!cxx_method.GetBasename().empty()) { + std::string shortname; + if (!cxx_method.GetContext().empty()) + shortname = cxx_method.GetContext().str() + "::"; + shortname += cxx_method.GetBasename().str(); + return ConstString(shortname); } } if (demangled_name) diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp index 4d283bb02e533..0d2e19013b64a 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp @@ -700,6 +700,20 @@ CPlusPlusNameParser::ParseFullNameImpl() { continue_parsing = false; } break; + case tok::kw_class: + case tok::kw_struct: // MS ABI: class Foo::Bar + if (state != State::Beginning) { + continue_parsing = false; + break; + } + Advance(); + if (ConsumeToken(tok::raw_identifier)) { + state = State::AfterIdentifier; + } else { + TakeBack(); + continue_parsing = false; + } + break; default: continue_parsing = false; break; diff --git a/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp b/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp index 41df35f67a790..3ed79a024a18e 100644 --- a/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp +++ b/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp @@ -34,6 +34,10 @@ TEST(CPlusPlusLanguage, MethodNameParsing) { "foo::bar"}, {"int foo::bar::func01(int a, double b)", "int", "foo::bar", "func01", "(int a, double b)", "", "foo::bar::func01"}, + {"class std::_Func_base<bool, int> * std::_Func_class<bool, " + "int>::_Getimpl(void) const", + "class std::_Func_base<bool, int> *", "std::_Func_class<bool, int>", + "_Getimpl", "(void)", "const", "std::_Func_class<bool, int>::_Getimpl"}, // Operators {"std::basic_ostream<char, std::char_traits<char> >& " _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
