Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -784,6 +784,14 @@ def AbiTag : Attr {
let Documentation = [AbiTagsDocs];
}

def StructorMangledNames : Attr {
let Spellings = [Clang<"structor_names">];
let Args = [VariadicStringArgument<"MangledNames">];
let Subjects = SubjectList<[Function], ErrorDiag>;
let Documentation = [StructorMangledNamesDocs];
}


def AddressSpace : TypeAttr {
let Spellings = [Clang<"address_space">];
let Args = [IntArgument<"AddressSpace">];
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -3568,6 +3568,11 @@ manipulating bits of the enumerator when issuing warnings.
}];
}

def StructorMangledNamesDocs : Documentation {
let Category = DocCatDecl;
let Content = [{ TODO }];
}

def AsmLabelDocs : Documentation {
let Category = DocCatDecl;
let Content = [{
Expand Down
85 changes: 82 additions & 3 deletions clang/lib/AST/Mangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,20 @@
// Implements generic name mangling support for blocks and Objective-C.
//
//===----------------------------------------------------------------------===//
#include "clang/AST/Attr.h"
#include "clang/AST/Mangle.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/Mangle.h"
#include "clang/AST/VTableBuilder.h"
#include "clang/Basic/ABI.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Mangler.h"
#include "llvm/Support/ErrorHandling.h"
Expand Down Expand Up @@ -126,7 +127,7 @@ bool MangleContext::shouldMangleDeclName(const NamedDecl *D) {

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

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

if (const StructorMangledNamesAttr *SMA =
D->getAttr<StructorMangledNamesAttr>()) {
CXXConstructorDecl const *Ctor = dyn_cast<CXXConstructorDecl>(D);
CXXDestructorDecl const *Dtor = dyn_cast<CXXDestructorDecl>(D);
assert(Ctor || Dtor);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally this won't look like this. But shows where I intend the mangler changes to go for the new attribute.

enum CtorDtor {
None = -1,
Deleting = 0,
Base,
Complete,
Allocating
} CtorDtorVariant = None;

// Map ctor/dtor variant to a the variant that LLDB encoded in the
// special identifier. I.e., a number between [0-3].
if (Dtor) {
switch (GD.getDtorType()) {
case Dtor_Complete:
CtorDtorVariant = Complete;
break;
case Dtor_Base:
CtorDtorVariant = Base;
break;
case Dtor_Deleting:
case Dtor_Comdat:
llvm_unreachable("");
}
} else if (Ctor) {
switch (GD.getCtorType()) {
case Ctor_Complete:
CtorDtorVariant = Complete;
break;
case Ctor_Base:
CtorDtorVariant = Base;
break;
case Ctor_DefaultClosure:
case Ctor_CopyingClosure:
case Ctor_Comdat:
llvm_unreachable("");
}
}

// TODO: if only 1 variant is specified (i.e., C1 or C2)
// and we're looking for C1 or C2, pick the single one.
// Will that always do the right thing? What if C1 was
// optimized out because it was actually never called
// in the source. But then we tried to call it in expression
// evaluator? Maybe that's a sacrifice we have to make?
//
// Parse the LLDB [variant -> special name] mappings.
llvm::DenseMap<CtorDtor, llvm::StringRef> names;
for (auto name : SMA->mangledNames()) {
auto [structor_variant, mangled_name] = name.split(':');
auto variant = llvm::StringSwitch<CtorDtor>(structor_variant)
.Case("0", CtorDtor::Deleting)
.Case("1", CtorDtor::Complete)
.Case("2", CtorDtor::Base)
.Default(CtorDtor::None);
names[variant] = mangled_name;
}

assert(CtorDtorVariant != CtorDtor::None);

// If there is no definition for a completing structor variant but
// Clang is calling it lets take call the base variant since the
// definitions should (?) be the same.
if (!names.contains(CtorDtorVariant)
&& names.size() == 1
&& CtorDtorVariant == CtorDtor::Complete) {
CtorDtorVariant = CtorDtor::Base;
assert(names.contains(CtorDtorVariant));
}

// Pick the mapping
Out << names[CtorDtorVariant];
return;
}

// Any decl can be declared with __asm("foo") on it, and this takes precedence
// over all other naming in the .o file.
if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) {
Expand Down
22 changes: 22 additions & 0 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5539,6 +5539,25 @@ static void handleMSConstexprAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
D->addAttr(::new (S.Context) MSConstexprAttr(S.Context, AL));
}

static void handleStructorNamesAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
SmallVector<StringRef, 4> Tags;
for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) {
StringRef Tag;
if (!S.checkStringLiteralArgumentAttr(AL, I, Tag))
return;
Tags.push_back(Tag);
}

if (!AL.checkAtLeastNumArgs(S, 1))
return;

// Store tags without duplicates.
Tags.erase(std::unique(Tags.begin(), Tags.end()), Tags.end());

D->addAttr(::new (S.Context) StructorMangledNamesAttr(
S.Context, AL, Tags.data(), Tags.size()));
}

static void handleAbiTagAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
SmallVector<StringRef, 4> Tags;
for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) {
Expand Down Expand Up @@ -6983,6 +7002,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
S.HLSL().handleParamModifierAttr(D, AL);
break;

case ParsedAttr::AT_StructorMangledNames:
handleStructorNamesAttr(S, D, AL);
break;
case ParsedAttr::AT_AbiTag:
handleAbiTagAttr(S, D, AL);
break;
Expand Down
36 changes: 36 additions & 0 deletions lldb/source/Expression/IRExecutionUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/raw_ostream.h"

#include "Plugins/SymbolFile/DWARF/DWARFBaseDIE.h"
#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Disassembler.h"
#include "lldb/Core/Module.h"
Expand All @@ -37,6 +39,8 @@
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"

#include <cstddef>
#include <cstdint>
#include <optional>

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

for (const ConstString &name : names) {
auto ref = name.GetStringRef();
if (ref.consume_front("$__lldb_func_")) {
uintptr_t module_ptr;
if (ref.consumeInteger(0, module_ptr))
return LLDB_INVALID_ADDRESS;

auto *mod = (lldb_private::Module *)module_ptr;
auto *sym = mod->GetSymbolFile();
assert(mod && sym);

if (!ref.consume_front(":"))
return LLDB_INVALID_ADDRESS;

lldb::user_id_t die_id;
if (ref.consumeInteger(10, die_id))
return LLDB_INVALID_ADDRESS;

auto *dwarf = llvm::dyn_cast<plugin::dwarf::SymbolFileDWARF>(sym);
if (!dwarf)
return LLDB_INVALID_ADDRESS;

auto die = dwarf->GetDIE(die_id);
Module::LookupInfo lookup_info(
ConstString(die.GetMangledName()),
lldb::FunctionNameType::eFunctionNameTypeAny,
lldb::LanguageType::eLanguageTypeC_plus_plus);
SymbolContextList sc_list;
dwarf->FindFunctions(lookup_info, {}, false, sc_list);
if (auto load_addr = resolver.Resolve(sc_list))
return *load_addr;
}

if (sc.module_sp) {
SymbolContextList sc_list;
sc.module_sp->FindFunctions(name, CompilerDeclContext(),
Expand Down
80 changes: 66 additions & 14 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#include "clang/AST/Type.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Demangle/Demangle.h"
#include "llvm/Support/FormatVariadic.h"

#include <map>
#include <memory>
Expand Down Expand Up @@ -1040,6 +1041,62 @@ bool DWARFASTParserClang::ParseObjCMethod(
return true;
}

static bool IsStructorDIE(DWARFDIE const &die, DWARFDIE const &parent_die) {
llvm::StringRef name = die.GetName();
llvm::StringRef parent_name = parent_die.GetName();

name.consume_front("~");
parent_name = parent_name.substr(0, parent_name.find('<'));

return name == parent_name;
}

/// Given a DIE with an external definition (and thus no linkage name)
/// find the definitions by lookup into the DWARF name index.
/// We check the DW_AT_specification for each DIE in the index with
/// the same name as the specified 'die' until we find one that references
/// 'die'. Then return that linkage name. If no such DIE is found in the index,
/// returns nullptr.
static std::vector<std::string> FindStructorNames(DWARFDIE die) {
auto *dwarf = die.GetDWARF();
assert(dwarf);

ConstString func_name(die.GetName());
assert(func_name);

SymbolContextList sc_list;
Module::LookupInfo lookup_info(func_name,
FunctionNameType::eFunctionNameTypeMethod |
FunctionNameType::eFunctionNameTypeFull,
LanguageType::eLanguageTypeUnknown);
dwarf->FindFunctions(lookup_info, {}, true, sc_list);

std::vector<std::string> structor_names;
for (auto const &sc : sc_list.SymbolContexts()) {
if (auto *func = sc.function) {
auto func_die = dwarf->GetDIE(func->GetID());
if (!func_die.IsValid())
continue;

auto spec_die =
func_die.GetAttributeValueAsReferenceDIE(DW_AT_specification);
if (spec_die.IsValid() && spec_die == die) {
llvm::ItaniumPartialDemangler D;
const bool success = !D.partialDemangle(func_die.GetMangledName());
assert(success);
const auto maybe_structor_kind = D.getCtorDtorVariant();
assert(maybe_structor_kind);

structor_names.push_back(
llvm::formatv("{0}:$__lldb_func_{1}:{2}", *maybe_structor_kind,
func_die.GetModule().get(), func_die.GetID()));
}
}
}

return structor_names;
}

std::pair<bool, TypeSP> DWARFASTParserClang::ParseCXXMethod(
const DWARFDIE &die, CompilerType clang_type,
const ParsedDWARFTypeAttributes &attrs, const DWARFDIE &decl_ctx_die,
Expand Down Expand Up @@ -1140,11 +1197,15 @@ std::pair<bool, TypeSP> DWARFASTParserClang::ParseCXXMethod(
const auto accessibility =
attrs.accessibility == eAccessNone ? eAccessPublic : attrs.accessibility;

std::vector<std::string> structor_names;
if (IsStructorDIE(die, decl_ctx_die))
structor_names = FindStructorNames(die);

clang::CXXMethodDecl *cxx_method_decl = m_ast.AddMethodToCXXRecordType(
class_opaque_type.GetOpaqueQualType(), attrs.name.GetCString(),
attrs.mangled_name, clang_type, accessibility, attrs.is_virtual,
is_static, attrs.is_inline, attrs.is_explicit, is_attr_used,
attrs.is_artificial);
attrs.is_artificial, structor_names);

if (cxx_method_decl) {
LinkDeclContextToDIE(cxx_method_decl, die);
Expand Down Expand Up @@ -1330,19 +1391,10 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
lldbassert(function_decl);

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

LinkDeclContextToDIE(function_decl, die);

Expand Down
15 changes: 14 additions & 1 deletion lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#include "clang/AST/DeclBase.h"
#include "clang/AST/ExprCXX.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/FormatAdapters.h"
#include "llvm/Support/FormatVariadic.h"
Expand Down Expand Up @@ -7735,7 +7736,8 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType(
lldb::opaque_compiler_type_t type, llvm::StringRef name,
const char *mangled_name, const CompilerType &method_clang_type,
lldb::AccessType access, bool is_virtual, bool is_static, bool is_inline,
bool is_explicit, bool is_attr_used, bool is_artificial) {
bool is_explicit, bool is_attr_used, bool is_artificial,
std::vector<std::string> const &structor_names) {
if (!type || !method_clang_type.IsValid() || name.empty())
return nullptr;

Expand Down Expand Up @@ -7788,6 +7790,11 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType(
cxx_dtor_decl->setImplicit(is_artificial);
cxx_dtor_decl->setInlineSpecified(is_inline);
cxx_dtor_decl->setConstexprKind(ConstexprSpecKind::Unspecified);
if (!structor_names.empty()) {
auto names = llvm::to_vector_of<llvm::StringRef>(structor_names);
cxx_dtor_decl->addAttr(clang::StructorMangledNamesAttr::CreateImplicit(
getASTContext(), names.data(), names.size()));
}
cxx_method_decl = cxx_dtor_decl;
} else if (decl_name == cxx_record_decl->getDeclName()) {
cxx_ctor_decl = clang::CXXConstructorDecl::CreateDeserialized(
Expand All @@ -7802,6 +7809,12 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType(
cxx_ctor_decl->setConstexprKind(ConstexprSpecKind::Unspecified);
cxx_ctor_decl->setNumCtorInitializers(0);
cxx_ctor_decl->setExplicitSpecifier(explicit_spec);
if (!structor_names.empty()) {
auto names = llvm::to_vector_of<llvm::StringRef>(structor_names);
cxx_ctor_decl->addAttr(clang::StructorMangledNamesAttr::CreateImplicit(
getASTContext(), names.data(), names.size()));
}

cxx_method_decl = cxx_ctor_decl;
} else {
clang::StorageClass SC = is_static ? clang::SC_Static : clang::SC_None;
Expand Down
Loading