Skip to content

Commit

Permalink
[lldb][dwarf] Compute fully qualified names on simplified template n…
Browse files Browse the repository at this point in the history
…ames with DWARFTypePrinter (llvm#117071)

This is a reland of llvm#112811.
Fixed the bot breakage by running ld.lld explicitly.
  • Loading branch information
ZequanWu authored Nov 20, 2024
1 parent 1c8ac4c commit f06c187
Show file tree
Hide file tree
Showing 14 changed files with 309 additions and 70 deletions.
21 changes: 14 additions & 7 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 "clang/Basic/Specifiers.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/DebugInfo/DWARF/DWARFTypePrinter.h"
#include "llvm/Demangle/Demangle.h"

#include <map>
Expand Down Expand Up @@ -826,11 +827,11 @@ std::string DWARFASTParserClang::GetDIEClassTemplateParams(DWARFDIE die) {
if (llvm::StringRef(die.GetName()).contains("<"))
return {};

TypeSystemClang::TemplateParameterInfos template_param_infos;
if (ParseTemplateParameterInfos(die, template_param_infos))
return m_ast.PrintTemplateParams(template_param_infos);

return {};
std::string name;
llvm::raw_string_ostream os(name);
llvm::DWARFTypePrinter<DWARFDIE> type_printer(os);
type_printer.appendAndTerminateTemplateParameters(die);
return name;
}

void DWARFASTParserClang::MapDeclDIEToDefDIE(
Expand Down Expand Up @@ -1618,9 +1619,9 @@ void DWARFASTParserClang::GetUniqueTypeNameAndDeclaration(
case DW_TAG_structure_type:
case DW_TAG_union_type: {
if (const char *class_union_struct_name = parent_decl_ctx_die.GetName()) {
qualified_name.insert(
0, GetDIEClassTemplateParams(parent_decl_ctx_die));
qualified_name.insert(0, "::");
qualified_name.insert(0,
GetDIEClassTemplateParams(parent_decl_ctx_die));
qualified_name.insert(0, class_union_struct_name);
}
parent_decl_ctx_die = parent_decl_ctx_die.GetParentDeclContextDIE();
Expand Down Expand Up @@ -1673,6 +1674,12 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc,
if (attrs.name) {
GetUniqueTypeNameAndDeclaration(die, cu_language, unique_typename,
unique_decl);
if (log) {
dwarf->GetObjectFile()->GetModule()->LogMessage(
log, "SymbolFileDWARF({0:p}) - {1:x16}: {2} has unique name: {3} ",
static_cast<void *>(this), die.GetID(), DW_TAG_value_to_name(tag),
unique_typename.AsCString());
}
if (UniqueDWARFASTType *unique_ast_entry_type =
dwarf->GetUniqueDWARFASTTypeMap().Find(
unique_typename, die, unique_decl, byte_size,
Expand Down
8 changes: 8 additions & 0 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ class DWARFUnit;
class DWARFDebugInfoEntry;
class DWARFDeclContext;
class SymbolFileDWARF;
class DWARFFormValue;

class DWARFBaseDIE {
public:
using DWARFFormValue = dwarf::DWARFFormValue;
DWARFBaseDIE() = default;

DWARFBaseDIE(DWARFUnit *cu, DWARFDebugInfoEntry *die)
Expand Down Expand Up @@ -117,6 +119,12 @@ class DWARFBaseDIE {
enum class Recurse : bool { no, yes };
DWARFAttributes GetAttributes(Recurse recurse = Recurse::yes) const;

// The following methods use LLVM naming convension in order to be are used by
// LLVM libraries.
dw_tag_t getTag() const { return Tag(); }

const char *getShortName() const { return GetName(); }

protected:
DWARFUnit *m_cu = nullptr;
DWARFDebugInfoEntry *m_die = nullptr;
Expand Down
37 changes: 37 additions & 0 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,43 @@ bool DWARFDIE::GetDIENamesAndRanges(
return false;
}

// The following methods use LLVM naming convension in order to be are used by
// LLVM libraries.
llvm::iterator_range<DWARFDIE::child_iterator> DWARFDIE::children() const {
return llvm::make_range(child_iterator(*this), child_iterator());
}

DWARFDIE::child_iterator DWARFDIE::begin() const {
return child_iterator(*this);
}

DWARFDIE::child_iterator DWARFDIE::end() const { return child_iterator(); }

std::optional<DWARFFormValue> DWARFDIE::find(const dw_attr_t attr) const {
DWARFFormValue form_value;
if (m_die->GetAttributeValue(m_cu, attr, form_value, nullptr, false))
return form_value;
return std::nullopt;
}

std::optional<uint64_t> DWARFDIE::getLanguage() const {
if (IsValid())
return m_cu->GetDWARFLanguageType();
return std::nullopt;
}

DWARFDIE DWARFDIE::resolveReferencedType(dw_attr_t attr) const {
return GetReferencedDIE(attr);
}

DWARFDIE DWARFDIE::resolveReferencedType(DWARFFormValue v) const {
if (IsValid())
return v.Reference();
return {};
}

DWARFDIE DWARFDIE::resolveTypeUnitReference() const {
if (DWARFDIE reference = GetReferencedDIE(DW_AT_signature))
return reference;
return *this;
}
17 changes: 17 additions & 0 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,25 @@ class DWARFDIE : public DWARFBaseDIE {
std::optional<int> &call_line, std::optional<int> &call_column,
DWARFExpressionList *frame_base) const;

// The following methods use LLVM naming convension in order to be are used by
// LLVM libraries.
std::optional<uint64_t> getLanguage() const;

DWARFDIE getParent() const { return GetParent(); }

DWARFDIE resolveReferencedType(dw_attr_t attr) const;

DWARFDIE resolveReferencedType(DWARFFormValue v) const;

DWARFDIE resolveTypeUnitReference() const;

std::optional<DWARFFormValue> find(const dw_attr_t attr) const;

/// The range of all the children of this DIE.
llvm::iterator_range<child_iterator> children() const;

child_iterator begin() const;
child_iterator end() const;
};

class DWARFDIE::child_iterator
Expand Down
25 changes: 25 additions & 0 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,31 @@ uint64_t DWARFFormValue::Reference(dw_offset_t base_offset) const {
}
}

std::optional<uint64_t> DWARFFormValue::getAsUnsignedConstant() const {
if ((!IsDataForm(m_form)) || m_form == lldb_private::dwarf::DW_FORM_sdata)
return std::nullopt;
return m_value.uval;
}

std::optional<int64_t> DWARFFormValue::getAsSignedConstant() const {
if ((!IsDataForm(m_form)) ||
(m_form == lldb_private::dwarf::DW_FORM_udata &&
uint64_t(std::numeric_limits<int64_t>::max()) < m_value.uval))
return std::nullopt;
switch (m_form) {
case lldb_private::dwarf::DW_FORM_data4:
return int32_t(m_value.uval);
case lldb_private::dwarf::DW_FORM_data2:
return int16_t(m_value.uval);
case lldb_private::dwarf::DW_FORM_data1:
return int8_t(m_value.uval);
case lldb_private::dwarf::DW_FORM_sdata:
case lldb_private::dwarf::DW_FORM_data8:
default:
return m_value.sval;
}
}

const uint8_t *DWARFFormValue::BlockData() const { return m_value.data; }

bool DWARFFormValue::IsBlockForm(const dw_form_t form) {
Expand Down
6 changes: 6 additions & 0 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,12 @@ class DWARFFormValue {
void Clear();
static bool FormIsSupported(dw_form_t form);

// The following methods use LLVM naming convension in order to be are used by
// LLVM libraries.
std::optional<uint64_t> getAsUnsignedConstant() const;
std::optional<int64_t> getAsSignedConstant() const;
const char *getAsCString() const { return AsCString(); }

protected:
// Compile unit where m_value was located.
// It may be different from compile unit where m_value refers to.
Expand Down
36 changes: 9 additions & 27 deletions lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "SymbolFileDWARF.h"

#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
#include "llvm/DebugInfo/DWARF/DWARFTypePrinter.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/Format.h"
Expand Down Expand Up @@ -2810,33 +2811,14 @@ void SymbolFileDWARF::FindTypes(const TypeQuery &query, TypeResults &results) {
return true; // Keep iterating over index types, language mismatch.
}

// Check the context matches
std::vector<lldb_private::CompilerContext> die_context;
if (query.GetModuleSearch())
die_context = die.GetDeclContext();
else
die_context = die.GetTypeLookupContext();
assert(!die_context.empty());
if (!query_simple.ContextMatches(die_context))
return true; // Keep iterating over index types, context mismatch.

// Try to resolve the type.
if (Type *matching_type = ResolveType(die, true, true)) {
ConstString name = matching_type->GetQualifiedName();
// We have found a type that still might not match due to template
// parameters. If we create a new TypeQuery that uses the new type's
// fully qualified name, we can find out if this type matches at all
// context levels. We can't use just the "match_simple" context
// because all template parameters were stripped off. The fully
// qualified name of the type will have the template parameters and
// will allow us to make sure it matches correctly.
TypeQuery die_query(name.GetStringRef(),
TypeQueryOptions::e_exact_match);
if (!query.ContextMatches(die_query.GetContextRef()))
return true; // Keep iterating over index types, context mismatch.

results.InsertUnique(matching_type->shared_from_this());
}
std::string qualified_name;
llvm::raw_string_ostream os(qualified_name);
llvm::DWARFTypePrinter<DWARFDIE> type_printer(os);
type_printer.appendQualifiedName(die);
TypeQuery die_query(qualified_name, e_exact_match);
if (query.ContextMatches(die_query.GetContextRef()))
if (Type *matching_type = ResolveType(die, true, true))
results.InsertUnique(matching_type->shared_from_this());
return !results.Done(query); // Keep iterating if we aren't done.
});
if (results.Done(query)) {
Expand Down
20 changes: 0 additions & 20 deletions lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1403,26 +1403,6 @@ static TemplateParameterList *CreateTemplateParameterList(
return template_param_list;
}

std::string TypeSystemClang::PrintTemplateParams(
const TemplateParameterInfos &template_param_infos) {
llvm::SmallVector<NamedDecl *, 8> ignore;
clang::TemplateParameterList *template_param_list =
CreateTemplateParameterList(getASTContext(), template_param_infos,
ignore);
llvm::SmallVector<clang::TemplateArgument, 2> args(
template_param_infos.GetArgs());
if (template_param_infos.hasParameterPack()) {
llvm::ArrayRef<TemplateArgument> pack_args =
template_param_infos.GetParameterPackArgs();
args.append(pack_args.begin(), pack_args.end());
}
std::string str;
llvm::raw_string_ostream os(str);
clang::printTemplateArgumentList(os, args, GetTypePrintingPolicy(),
template_param_list);
return str;
}

clang::FunctionTemplateDecl *TypeSystemClang::CreateFunctionTemplateDecl(
clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module,
clang::FunctionDecl *func_decl,
Expand Down
4 changes: 0 additions & 4 deletions lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
Original file line number Diff line number Diff line change
Expand Up @@ -1148,10 +1148,6 @@ class TypeSystemClang : public TypeSystem {

bool SetDeclIsForcefullyCompleted(const clang::TagDecl *td);

/// Return the template parameters (including surrounding <>) in string form.
std::string
PrintTemplateParams(const TemplateParameterInfos &template_param_infos);

private:
/// Returns the PrintingPolicy used when generating the internal type names.
/// These type names are mostly used for the formatter selection.
Expand Down
36 changes: 36 additions & 0 deletions lldb/test/Shell/SymbolFile/DWARF/x86/simplified-template-names.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Test lldb is able to compute the fully qualified names on templates with
// -gsimple-template-names and -fdebug-types-section.

// REQUIRES: lld

// Test against logging to see if we print the fully qualified names correctly.
// RUN: %clangxx --target=x86_64-pc-linux -g -gsimple-template-names %s -c -o %t1.o
// RUN: ld.lld %t1.o -o %t1
// RUN: %lldb %t1 -o "log enable dwarf comp" -o "target variable v3" -o exit | FileCheck %s --check-prefix=LOG

// Test that we following DW_AT_signature correctly. If not, lldb might confuse the types of v1 and v2.
// RUN: %clangxx --target=x86_64-pc-linux -g -gsimple-template-names -fdebug-types-section %s -c -o %t2.o
// RUN: ld.lld %t2.o -o %t2
// RUN: %lldb %t2 -o "target variable v1 v2" -o exit | FileCheck %s --check-prefix=TYPE

// LOG: unique name: t3<t2<int> >::t4

// TYPE: (t2<outer_struct1::t1<int> >) v1 = {}
// TYPE-NEXT: (t2<outer_struct2::t1<int> >) v2 = {}

struct outer_struct1 {
template <typename> struct t1 {};
};

struct outer_struct2 {
template <typename> struct t1 {};
};

template <typename> struct t2 {};
t2<outer_struct1::t1<int>> v1;
t2<outer_struct2::t1<int>> v2;

template <typename> struct t3 {
struct t4 {};
};
t3<t2<int>>::t4 v3;
Loading

0 comments on commit f06c187

Please sign in to comment.