DWARF: Introduce DWARFTypeUnit class

Summary:
This patch introduces the DWARFTypeUnit class, and teaches lldb to parse
type units out of both the debug_types section (DWARF v4), and from the
regular debug_info section (DWARF v5).

The most important piece of functionality - resolving DW_AT_signatures
to connect type forward declarations to their definitions - is not
implemented here, but even without that, a lot of functionality becomes
available. I've added tests for the commands that start to work after
this patch.

The changes in this patch were greatly inspired by D61505, which in turn took
over changes from D32167.

Reviewers: JDevlieghere, clayborg, aprantl

Subscribers: mgorny, jankratochvil, lldb-commits

Differential Revision: https://reviews.llvm.org/D62008

llvm-svn: 361360
This commit is contained in:
Pavel Labath 2019-05-22 09:09:39 +00:00
parent b72b091389
commit 80233daeaa
15 changed files with 224 additions and 48 deletions

View File

@ -0,0 +1,13 @@
struct A {
int i;
long l;
float f;
double d;
};
enum E { e1, e2, e3 };
enum class EC { e1, e2, e3 };
extern constexpr A a{42, 47l, 4.2f, 4.7};
extern constexpr E e(e2);
extern constexpr EC ec(EC::e2);

View File

@ -0,0 +1,25 @@
struct A {
int i = 47;
int f() { return i; }
virtual ~A() = default;
};
struct B: public A {
int j = 42;
};
namespace ns {
struct A {
int i = 147;
A();
};
A::A() = default;
}
int foo(A *a) {
return a->f();
}
int main() {
return foo(new B);
}

View File

@ -0,0 +1,46 @@
# REQUIRES: lld
# Make sure DWARF v4 type units work.
# RUN: %clangxx -target x86_64-pc-linux %S/Inputs/debug-types-basic.cpp \
# RUN: -g -gdwarf-4 -fdebug-types-section -c -o %t.o
# RUN: ld.lld %t.o -o %t
# RUN: %lldb %t -s %s -o exit | FileCheck %s
# Now do the same for DWARF v5.
# RUN: %clangxx -target x86_64-pc-linux %S/Inputs/debug-types-basic.cpp \
# RUN: -g -gdwarf-5 -fdebug-types-section -c -o %t.o
# RUN: ld.lld %t.o -o %t
# RUN: %lldb %t -s %s -o exit | FileCheck %s
type lookup A
# CHECK-LABEL: type lookup A
# CHECK: struct A {
# CHECK-NEXT: int i;
# CHECK-NEXT: long l;
# CHECK-NEXT: float f;
# CHECK-NEXT: double d;
# CHECK-NEXT: }
type lookup E
# CHECK-LABEL: type lookup E
# CHECK: enum E {
# CHECK-NEXT: e1,
# CHECK-NEXT: e2,
# CHECK-NEXT: e3
# CHECK-NEXT: }
type lookup EC
# CHECK-LABEL: type lookup EC
# CHECK: enum class EC {
# CHECK-NEXT: e1,
# CHECK-NEXT: e2,
# CHECK-NEXT: e3
# CHECK-NEXT: }
print (E) 1
# CHECK-LABEL: print (E) 1
# CHECK: (E) $0 = e2
print (EC) 1
# CHECK-LABEL: print (EC) 1
# CHECK: (EC) $1 = e2

View File

@ -0,0 +1,28 @@
# UNSUPPORTED: system-darwin, system-windows
# Make sure DWARF v4 type units work.
# RUN: %clangxx %S/Inputs/debug-types-expressions.cpp \
# RUN: -g -fdebug-types-section -o %t
# RUN: %lldb %t -s %s -o exit | FileCheck %s
# Now do the same for DWARF v5.
# RUN: %clangxx %S/Inputs/debug-types-expressions.cpp \
# RUN: -g -gdwarf-5 -fdebug-types-section -o %t
# RUN: %lldb %t -s %s -o exit | FileCheck %s
breakpoint set -n foo
process launch
# CHECK: Process {{.*}} stopped
frame variable a
# CHECK-LABEL: frame variable a
# CHECK: (B *) a =
print a->f()
# CHECK-LABEL: print a->f()
# CHECK: (int) $0 = 47
print ns::A()
# CHECK-LABEL: print ns::A()
# CHECK: (ns::A) $1 = (i = 147)

View File

@ -1 +1 @@
config.suffixes = ['.cpp', '.s']
config.suffixes = ['.cpp', '.s', '.test']

View File

@ -22,6 +22,7 @@ add_lldb_library(lldbPluginSymbolFileDWARF PLUGIN
DWARFDIE.cpp
DWARFFormValue.cpp
DWARFIndex.cpp
DWARFTypeUnit.cpp
DWARFUnit.cpp
HashedNameToDIE.cpp
LogChannelDWARF.cpp

View File

@ -16,15 +16,12 @@ class DWARFCompileUnit : public DWARFUnit {
public:
void Dump(lldb_private::Stream *s) const override;
DIERef::Section GetDebugSection() const override {
return DIERef::Section::DebugInfo;
}
private:
DWARFCompileUnit(SymbolFileDWARF *dwarf, lldb::user_id_t uid,
const DWARFUnitHeader &header,
const DWARFAbbreviationDeclarationSet &abbrevs)
: DWARFUnit(dwarf, uid, header, abbrevs) {}
const DWARFAbbreviationDeclarationSet &abbrevs,
DIERef::Section section)
: DWARFUnit(dwarf, uid, header, abbrevs, section) {}
DISALLOW_COPY_AND_ASSIGN(DWARFCompileUnit);

View File

@ -91,3 +91,8 @@ const DWARFDataExtractor &DWARFContext::getOrLoadStrOffsetsData() {
return LoadOrGetSection(m_main_section_list, eSectionTypeDWARFDebugStrOffsets,
m_data_debug_str_offsets);
}
const DWARFDataExtractor &DWARFContext::getOrLoadDebugTypesData() {
return LoadOrGetSection(m_main_section_list, eSectionTypeDWARFDebugTypes,
m_data_debug_types);
}

View File

@ -29,6 +29,7 @@ private:
llvm::Optional<DWARFDataExtractor> m_data_debug_macro;
llvm::Optional<DWARFDataExtractor> m_data_debug_str;
llvm::Optional<DWARFDataExtractor> m_data_debug_str_offsets;
llvm::Optional<DWARFDataExtractor> m_data_debug_types;
bool isDwo() { return m_dwo_section_list != nullptr; }
@ -47,6 +48,7 @@ public:
const DWARFDataExtractor &getOrLoadMacroData();
const DWARFDataExtractor &getOrLoadStrData();
const DWARFDataExtractor &getOrLoadStrOffsetsData();
const DWARFDataExtractor &getOrLoadDebugTypesData();
};
} // namespace lldb_private

View File

@ -22,6 +22,7 @@
#include "DWARFDebugInfo.h"
#include "DWARFDebugInfoEntry.h"
#include "DWARFFormValue.h"
#include "DWARFTypeUnit.h"
using namespace lldb;
using namespace lldb_private;
@ -73,17 +74,12 @@ llvm::Expected<DWARFDebugAranges &> DWARFDebugInfo::GetCompileUnitAranges() {
return *m_cu_aranges_up;
}
void DWARFDebugInfo::ParseUnitHeadersIfNeeded() {
if (!m_units.empty())
return;
if (!m_dwarf2Data)
return;
void Parse(SymbolFileDWARF *dwarf, const DWARFDataExtractor &data,
DIERef::Section section, std::vector<DWARFUnitSP> &units) {
lldb::offset_t offset = 0;
const auto &debug_info_data = m_context.getOrLoadDebugInfoData();
while (debug_info_data.ValidOffset(offset)) {
llvm::Expected<DWARFUnitSP> unit_sp = DWARFUnit::extract(
m_dwarf2Data, m_units.size(), debug_info_data, &offset);
while (data.ValidOffset(offset)) {
llvm::Expected<DWARFUnitSP> unit_sp =
DWARFUnit::extract(dwarf, units.size(), data, section, &offset);
if (!unit_sp) {
// FIXME: Propagate this error up.
@ -94,12 +90,24 @@ void DWARFDebugInfo::ParseUnitHeadersIfNeeded() {
// If it didn't return an error, then it should be returning a valid Unit.
assert(*unit_sp);
m_units.push_back(*unit_sp);
units.push_back(*unit_sp);
offset = (*unit_sp)->GetNextUnitOffset();
}
}
void DWARFDebugInfo::ParseUnitHeadersIfNeeded() {
if (!m_units.empty())
return;
if (!m_dwarf2Data)
return;
Parse(m_dwarf2Data, m_context.getOrLoadDebugInfoData(),
DIERef::Section::DebugInfo, m_units);
Parse(m_dwarf2Data, m_context.getOrLoadDebugTypesData(),
DIERef::Section::DebugTypes, m_units);
}
size_t DWARFDebugInfo::GetNumUnits() {
ParseUnitHeadersIfNeeded();
return m_units.size();

View File

@ -0,0 +1,24 @@
//===-- DWARFTypeUnit.cpp ---------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "DWARFTypeUnit.h"
#include "SymbolFileDWARF.h"
#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
void DWARFTypeUnit::Dump(Stream *s) const {
s->Printf("0x%8.8x: Type Unit: length = 0x%8.8x, version = 0x%4.4x, "
"abbr_offset = 0x%8.8x, addr_size = 0x%2.2x (next CU at "
"{0x%8.8x})\n",
GetOffset(), GetLength(), GetVersion(), GetAbbrevOffset(),
GetAddressByteSize(), GetNextUnitOffset());
}

View File

@ -0,0 +1,29 @@
//===-- DWARFTypeUnit.h -----------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef SymbolFileDWARF_DWARFTypeUnit_h_
#define SymbolFileDWARF_DWARFTypeUnit_h_
#include "DWARFUnit.h"
#include "llvm/Support/Error.h"
class DWARFTypeUnit : public DWARFUnit {
public:
void Dump(lldb_private::Stream *s) const override;
private:
DWARFTypeUnit(SymbolFileDWARF *dwarf, lldb::user_id_t uid,
const DWARFUnitHeader &header,
const DWARFAbbreviationDeclarationSet &abbrevs,
DIERef::Section section)
: DWARFUnit(dwarf, uid, header, abbrevs, section) {}
friend class DWARFUnit;
};
#endif // SymbolFileDWARF_DWARFTypeUnit_h_

View File

@ -21,6 +21,7 @@
#include "DWARFCompileUnit.h"
#include "DWARFDebugAranges.h"
#include "DWARFDebugInfo.h"
#include "DWARFTypeUnit.h"
#include "LogChannelDWARF.h"
#include "SymbolFileDWARFDebugMap.h"
#include "SymbolFileDWARFDwo.h"
@ -33,9 +34,10 @@ extern int g_verbose;
DWARFUnit::DWARFUnit(SymbolFileDWARF *dwarf, lldb::user_id_t uid,
const DWARFUnitHeader &header,
const DWARFAbbreviationDeclarationSet &abbrevs)
const DWARFAbbreviationDeclarationSet &abbrevs,
DIERef::Section section)
: UserID(uid), m_dwarf(dwarf), m_header(header), m_abbrevs(&abbrevs),
m_cancel_scopes(false) {}
m_cancel_scopes(false), m_section(section) {}
DWARFUnit::~DWARFUnit() = default;
@ -788,7 +790,7 @@ const DWARFDebugAranges &DWARFUnit::GetFunctionAranges() {
}
llvm::Expected<DWARFUnitHeader>
DWARFUnitHeader::extract(const DWARFDataExtractor &data,
DWARFUnitHeader::extract(const DWARFDataExtractor &data, DIERef::Section section,
lldb::offset_t *offset_ptr) {
DWARFUnitHeader header;
header.m_offset = *offset_ptr;
@ -803,8 +805,8 @@ DWARFUnitHeader::extract(const DWARFDataExtractor &data,
} else {
header.m_abbr_offset = data.GetDWARFOffset(offset_ptr);
header.m_addr_size = data.GetU8(offset_ptr);
// Only compile units supported so far.
header.m_unit_type = DW_UT_compile;
header.m_unit_type =
section == DIERef::Section::DebugTypes ? DW_UT_type : DW_UT_compile;
}
bool length_OK = data.ValidOffset(header.GetNextUnitOffset() - 1);
@ -826,11 +828,12 @@ DWARFUnitHeader::extract(const DWARFDataExtractor &data,
llvm::Expected<DWARFUnitSP>
DWARFUnit::extract(SymbolFileDWARF *dwarf, user_id_t uid,
const DWARFDataExtractor &debug_info,
const DWARFDataExtractor &debug_info, DIERef::Section section,
lldb::offset_t *offset_ptr) {
assert(debug_info.ValidOffset(*offset_ptr));
auto expected_header = DWARFUnitHeader::extract(debug_info, offset_ptr);
auto expected_header =
DWARFUnitHeader::extract(debug_info, section, offset_ptr);
if (!expected_header)
return expected_header.takeError();
@ -852,14 +855,17 @@ DWARFUnit::extract(SymbolFileDWARF *dwarf, user_id_t uid,
return llvm::make_error<llvm::object::GenericBinaryError>(
"No abbrev exists at the specified offset.");
DWARFUnitSP unit_sp(
new DWARFCompileUnit(dwarf, uid, *expected_header, *abbrevs));
return unit_sp;
if (expected_header->IsTypeUnit())
return DWARFUnitSP(
new DWARFTypeUnit(dwarf, uid, *expected_header, *abbrevs, section));
return DWARFUnitSP(
new DWARFCompileUnit(dwarf, uid, *expected_header, *abbrevs, section));
}
const lldb_private::DWARFDataExtractor &DWARFUnit::GetData() const {
return m_dwarf->GetDWARFContext().getOrLoadDebugInfoData();
return m_section == DIERef::Section::DebugTypes
? m_dwarf->GetDWARFContext().getOrLoadDebugTypesData()
: m_dwarf->GetDWARFContext().getOrLoadDebugInfoData();
}
uint32_t DWARFUnit::GetHeaderByteSize() const {

View File

@ -58,7 +58,7 @@ public:
uint32_t GetNextUnitOffset() const { return m_offset + m_length + 4; }
static llvm::Expected<DWARFUnitHeader>
extract(const lldb_private::DWARFDataExtractor &data,
extract(const lldb_private::DWARFDataExtractor &data, DIERef::Section section,
lldb::offset_t *offset_ptr);
};
@ -70,7 +70,7 @@ public:
static llvm::Expected<DWARFUnitSP>
extract(SymbolFileDWARF *dwarf2Data, lldb::user_id_t uid,
const lldb_private::DWARFDataExtractor &debug_info,
lldb::offset_t *offset_ptr);
DIERef::Section section, lldb::offset_t *offset_ptr);
virtual ~DWARFUnit();
void ExtractUnitDIEIfNeeded();
@ -203,12 +203,17 @@ public:
return die_iterator_range(m_die_array.begin(), m_die_array.end());
}
virtual DIERef::Section GetDebugSection() const = 0;
DIERef::Section GetDebugSection() const { return m_section; }
protected:
DWARFUnit(SymbolFileDWARF *dwarf, lldb::user_id_t uid,
const DWARFUnitHeader &header,
const DWARFAbbreviationDeclarationSet &abbrevs);
const DWARFAbbreviationDeclarationSet &abbrevs,
DIERef::Section section);
llvm::Error ExtractHeader(SymbolFileDWARF *dwarf,
const lldb_private::DWARFDataExtractor &data,
lldb::offset_t *offset_ptr);
SymbolFileDWARF *m_dwarf = nullptr;
std::unique_ptr<SymbolFileDWARFDwo> m_dwo_symbol_file;
@ -245,6 +250,7 @@ protected:
// in the main object file
dw_offset_t m_base_obj_offset = DW_INVALID_OFFSET;
dw_offset_t m_str_offsets_base = 0; // Value of DW_AT_str_offsets_base.
const DIERef::Section m_section;
private:
void ParseProducerInfo();

View File

@ -439,20 +439,6 @@ uint32_t SymbolFileDWARF::CalculateAbilities() {
if (section_list == NULL)
return 0;
// On non Apple platforms we might have .debug_types debug info that is
// created by using "-fdebug-types-section". LLDB currently will try to
// load this debug info, but it causes crashes during debugging when types
// are missing since it doesn't know how to parse the info in the
// .debug_types type units. This causes all complex debug info types to be
// unresolved. Because this causes LLDB to crash and since it really
// doesn't provide a solid debuggiung experience, we should disable trying
// to debug this kind of DWARF until support gets added or deprecated.
if (section_list->FindSectionByName(ConstString(".debug_types"))) {
m_obj_file->GetModule()->ReportWarning(
"lldb doesnt support .debug_types debug info");
return 0;
}
uint64_t debug_abbrev_file_size = 0;
uint64_t debug_info_file_size = 0;
uint64_t debug_line_file_size = 0;