Skip to content

[lldb][dwarf] Compute fully qualified names on simplified template names with DWARFTypePrinter #112811

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Nov 18, 2024
Merged
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
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 @@ -44,6 +44,7 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Type.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/DebugInfo/DWARF/DWARFTypePrinter.h"
#include "llvm/Demangle/Demangle.h"

#include <map>
Expand Down Expand Up @@ -825,11 +826,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 @@ -1617,9 +1618,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 @@ -1672,6 +1673,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 @@ -569,6 +569,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 @@ -2821,33 +2822,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;
}
Copy link
Member

Choose a reason for hiding this comment

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

Nice


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
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 -o %t
// RUN: %lldb %t -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 -o %t
// RUN: %lldb %t -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 = {}
Copy link
Member

Choose a reason for hiding this comment

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

Do we need to check the typename that gets displayed here? Is that actually affected by this patch?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, they are not affected by this patch. When I working on this change, I had an oversight on not calling DWARFDIE::resolveTypeUnitReference in https://github.com/llvm/llvm-project/pull/112811/files/3fc0675398547617731d0501e3d4b98e2ffc480e#diff-5e94a4eb2c54c062b27821639b3c2732886de49229c99b11b6b2602f35b0ccdcR788 and existing lldb tests didn't catch it. So, I added this for test coverage.


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;

int main() {}
Loading
Loading