Skip to content

Commit

Permalink
DWARF: Introduce DWARFUnitHeader class
Browse files Browse the repository at this point in the history
Summary:
This patch introduces the DWARFUnitHeader class. Its purpose (and its
structure, to the extent it was possible to make it) is the same as its
LLVM counterpart -- to extract the unit header information before we
actually construct the unit, so that we know which kind of units to
construct. This is needed because as of DWARF5, type units live in the
.debug_info section, which means it's not possible to statically
determine the type of units in a given section.

Reviewers: aprantl, clayborg, JDevlieghere

Subscribers: lldb-commits

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

llvm-svn: 361224
  • Loading branch information
labath authored and MrSidims committed May 24, 2019
1 parent d80abde commit 04049a0
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 147 deletions.
93 changes: 2 additions & 91 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp
Expand Up @@ -8,104 +8,15 @@

#include "DWARFCompileUnit.h"

#include "SymbolFileDWARF.h"
#include "lldb/Utility/Stream.h"
#include "llvm/Object/Error.h"

using namespace lldb;
using namespace lldb_private;

DWARFCompileUnit::DWARFCompileUnit(SymbolFileDWARF *dwarf2Data,
lldb::user_id_t uid)
: DWARFUnit(dwarf2Data, uid) {}


llvm::Expected<DWARFUnitSP> DWARFCompileUnit::extract(
SymbolFileDWARF *dwarf2Data, user_id_t uid,
const DWARFDataExtractor &debug_info, lldb::offset_t *offset_ptr) {
assert(debug_info.ValidOffset(*offset_ptr));

// std::make_shared would require the ctor to be public.
std::shared_ptr<DWARFCompileUnit> cu_sp(
new DWARFCompileUnit(dwarf2Data, uid));

cu_sp->m_offset = *offset_ptr;

dw_offset_t abbr_offset;
const DWARFDebugAbbrev *abbr = dwarf2Data->DebugAbbrev();
if (!abbr)
return llvm::make_error<llvm::object::GenericBinaryError>(
"No debug_abbrev data");

cu_sp->m_length = debug_info.GetDWARFInitialLength(offset_ptr);
cu_sp->m_version = debug_info.GetU16(offset_ptr);

if (cu_sp->m_version == 5) {
cu_sp->m_unit_type = debug_info.GetU8(offset_ptr);
cu_sp->m_addr_size = debug_info.GetU8(offset_ptr);
abbr_offset = debug_info.GetDWARFOffset(offset_ptr);

if (cu_sp->m_unit_type == llvm::dwarf::DW_UT_skeleton)
cu_sp->m_dwo_id = debug_info.GetU64(offset_ptr);
} else {
abbr_offset = debug_info.GetDWARFOffset(offset_ptr);
cu_sp->m_addr_size = debug_info.GetU8(offset_ptr);
}

bool length_OK = debug_info.ValidOffset(cu_sp->GetNextUnitOffset() - 1);
bool version_OK = SymbolFileDWARF::SupportedVersion(cu_sp->m_version);
bool abbr_offset_OK =
dwarf2Data->GetDWARFContext().getOrLoadAbbrevData().ValidOffset(
abbr_offset);
bool addr_size_OK = (cu_sp->m_addr_size == 4) || (cu_sp->m_addr_size == 8);

if (!length_OK)
return llvm::make_error<llvm::object::GenericBinaryError>(
"Invalid compile unit length");
if (!version_OK)
return llvm::make_error<llvm::object::GenericBinaryError>(
"Unsupported compile unit version");
if (!abbr_offset_OK)
return llvm::make_error<llvm::object::GenericBinaryError>(
"Abbreviation offset for compile unit is not valid");
if (!addr_size_OK)
return llvm::make_error<llvm::object::GenericBinaryError>(
"Invalid compile unit address size");

cu_sp->m_abbrevs = abbr->GetAbbreviationDeclarationSet(abbr_offset);
if (!cu_sp->m_abbrevs)
return llvm::make_error<llvm::object::GenericBinaryError>(
"No abbrev exists at the specified offset.");

return cu_sp;
}

void DWARFCompileUnit::Dump(Stream *s) const {
s->Printf("0x%8.8x: Compile 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",
m_offset, m_length, m_version, GetAbbrevOffset(), m_addr_size,
GetNextUnitOffset());
}

uint32_t DWARFCompileUnit::GetHeaderByteSize() const {
if (m_version < 5)
return 11;

switch (m_unit_type) {
case llvm::dwarf::DW_UT_compile:
case llvm::dwarf::DW_UT_partial:
return 12;
case llvm::dwarf::DW_UT_skeleton:
case llvm::dwarf::DW_UT_split_compile:
return 20;
case llvm::dwarf::DW_UT_type:
case llvm::dwarf::DW_UT_split_type:
return 24;
}
llvm_unreachable("invalid UnitType.");
}

const lldb_private::DWARFDataExtractor &DWARFCompileUnit::GetData() const {
return m_dwarf->GetDWARFContext().getOrLoadDebugInfoData();
GetOffset(), GetLength(), GetVersion(), GetAbbrevOffset(),
GetAddressByteSize(), GetNextUnitOffset());
}
26 changes: 7 additions & 19 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h
Expand Up @@ -14,33 +14,21 @@

class DWARFCompileUnit : public DWARFUnit {
public:
static llvm::Expected<DWARFUnitSP>
extract(SymbolFileDWARF *dwarf2Data, lldb::user_id_t uid,
const lldb_private::DWARFDataExtractor &debug_info,
lldb::offset_t *offset_ptr);
void Dump(lldb_private::Stream *s) const override;

/// Get the data that contains the DIE information for this unit.
///
/// \return
/// The correct data (.debug_types for DWARF 4 and earlier, and
/// .debug_info for DWARF 5 and later) for the DIE information in
/// this unit.
const lldb_private::DWARFDataExtractor &GetData() const override;

/// Get the size in bytes of the header.
///
/// \return
/// Byte size of the compile unit header
uint32_t GetHeaderByteSize() const override;

DIERef::Section GetDebugSection() const override {
return DIERef::Section::DebugInfo;
}

private:
DWARFCompileUnit(SymbolFileDWARF *dwarf2Data, lldb::user_id_t uid);
DWARFCompileUnit(SymbolFileDWARF *dwarf, lldb::user_id_t uid,
const DWARFUnitHeader &header,
const DWARFAbbreviationDeclarationSet &abbrevs)
: DWARFUnit(dwarf, uid, header, abbrevs) {}

DISALLOW_COPY_AND_ASSIGN(DWARFCompileUnit);

friend class DWARFUnit;
};

#endif // SymbolFileDWARF_DWARFCompileUnit_h_
13 changes: 6 additions & 7 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
Expand Up @@ -81,23 +81,22 @@ void DWARFDebugInfo::ParseUnitHeadersIfNeeded() {

lldb::offset_t offset = 0;
const auto &debug_info_data = m_context.getOrLoadDebugInfoData();

while (debug_info_data.ValidOffset(offset)) {
llvm::Expected<DWARFUnitSP> cu_sp = DWARFCompileUnit::extract(
llvm::Expected<DWARFUnitSP> unit_sp = DWARFUnit::extract(
m_dwarf2Data, m_units.size(), debug_info_data, &offset);

if (!cu_sp) {
if (!unit_sp) {
// FIXME: Propagate this error up.
llvm::consumeError(cu_sp.takeError());
llvm::consumeError(unit_sp.takeError());
return;
}

// If it didn't return an error, then it should be returning a valid Unit.
assert(*cu_sp);
assert(*unit_sp);

m_units.push_back(*cu_sp);
m_units.push_back(*unit_sp);

offset = (*cu_sp)->GetNextUnitOffset();
offset = (*unit_sp)->GetNextUnitOffset();
}
}

Expand Down
114 changes: 102 additions & 12 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
Expand Up @@ -16,7 +16,9 @@
#include "lldb/Utility/LLDBAssert.h"
#include "lldb/Utility/StreamString.h"
#include "lldb/Utility/Timer.h"
#include "llvm/Object/Error.h"

#include "DWARFCompileUnit.h"
#include "DWARFDebugAranges.h"
#include "DWARFDebugInfo.h"
#include "LogChannelDWARF.h"
Expand All @@ -29,10 +31,13 @@ using namespace std;

extern int g_verbose;

DWARFUnit::DWARFUnit(SymbolFileDWARF *dwarf, user_id_t uid)
: UserID(uid), m_dwarf(dwarf), m_cancel_scopes(false) {}
DWARFUnit::DWARFUnit(SymbolFileDWARF *dwarf, lldb::user_id_t uid,
const DWARFUnitHeader &header,
const DWARFAbbreviationDeclarationSet &abbrevs)
: UserID(uid), m_dwarf(dwarf), m_header(header), m_abbrevs(&abbrevs),
m_cancel_scopes(false) {}

DWARFUnit::~DWARFUnit() {}
DWARFUnit::~DWARFUnit() = default;

// Parses first DIE of a compile unit.
void DWARFUnit::ExtractUnitDIEIfNeeded() {
Expand All @@ -46,8 +51,8 @@ void DWARFUnit::ExtractUnitDIEIfNeeded() {
return; // Already parsed

static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
Timer scoped_timer(
func_cat, "%8.8x: DWARFUnit::ExtractUnitDIEIfNeeded()", m_offset);
Timer scoped_timer(func_cat, "%8.8x: DWARFUnit::ExtractUnitDIEIfNeeded()",
GetOffset());

// Set the offset to that of the first DIE and calculate the start of the
// next compilation unit header.
Expand Down Expand Up @@ -145,8 +150,8 @@ void DWARFUnit::ExtractDIEsRWLocked() {
llvm::sys::ScopedWriter first_die_lock(m_first_die_mutex);

static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
Timer scoped_timer(
func_cat, "%8.8x: DWARFUnit::ExtractDIEsIfNeeded()", m_offset);
Timer scoped_timer(func_cat, "%8.8x: DWARFUnit::ExtractDIEsIfNeeded()",
GetOffset());

// Set the offset to that of the first DIE and calculate the start of the
// next compilation unit header.
Expand Down Expand Up @@ -332,7 +337,7 @@ void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) {
DW_AT_GNU_ranges_base, 0);
dwo_cu->SetRangesBase(ranges_base);

dwo_cu->SetBaseObjOffset(m_offset);
dwo_cu->SetBaseObjOffset(GetOffset());

SetDwoStrOffsetsBase(dwo_cu);
}
Expand Down Expand Up @@ -366,10 +371,6 @@ size_t DWARFUnit::AppendDIEsWithTag(const dw_tag_t tag,
return dies.size() - old_size;
}

dw_offset_t DWARFUnit::GetNextUnitOffset() const {
return m_offset + GetLengthByteSize() + GetLength();
}

size_t DWARFUnit::GetDebugInfoSize() const {
return GetLengthByteSize() + GetLength() - GetHeaderByteSize();
}
Expand Down Expand Up @@ -790,3 +791,92 @@ const DWARFDebugAranges &DWARFUnit::GetFunctionAranges() {
return *m_func_aranges_up;
}

llvm::Expected<DWARFUnitHeader>
DWARFUnitHeader::extract(const DWARFDataExtractor &data,
lldb::offset_t *offset_ptr) {
DWARFUnitHeader header;
header.m_offset = *offset_ptr;
header.m_length = data.GetDWARFInitialLength(offset_ptr);
header.m_version = data.GetU16(offset_ptr);
if (header.m_version == 5) {
header.m_unit_type = data.GetU8(offset_ptr);
header.m_addr_size = data.GetU8(offset_ptr);
header.m_abbr_offset = data.GetDWARFOffset(offset_ptr);
if (header.m_unit_type == llvm::dwarf::DW_UT_skeleton)
header.m_dwo_id = data.GetU64(offset_ptr);
} 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;
}

bool length_OK = data.ValidOffset(header.GetNextUnitOffset() - 1);
bool version_OK = SymbolFileDWARF::SupportedVersion(header.m_version);
bool addr_size_OK = (header.m_addr_size == 4) || (header.m_addr_size == 8);

if (!length_OK)
return llvm::make_error<llvm::object::GenericBinaryError>(
"Invalid unit length");
if (!version_OK)
return llvm::make_error<llvm::object::GenericBinaryError>(
"Unsupported unit version");
if (!addr_size_OK)
return llvm::make_error<llvm::object::GenericBinaryError>(
"Invalid unit address size");

return header;
}

llvm::Expected<DWARFUnitSP>
DWARFUnit::extract(SymbolFileDWARF *dwarf, user_id_t uid,
const DWARFDataExtractor &debug_info,
lldb::offset_t *offset_ptr) {
assert(debug_info.ValidOffset(*offset_ptr));

auto expected_header = DWARFUnitHeader::extract(debug_info, offset_ptr);
if (!expected_header)
return expected_header.takeError();

const DWARFDebugAbbrev *abbr = dwarf->DebugAbbrev();
if (!abbr)
return llvm::make_error<llvm::object::GenericBinaryError>(
"No debug_abbrev data");

bool abbr_offset_OK =
dwarf->GetDWARFContext().getOrLoadAbbrevData().ValidOffset(
expected_header->GetAbbrOffset());
if (!abbr_offset_OK)
return llvm::make_error<llvm::object::GenericBinaryError>(
"Abbreviation offset for unit is not valid");

const DWARFAbbreviationDeclarationSet *abbrevs =
abbr->GetAbbreviationDeclarationSet(expected_header->GetAbbrOffset());
if (!abbrevs)
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;
}

const lldb_private::DWARFDataExtractor &DWARFUnit::GetData() const {
return m_dwarf->GetDWARFContext().getOrLoadDebugInfoData();
}

uint32_t DWARFUnit::GetHeaderByteSize() const {
switch (m_header.GetUnitType()) {
case llvm::dwarf::DW_UT_compile:
case llvm::dwarf::DW_UT_partial:
return GetVersion() < 5 ? 11 : 12;
case llvm::dwarf::DW_UT_skeleton:
case llvm::dwarf::DW_UT_split_compile:
return 20;
case llvm::dwarf::DW_UT_type:
case llvm::dwarf::DW_UT_split_type:
return GetVersion() < 5 ? 23 : 24;
}
llvm_unreachable("invalid UnitType.");
}

0 comments on commit 04049a0

Please sign in to comment.