forked from OSchip/llvm-project
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:
parent
b72b091389
commit
80233daeaa
|
@ -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);
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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)
|
|
@ -1 +1 @@
|
|||
config.suffixes = ['.cpp', '.s']
|
||||
config.suffixes = ['.cpp', '.s', '.test']
|
||||
|
|
|
@ -22,6 +22,7 @@ add_lldb_library(lldbPluginSymbolFileDWARF PLUGIN
|
|||
DWARFDIE.cpp
|
||||
DWARFFormValue.cpp
|
||||
DWARFIndex.cpp
|
||||
DWARFTypeUnit.cpp
|
||||
DWARFUnit.cpp
|
||||
HashedNameToDIE.cpp
|
||||
LogChannelDWARF.cpp
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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());
|
||||
}
|
|
@ -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_
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 doesn’t 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;
|
||||
|
|
Loading…
Reference in New Issue