Skip to content

Commit 6b3b5ef

Browse files
committed
[WIP][lldb][Expression] More reliable function call resolution
Implements all the parts of following RFC: https://discourse.llvm.org/t/rfc-lldb-handling-abi-tagged-constructors-destructors-in-expression-evaluator/82816 Main changes: 1. Instead of relying on linkage names to resolve function symbols, encode the exact function DIE and module in the `AsmLabelAttr` 2. Teach the LLDB symbol resolve about (1) 3. Introduce new Clang attribute to allow specifying multiple `asm` labels for ctors/dtors (one for each variant) 4. Attach the new attribute in (3), where the mangled names use the format from (1). To determine which variant a DIE corresponds to we add a new API to the `ItaniumPartialDemangler` (though could be made into a DWARF attribute for quicker determination).
1 parent 9548dbe commit 6b3b5ef

File tree

12 files changed

+260
-25
lines changed

12 files changed

+260
-25
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -784,6 +784,14 @@ def AbiTag : Attr {
784784
let Documentation = [AbiTagsDocs];
785785
}
786786

787+
def StructorMangledNames : Attr {
788+
let Spellings = [Clang<"structor_names">];
789+
let Args = [VariadicStringArgument<"MangledNames">];
790+
let Subjects = SubjectList<[Function], ErrorDiag>;
791+
let Documentation = [StructorMangledNamesDocs];
792+
}
793+
794+
787795
def AddressSpace : TypeAttr {
788796
let Spellings = [Clang<"address_space">];
789797
let Args = [IntArgument<"AddressSpace">];

clang/include/clang/Basic/AttrDocs.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3568,6 +3568,11 @@ manipulating bits of the enumerator when issuing warnings.
35683568
}];
35693569
}
35703570

3571+
def StructorMangledNamesDocs : Documentation {
3572+
let Category = DocCatDecl;
3573+
let Content = [{ TODO }];
3574+
}
3575+
35713576
def AsmLabelDocs : Documentation {
35723577
let Category = DocCatDecl;
35733578
let Content = [{

clang/lib/AST/Mangle.cpp

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,20 @@
99
// Implements generic name mangling support for blocks and Objective-C.
1010
//
1111
//===----------------------------------------------------------------------===//
12-
#include "clang/AST/Attr.h"
12+
#include "clang/AST/Mangle.h"
1313
#include "clang/AST/ASTContext.h"
14+
#include "clang/AST/Attr.h"
1415
#include "clang/AST/Decl.h"
1516
#include "clang/AST/DeclCXX.h"
1617
#include "clang/AST/DeclObjC.h"
1718
#include "clang/AST/DeclTemplate.h"
1819
#include "clang/AST/ExprCXX.h"
19-
#include "clang/AST/Mangle.h"
2020
#include "clang/AST/VTableBuilder.h"
2121
#include "clang/Basic/ABI.h"
2222
#include "clang/Basic/SourceManager.h"
2323
#include "clang/Basic/TargetInfo.h"
2424
#include "llvm/ADT/StringExtras.h"
25+
#include "llvm/ADT/StringSwitch.h"
2526
#include "llvm/IR/DataLayout.h"
2627
#include "llvm/IR/Mangler.h"
2728
#include "llvm/Support/ErrorHandling.h"
@@ -126,7 +127,7 @@ bool MangleContext::shouldMangleDeclName(const NamedDecl *D) {
126127

127128
// Any decl can be declared with __asm("foo") on it, and this takes precedence
128129
// over all other naming in the .o file.
129-
if (D->hasAttr<AsmLabelAttr>())
130+
if (D->hasAttr<AsmLabelAttr>() || D->hasAttr<StructorMangledNamesAttr>())
130131
return true;
131132

132133
// Declarations that don't have identifier names always need to be mangled.
@@ -140,6 +141,64 @@ void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) {
140141
const ASTContext &ASTContext = getASTContext();
141142
const NamedDecl *D = cast<NamedDecl>(GD.getDecl());
142143

144+
if (const StructorMangledNamesAttr *SMA =
145+
D->getAttr<StructorMangledNamesAttr>()) {
146+
CXXConstructorDecl const *Ctor = dyn_cast<CXXConstructorDecl>(D);
147+
CXXDestructorDecl const *Dtor = dyn_cast<CXXDestructorDecl>(D);
148+
assert(Ctor || Dtor);
149+
enum CtorDtor {
150+
None = -1,
151+
Deleting = 0,
152+
Base,
153+
Complete,
154+
Allocating
155+
} CtorDtorVariant = None;
156+
157+
if (Dtor) {
158+
switch (GD.getDtorType()) {
159+
case Dtor_Complete:
160+
CtorDtorVariant = Complete;
161+
break;
162+
case Dtor_Base:
163+
CtorDtorVariant = Base;
164+
break;
165+
case Dtor_Deleting:
166+
case Dtor_Comdat:
167+
llvm_unreachable("");
168+
}
169+
} else if (Ctor) {
170+
switch (GD.getCtorType()) {
171+
case Ctor_Complete:
172+
CtorDtorVariant = Complete;
173+
break;
174+
case Ctor_Base:
175+
CtorDtorVariant = Base;
176+
break;
177+
case Ctor_DefaultClosure:
178+
case Ctor_CopyingClosure:
179+
case Ctor_Comdat:
180+
llvm_unreachable("");
181+
}
182+
}
183+
184+
llvm::DenseMap<CtorDtor, llvm::StringRef> names;
185+
for (auto name : SMA->mangledNames()) {
186+
auto [structor_variant, mangled_name] = name.split(':');
187+
auto variant = llvm::StringSwitch<CtorDtor>(structor_variant)
188+
.Case("0", CtorDtor::Deleting)
189+
.Case("1", CtorDtor::Base)
190+
.Case("2", CtorDtor::Complete)
191+
.Case("3", CtorDtor::Complete)
192+
.Default(CtorDtor::None);
193+
names[variant] = mangled_name;
194+
}
195+
196+
assert(CtorDtorVariant != CtorDtor::None);
197+
198+
Out << names[CtorDtorVariant];
199+
return;
200+
}
201+
143202
// Any decl can be declared with __asm("foo") on it, and this takes precedence
144203
// over all other naming in the .o file.
145204
if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) {

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5539,6 +5539,25 @@ static void handleMSConstexprAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
55395539
D->addAttr(::new (S.Context) MSConstexprAttr(S.Context, AL));
55405540
}
55415541

5542+
static void handleStructorNamesAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
5543+
SmallVector<StringRef, 4> Tags;
5544+
for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) {
5545+
StringRef Tag;
5546+
if (!S.checkStringLiteralArgumentAttr(AL, I, Tag))
5547+
return;
5548+
Tags.push_back(Tag);
5549+
}
5550+
5551+
if (!AL.checkAtLeastNumArgs(S, 1))
5552+
return;
5553+
5554+
// Store tags without duplicates.
5555+
Tags.erase(std::unique(Tags.begin(), Tags.end()), Tags.end());
5556+
5557+
D->addAttr(::new (S.Context) StructorMangledNamesAttr(
5558+
S.Context, AL, Tags.data(), Tags.size()));
5559+
}
5560+
55425561
static void handleAbiTagAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
55435562
SmallVector<StringRef, 4> Tags;
55445563
for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) {
@@ -6983,6 +7002,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
69837002
S.HLSL().handleParamModifierAttr(D, AL);
69847003
break;
69857004

7005+
case ParsedAttr::AT_StructorMangledNames:
7006+
handleStructorNamesAttr(S, D, AL);
7007+
break;
69867008
case ParsedAttr::AT_AbiTag:
69877009
handleAbiTagAttr(S, D, AL);
69887010
break;

lldb/source/Expression/IRExecutionUnit.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
#include "llvm/Support/SourceMgr.h"
1717
#include "llvm/Support/raw_ostream.h"
1818

19+
#include "Plugins/SymbolFile/DWARF/DWARFBaseDIE.h"
20+
#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
1921
#include "lldb/Core/Debugger.h"
2022
#include "lldb/Core/Disassembler.h"
2123
#include "lldb/Core/Module.h"
@@ -37,6 +39,8 @@
3739
#include "lldb/Utility/LLDBLog.h"
3840
#include "lldb/Utility/Log.h"
3941

42+
#include <cstddef>
43+
#include <cstdint>
4044
#include <optional>
4145

4246
using namespace lldb_private;
@@ -781,6 +785,38 @@ IRExecutionUnit::FindInSymbols(const std::vector<ConstString> &names,
781785
function_options.include_inlines = false;
782786

783787
for (const ConstString &name : names) {
788+
auto ref = name.GetStringRef();
789+
if (ref.consume_front("$__lldb_func_")) {
790+
uintptr_t module_ptr;
791+
if (ref.consumeInteger(0, module_ptr))
792+
return LLDB_INVALID_ADDRESS;
793+
794+
auto *mod = (lldb_private::Module *)module_ptr;
795+
auto *sym = mod->GetSymbolFile();
796+
assert(mod && sym);
797+
798+
if (!ref.consume_front(":"))
799+
return LLDB_INVALID_ADDRESS;
800+
801+
lldb::user_id_t die_id;
802+
if (ref.consumeInteger(10, die_id))
803+
return LLDB_INVALID_ADDRESS;
804+
805+
auto *dwarf = llvm::dyn_cast<plugin::dwarf::SymbolFileDWARF>(sym);
806+
if (!dwarf)
807+
return LLDB_INVALID_ADDRESS;
808+
809+
auto die = dwarf->GetDIE(die_id);
810+
Module::LookupInfo lookup_info(
811+
ConstString(die.GetMangledName()),
812+
lldb::FunctionNameType::eFunctionNameTypeAny,
813+
lldb::LanguageType::eLanguageTypeC_plus_plus);
814+
SymbolContextList sc_list;
815+
dwarf->FindFunctions(lookup_info, {}, false, sc_list);
816+
if (auto load_addr = resolver.Resolve(sc_list))
817+
return *load_addr;
818+
}
819+
784820
if (sc.module_sp) {
785821
SymbolContextList sc_list;
786822
sc.module_sp->FindFunctions(name, CompilerDeclContext(),

lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp

Lines changed: 66 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include "clang/AST/Type.h"
4646
#include "llvm/ADT/StringExtras.h"
4747
#include "llvm/Demangle/Demangle.h"
48+
#include "llvm/Support/FormatVariadic.h"
4849

4950
#include <map>
5051
#include <memory>
@@ -1040,6 +1041,62 @@ bool DWARFASTParserClang::ParseObjCMethod(
10401041
return true;
10411042
}
10421043

1044+
static bool IsStructorDIE(DWARFDIE const &die, DWARFDIE const &parent_die) {
1045+
llvm::StringRef name = die.GetName();
1046+
llvm::StringRef parent_name = parent_die.GetName();
1047+
1048+
name.consume_front("~");
1049+
parent_name = parent_name.substr(0, parent_name.find('<'));
1050+
1051+
return name == parent_name;
1052+
}
1053+
1054+
/// Given a DIE with an external definition (and thus no linkage name)
1055+
/// find the definitions by lookup into the DWARF name index.
1056+
/// We check the DW_AT_specification for each DIE in the index with
1057+
/// the same name as the specified 'die' until we find one that references
1058+
/// 'die'. Then return that linkage name. If no such DIE is found in the index,
1059+
/// returns nullptr.
1060+
static std::vector<std::string> FindStructorNames(DWARFDIE die) {
1061+
auto *dwarf = die.GetDWARF();
1062+
assert(dwarf);
1063+
1064+
ConstString func_name(die.GetName());
1065+
assert(func_name);
1066+
1067+
SymbolContextList sc_list;
1068+
Module::LookupInfo lookup_info(func_name,
1069+
FunctionNameType::eFunctionNameTypeMethod |
1070+
FunctionNameType::eFunctionNameTypeFull,
1071+
LanguageType::eLanguageTypeUnknown);
1072+
dwarf->FindFunctions(lookup_info, {}, true, sc_list);
1073+
1074+
std::vector<std::string> structor_names;
1075+
for (auto const &sc : sc_list.SymbolContexts()) {
1076+
if (auto *func = sc.function) {
1077+
auto func_die = dwarf->GetDIE(func->GetID());
1078+
if (!func_die.IsValid())
1079+
continue;
1080+
1081+
auto spec_die =
1082+
func_die.GetAttributeValueAsReferenceDIE(DW_AT_specification);
1083+
if (spec_die.IsValid() && spec_die == die) {
1084+
llvm::ItaniumPartialDemangler D;
1085+
const bool success = !D.partialDemangle(func_die.GetMangledName());
1086+
assert(success);
1087+
const auto maybe_structor_kind = D.getCtorDtorVariant();
1088+
assert(maybe_structor_kind);
1089+
1090+
structor_names.push_back(
1091+
llvm::formatv("{0}:$__lldb_func_{1}:{2}", *maybe_structor_kind,
1092+
func_die.GetModule().get(), die.GetID()));
1093+
}
1094+
}
1095+
}
1096+
1097+
return structor_names;
1098+
}
1099+
10431100
std::pair<bool, TypeSP> DWARFASTParserClang::ParseCXXMethod(
10441101
const DWARFDIE &die, CompilerType clang_type,
10451102
const ParsedDWARFTypeAttributes &attrs, const DWARFDIE &decl_ctx_die,
@@ -1140,11 +1197,15 @@ std::pair<bool, TypeSP> DWARFASTParserClang::ParseCXXMethod(
11401197
const auto accessibility =
11411198
attrs.accessibility == eAccessNone ? eAccessPublic : attrs.accessibility;
11421199

1200+
std::vector<std::string> structor_names;
1201+
if (IsStructorDIE(die, decl_ctx_die))
1202+
structor_names = FindStructorNames(die);
1203+
11431204
clang::CXXMethodDecl *cxx_method_decl = m_ast.AddMethodToCXXRecordType(
11441205
class_opaque_type.GetOpaqueQualType(), attrs.name.GetCString(),
11451206
attrs.mangled_name, clang_type, accessibility, attrs.is_virtual,
11461207
is_static, attrs.is_inline, attrs.is_explicit, is_attr_used,
1147-
attrs.is_artificial);
1208+
attrs.is_artificial, structor_names);
11481209

11491210
if (cxx_method_decl) {
11501211
LinkDeclContextToDIE(cxx_method_decl, die);
@@ -1330,19 +1391,10 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
13301391
lldbassert(function_decl);
13311392

13321393
if (function_decl) {
1333-
// Attach an asm(<mangled_name>) label to the FunctionDecl.
1334-
// This ensures that clang::CodeGen emits function calls
1335-
// using symbols that are mangled according to the DW_AT_linkage_name.
1336-
// If we didn't do this, the external symbols wouldn't exactly
1337-
// match the mangled name LLDB knows about and the IRExecutionUnit
1338-
// would have to fall back to searching object files for
1339-
// approximately matching function names. The motivating
1340-
// example is generating calls to ABI-tagged template functions.
1341-
// This is done separately for member functions in
1342-
// AddMethodToCXXRecordType.
1343-
if (attrs.mangled_name)
1344-
function_decl->addAttr(clang::AsmLabelAttr::CreateImplicit(
1345-
m_ast.getASTContext(), attrs.mangled_name, /*literal=*/false));
1394+
auto ident = llvm::formatv("$__lldb_func_{0}:{1}",
1395+
die.GetModule().get(), die.GetID());
1396+
function_decl->addAttr(clang::AsmLabelAttr::CreateImplicit(
1397+
m_ast.getASTContext(), ident.str(), /*literal=*/false));
13461398

13471399
LinkDeclContextToDIE(function_decl, die);
13481400

lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include "clang/AST/DeclBase.h"
1212
#include "clang/AST/ExprCXX.h"
13+
#include "llvm/ADT/SmallVector.h"
1314
#include "llvm/Support/Casting.h"
1415
#include "llvm/Support/FormatAdapters.h"
1516
#include "llvm/Support/FormatVariadic.h"
@@ -7735,7 +7736,8 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType(
77357736
lldb::opaque_compiler_type_t type, llvm::StringRef name,
77367737
const char *mangled_name, const CompilerType &method_clang_type,
77377738
lldb::AccessType access, bool is_virtual, bool is_static, bool is_inline,
7738-
bool is_explicit, bool is_attr_used, bool is_artificial) {
7739+
bool is_explicit, bool is_attr_used, bool is_artificial,
7740+
std::vector<std::string> const &structor_names) {
77397741
if (!type || !method_clang_type.IsValid() || name.empty())
77407742
return nullptr;
77417743

@@ -7788,6 +7790,11 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType(
77887790
cxx_dtor_decl->setImplicit(is_artificial);
77897791
cxx_dtor_decl->setInlineSpecified(is_inline);
77907792
cxx_dtor_decl->setConstexprKind(ConstexprSpecKind::Unspecified);
7793+
if (!structor_names.empty()) {
7794+
auto names = llvm::to_vector_of<llvm::StringRef>(structor_names);
7795+
cxx_dtor_decl->addAttr(clang::StructorMangledNamesAttr::CreateImplicit(
7796+
getASTContext(), names.data(), names.size()));
7797+
}
77917798
cxx_method_decl = cxx_dtor_decl;
77927799
} else if (decl_name == cxx_record_decl->getDeclName()) {
77937800
cxx_ctor_decl = clang::CXXConstructorDecl::CreateDeserialized(
@@ -7802,6 +7809,12 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType(
78027809
cxx_ctor_decl->setConstexprKind(ConstexprSpecKind::Unspecified);
78037810
cxx_ctor_decl->setNumCtorInitializers(0);
78047811
cxx_ctor_decl->setExplicitSpecifier(explicit_spec);
7812+
if (!structor_names.empty()) {
7813+
auto names = llvm::to_vector_of<llvm::StringRef>(structor_names);
7814+
cxx_ctor_decl->addAttr(clang::StructorMangledNamesAttr::CreateImplicit(
7815+
getASTContext(), names.data(), names.size()));
7816+
}
7817+
78057818
cxx_method_decl = cxx_ctor_decl;
78067819
} else {
78077820
clang::StorageClass SC = is_static ? clang::SC_Static : clang::SC_None;

lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -980,7 +980,8 @@ class TypeSystemClang : public TypeSystem {
980980
lldb::opaque_compiler_type_t type, llvm::StringRef name,
981981
const char *mangled_name, const CompilerType &method_type,
982982
lldb::AccessType access, bool is_virtual, bool is_static, bool is_inline,
983-
bool is_explicit, bool is_attr_used, bool is_artificial);
983+
bool is_explicit, bool is_attr_used, bool is_artificial,
984+
std::vector<std::string> const &structor_names = {});
984985

985986
void AddMethodOverridesForCXXRecordType(lldb::opaque_compiler_type_t type);
986987

0 commit comments

Comments
 (0)