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
7 changes: 7 additions & 0 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -812,6 +812,13 @@ def AbiTag : Attr {
let Documentation = [AbiTagsDocs];
}

def StructorName : Attr {
let Spellings = [Clang<"structor_name">];
let Args = [StringArgument<"Name">];
let Subjects = SubjectList<[Function], ErrorDiag>;
let Documentation = [StructorNameDocs];
}

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 @@ -4067,6 +4067,11 @@ manipulating bits of the enumerator when issuing warnings.
}];
}

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

def AsmLabelDocs : Documentation {
let Category = DocCatDecl;
let Content = [{
Expand Down
16 changes: 15 additions & 1 deletion clang/lib/AST/Mangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,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<StructorNameAttr>())
return true;

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

if (const auto *SNA = D->getAttr<StructorNameAttr>()) {
Out << SNA->getName() << ':';

if (isa<CXXConstructorDecl>(D)) {
Out << 'C';
Out << GD.getCtorType();
} else {
Out << 'D';
Out << GD.getDtorType();
}

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
11 changes: 11 additions & 0 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1730,6 +1730,14 @@ static void handleIFuncAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
D->addAttr(::new (S.Context) IFuncAttr(S.Context, AL, Str));
}

static void handleStructorNameAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
StringRef Str;
if (!S.checkStringLiteralArgumentAttr(AL, 0, Str))
return;

D->addAttr(::new (S.Context) StructorNameAttr(S.Context, AL, Str));
}

static void handleAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
StringRef Str;
if (!S.checkStringLiteralArgumentAttr(AL, 0, Str))
Expand Down Expand Up @@ -7532,6 +7540,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
S.HLSL().handleParamModifierAttr(D, AL);
break;

case ParsedAttr::AT_StructorName:
handleStructorNameAttr(S, D, AL);
break;
case ParsedAttr::AT_AbiTag:
handleAbiTagAttr(S, D, AL);
break;
Expand Down
2 changes: 2 additions & 0 deletions libcxxabi/src/demangle/ItaniumDemangle.h
Original file line number Diff line number Diff line change
Expand Up @@ -1750,6 +1750,8 @@ class CtorDtorName final : public Node {

template<typename Fn> void match(Fn F) const { F(Basename, IsDtor, Variant); }

int getVariant() const { return Variant; }

void printLeft(OutputBuffer &OB) const override {
if (IsDtor)
OB += "~";
Expand Down
186 changes: 186 additions & 0 deletions lldb/source/Expression/IRExecutionUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,23 @@
//
//===----------------------------------------------------------------------===//

#include "clang/Basic/ABI.h"
#include "llvm/Demangle/Demangle.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/ExecutionEngine/ObjectCache.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DiagnosticHandler.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/raw_ostream.h"

#include "Plugins/SymbolFile/DWARF/DWARFBaseDIE.h"
#include "Plugins/SymbolFile/DWARF/DWARFDIE.h"
#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"

#include "lldb/Core/Debugger.h"
#include "lldb/Core/Disassembler.h"
#include "lldb/Core/Module.h"
Expand All @@ -36,8 +43,10 @@
#include "lldb/Utility/LLDBAssert.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
#include "lldb/lldb-defines.h"

#include <optional>
#include <variant>

using namespace lldb_private;

Expand Down Expand Up @@ -769,6 +778,180 @@ class LoadAddressResolver {
lldb::addr_t m_best_internal_load_address = LLDB_INVALID_ADDRESS;
};

using namespace lldb_private::plugin::dwarf;

struct StructorVariant {
std::variant<clang::CXXCtorType, clang::CXXDtorType> m_variant;
};

static llvm::Expected<StructorVariant>
MakeStructorVariant(llvm::StringRef variant_num) {
if (variant_num.consume_front("D")) {
std::underlying_type_t<clang::CXXDtorType> dtor_type;
if (variant_num.consumeInteger(10, dtor_type))
return llvm::createStringError("Invalid ctor variant code.");

return StructorVariant{.m_variant =
static_cast<clang::CXXDtorType>(dtor_type)};
}

if (variant_num.consume_front("C")) {
std::underlying_type_t<clang::CXXCtorType> ctor_type;
if (variant_num.consumeInteger(10, ctor_type))
return llvm::createStringError("Invalid dtor variant code.");

return StructorVariant{.m_variant =
static_cast<clang::CXXCtorType>(ctor_type)};
}

return llvm::createStringError("Incorrect structor variant prefix.");
}

static int GetItaniumVariantCode(StructorVariant structor) {
if (auto const *ctor = std::get_if<clang::CXXCtorType>(&structor.m_variant)) {
switch (*ctor) {
case clang::CXXCtorType::Ctor_Complete:
return 1;
case clang::CXXCtorType::Ctor_Base:
return 2;
default:
llvm_unreachable("Unimplemented");
}
} else {
switch (std::get<clang::CXXDtorType>(structor.m_variant)) {
case clang::CXXDtorType::Dtor_Complete:
return 1;
case clang::CXXDtorType::Dtor_Base:
return 2;
default:
llvm_unreachable("Unimplemented");
}
}
}

// TODO:
// 1. MS-ABI
// 2. GCC-style dtor/ctor declarations
// 3. Inheriting ctors
// 4. Regular functions
static std::string FindStructorLinkageName(DWARFDIE die,
StructorVariant structor_variant) {
auto *dwarf = die.GetDWARF();
assert(dwarf);

// Note, GCC only puts DW_AT_linkage_name (not DW_AT_name) on constructor
// decls Will those cases still work?
ConstString func_name(die.GetName());
assert(func_name);

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

llvm::DenseMap<int, std::string> variants;

for (auto const &sc : sc_list.SymbolContexts()) {
if (!sc.function)
continue;

auto func_die = dwarf->GetDIE(sc.function->GetID());
if (!func_die.IsValid())
continue;

auto spec_die = func_die.GetAttributeValueAsReferenceDIE(
llvm::dwarf::DW_AT_specification);
if (!spec_die.IsValid() || spec_die != die)
continue;

llvm::ItaniumPartialDemangler D;
if (D.partialDemangle(func_die.GetMangledName()))
continue;

const auto maybe_structor_kind = D.getCtorDtorVariant();
// TODO: this need not be true
assert(maybe_structor_kind);

variants.insert({*maybe_structor_kind, func_die.GetMangledName()});
}

auto itanium_code = GetItaniumVariantCode(structor_variant);
auto it = variants.find(itanium_code);
if (it != variants.end())
return it->second;

// If only C2 was emitted but we tried calling C1,
// we can probably (?) safely call C2.
if (itanium_code == 1 && variants.size() == 1)
if (auto retry = variants.find(2); retry != variants.end())
return retry->second;

return {};
}

static lldb::addr_t FindSpecialLinkageName(
LoadAddressResolver &resolver,ConstString name, llvm::StringRef symbol) {
uintptr_t module_ptr;
if (symbol.consumeInteger(0, module_ptr))
return LLDB_INVALID_ADDRESS;

if (module_ptr == 0) {
// TODO: log this case. We should ever be putting a null module pointer
// here
return LLDB_INVALID_ADDRESS;
}

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

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

lldb::user_id_t die_id;
if (symbol.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);
if (!die.IsValid())
return LLDB_INVALID_ADDRESS;

// TODO: account for MS-ABI (where there are no ctor variants in the
// mangling)
if (!symbol.consume_front(":"))
return LLDB_INVALID_ADDRESS;

auto structor_variant_or_err = MakeStructorVariant(symbol);
if (!structor_variant_or_err) {
LLDB_LOG_ERROR(GetLog(LLDBLog::Expressions),
structor_variant_or_err.takeError(),
"Failed to parse structor variant encoding for {1}: {0}",
name.GetStringRef());
return LLDB_INVALID_ADDRESS;
}

ConstString mangled(
FindStructorLinkageName(die, *structor_variant_or_err));

Module::LookupInfo lookup_info(
mangled, 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;

return LLDB_INVALID_ADDRESS;
}

lldb::addr_t
IRExecutionUnit::FindInSymbols(const std::vector<ConstString> &names,
const lldb_private::SymbolContext &sc,
Expand All @@ -795,6 +978,9 @@ IRExecutionUnit::FindInSymbols(const std::vector<ConstString> &names,
function_options.include_inlines = false;

for (const ConstString &name : names) {
if (auto ref = name.GetStringRef(); ref.consume_front("$__lldb_func_"))
return FindSpecialLinkageName(resolver, name, ref);

// The lookup order here is as follows:
// 1) Functions in `sc.module_sp`
// 2) Functions in the preferred modules list
Expand Down
29 changes: 25 additions & 4 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1112,6 +1112,16 @@ 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;
}

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

// TODO: we should also include mangled name in identifier for
// better diagnostics and easier debugging when reading the
// expression evaluator IR.
std::string mangled_name;
if (IsStructorDIE(die, decl_ctx_die))
mangled_name = llvm::formatv("$__lldb_func_{0}:{1}", die.GetModule().get(),
die.GetID())
.str();

char const *mangled =
mangled_name.empty() ? attrs.mangled_name : mangled_name.c_str();

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);
class_opaque_type.GetOpaqueQualType(), attrs.name.GetCString(), mangled,
clang_type, accessibility, attrs.is_virtual, is_static, attrs.is_inline,
attrs.is_explicit, is_attr_used, attrs.is_artificial);

if (cxx_method_decl) {
LinkDeclContextToDIE(cxx_method_decl, die);
Expand Down
12 changes: 10 additions & 2 deletions lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7822,6 +7822,7 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType(
nullptr /*expr*/, is_explicit ? clang::ExplicitSpecKind::ResolvedTrue
: clang::ExplicitSpecKind::ResolvedFalse);

bool is_ctor_or_dtor = false;
if (name.starts_with("~")) {
cxx_dtor_decl = clang::CXXDestructorDecl::CreateDeserialized(
getASTContext(), GlobalDeclID());
Expand All @@ -7834,6 +7835,7 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType(
cxx_dtor_decl->setInlineSpecified(is_inline);
cxx_dtor_decl->setConstexprKind(ConstexprSpecKind::Unspecified);
cxx_method_decl = cxx_dtor_decl;
is_ctor_or_dtor = true;
} else if (decl_name == cxx_record_decl->getDeclName()) {
cxx_ctor_decl = clang::CXXConstructorDecl::CreateDeserialized(
getASTContext(), GlobalDeclID(), 0);
Expand All @@ -7848,6 +7850,7 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType(
cxx_ctor_decl->setNumCtorInitializers(0);
cxx_ctor_decl->setExplicitSpecifier(explicit_spec);
cxx_method_decl = cxx_ctor_decl;
is_ctor_or_dtor = true;
} else {
clang::StorageClass SC = is_static ? clang::SC_Static : clang::SC_None;
clang::OverloadedOperatorKind op_kind = clang::NUM_OVERLOADED_OPERATORS;
Expand Down Expand Up @@ -7912,8 +7915,13 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType(
cxx_method_decl->addAttr(clang::UsedAttr::CreateImplicit(getASTContext()));

if (mangled_name != nullptr) {
cxx_method_decl->addAttr(clang::AsmLabelAttr::CreateImplicit(
getASTContext(), mangled_name, /*literal=*/false));
if (is_ctor_or_dtor) {
cxx_method_decl->addAttr(clang::StructorNameAttr::CreateImplicit(
getASTContext(), mangled_name));
} else {
cxx_method_decl->addAttr(clang::AsmLabelAttr::CreateImplicit(
getASTContext(), mangled_name, /*literal=*/false));
}
}

// Parameters on member function declarations in DWARF generally don't
Expand Down
Loading
Loading