[Lldb-commits] [lldb] [lldb] Support parsing MS demangled names (PR #196509)
via lldb-commits
lldb-commits at lists.llvm.org
Fri May 8 04:04:41 PDT 2026
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 <nerixdev at outlook.de>
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> >& "
More information about the lldb-commits
mailing list