Files
clang-p2996/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp
Pavel Labath f4014e116e DWARF: Add ability to reference debug info coming from multiple sections
Summary:
This patch adds the ability to precisely address debug info in
situations when a single file can have more than one debug-info-bearing
sections (as is the case with type units in DWARF v4).

The changes here can be classified into roughly three categories:
- the code which addresses a debug info by offset gets an additional
  argument, which specifies the section one should look into.
- the DIERef class also gets an additional member variable specifying
  the section. This way, code dealing with DIERefs can know which
  section is the object referring to.
- the user_id_t encoding steals one bit from the dwarf_id field to store
  the section. This means the total number of separate object files
  (apple .o, or normal .dwo) is limited to 2 billion, but that is fine
  as it's not possible to hit that number without switching to DWARF64
  anyway.

This patch is functionally equivalent to (and inspired by) the two
patches (D61503 and D61504) by Jan Kratochvil, but there are differences
in the implementation:
- it uses an enum instead of a bool flag to differentiate the sections
- it increases the size of DIERef struct instead of reducing the amount
  of addressable debug info
- it sets up DWARFDebugInfo to store the units in a single vector
  instead of two. This sets us up for the future in which type units can
  also live in the debug_info section, and I believe it's cleaner
  because there's no need for unit index remapping

There are no tests with this patch as this is essentially NFC until
we start parsing type units from the debug_types section.

Reviewers: JDevlieghere, clayborg, aprantl

Subscribers: arphaman, jankratochvil, lldb-commits

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

llvm-svn: 360872
2019-05-16 11:07:58 +00:00

279 lines
9.4 KiB
C++

//===-- DebugNamesDWARFIndex.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 "Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h"
#include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h"
#include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h"
#include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h"
#include "lldb/Utility/RegularExpression.h"
#include "lldb/Utility/Stream.h"
using namespace lldb_private;
using namespace lldb;
static llvm::DWARFDataExtractor ToLLVM(const DWARFDataExtractor &data) {
return llvm::DWARFDataExtractor(
llvm::StringRef(reinterpret_cast<const char *>(data.GetDataStart()),
data.GetByteSize()),
data.GetByteOrder() == eByteOrderLittle, data.GetAddressByteSize());
}
llvm::Expected<std::unique_ptr<DebugNamesDWARFIndex>>
DebugNamesDWARFIndex::Create(Module &module, DWARFDataExtractor debug_names,
DWARFDataExtractor debug_str,
DWARFDebugInfo *debug_info) {
if (!debug_info) {
return llvm::make_error<llvm::StringError>("debug info null",
llvm::inconvertibleErrorCode());
}
auto index_up =
llvm::make_unique<DebugNames>(ToLLVM(debug_names), ToLLVM(debug_str));
if (llvm::Error E = index_up->extract())
return std::move(E);
return std::unique_ptr<DebugNamesDWARFIndex>(new DebugNamesDWARFIndex(
module, std::move(index_up), debug_names, debug_str, *debug_info));
}
llvm::DenseSet<dw_offset_t>
DebugNamesDWARFIndex::GetUnits(const DebugNames &debug_names) {
llvm::DenseSet<dw_offset_t> result;
for (const DebugNames::NameIndex &ni : debug_names) {
for (uint32_t cu = 0; cu < ni.getCUCount(); ++cu)
result.insert(ni.getCUOffset(cu));
}
return result;
}
DIERef DebugNamesDWARFIndex::ToDIERef(const DebugNames::Entry &entry) {
llvm::Optional<uint64_t> cu_offset = entry.getCUOffset();
if (!cu_offset)
return DIERef();
DWARFUnit *cu = m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, *cu_offset);
if (!cu)
return DIERef();
// This initializes the DWO symbol file. It's not possible for
// GetDwoSymbolFile to call this automatically because of mutual recursion
// between this and DWARFDebugInfoEntry::GetAttributeValue.
cu->ExtractUnitDIEIfNeeded();
uint64_t die_bias = cu->GetDwoSymbolFile() ? 0 : *cu_offset;
if (llvm::Optional<uint64_t> die_offset = entry.getDIEUnitOffset())
return DIERef(DIERef::Section::DebugInfo, *cu_offset, die_bias + *die_offset);
return DIERef();
}
void DebugNamesDWARFIndex::Append(const DebugNames::Entry &entry,
DIEArray &offsets) {
if (DIERef ref = ToDIERef(entry))
offsets.push_back(ref);
}
void DebugNamesDWARFIndex::MaybeLogLookupError(llvm::Error error,
const DebugNames::NameIndex &ni,
llvm::StringRef name) {
// Ignore SentinelErrors, log everything else.
LLDB_LOG_ERROR(
LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS),
handleErrors(std::move(error), [](const DebugNames::SentinelError &) {}),
"Failed to parse index entries for index at {1:x}, name {2}: {0}",
ni.getUnitOffset(), name);
}
void DebugNamesDWARFIndex::GetGlobalVariables(ConstString basename,
DIEArray &offsets) {
m_fallback.GetGlobalVariables(basename, offsets);
for (const DebugNames::Entry &entry :
m_debug_names_up->equal_range(basename.GetStringRef())) {
if (entry.tag() != DW_TAG_variable)
continue;
Append(entry, offsets);
}
}
void DebugNamesDWARFIndex::GetGlobalVariables(const RegularExpression &regex,
DIEArray &offsets) {
m_fallback.GetGlobalVariables(regex, offsets);
for (const DebugNames::NameIndex &ni: *m_debug_names_up) {
for (DebugNames::NameTableEntry nte: ni) {
if (!regex.Execute(nte.getString()))
continue;
uint32_t entry_offset = nte.getEntryOffset();
llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
if (entry_or->tag() != DW_TAG_variable)
continue;
Append(*entry_or, offsets);
}
MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
}
}
}
void DebugNamesDWARFIndex::GetGlobalVariables(const DWARFUnit &cu,
DIEArray &offsets) {
m_fallback.GetGlobalVariables(cu, offsets);
uint64_t cu_offset = cu.GetOffset();
for (const DebugNames::NameIndex &ni: *m_debug_names_up) {
for (DebugNames::NameTableEntry nte: ni) {
uint32_t entry_offset = nte.getEntryOffset();
llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
if (entry_or->tag() != DW_TAG_variable)
continue;
if (entry_or->getCUOffset() != cu_offset)
continue;
Append(*entry_or, offsets);
}
MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
}
}
}
void DebugNamesDWARFIndex::GetCompleteObjCClass(ConstString class_name,
bool must_be_implementation,
DIEArray &offsets) {
m_fallback.GetCompleteObjCClass(class_name, must_be_implementation, offsets);
// Keep a list of incomplete types as fallback for when we don't find the
// complete type.
DIEArray incomplete_types;
for (const DebugNames::Entry &entry :
m_debug_names_up->equal_range(class_name.GetStringRef())) {
if (entry.tag() != DW_TAG_structure_type &&
entry.tag() != DW_TAG_class_type)
continue;
DIERef ref = ToDIERef(entry);
if (!ref)
continue;
DWARFUnit *cu =
m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, ref.cu_offset);
if (!cu || !cu->Supports_DW_AT_APPLE_objc_complete_type()) {
incomplete_types.push_back(ref);
continue;
}
// FIXME: We should return DWARFDIEs so we don't have to resolve it twice.
DWARFDIE die = m_debug_info.GetDIE(ref);
if (!die)
continue;
if (die.GetAttributeValueAsUnsigned(DW_AT_APPLE_objc_complete_type, 0)) {
// If we find the complete version we're done.
offsets.push_back(ref);
return;
} else {
incomplete_types.push_back(ref);
}
}
offsets.insert(offsets.end(), incomplete_types.begin(),
incomplete_types.end());
}
void DebugNamesDWARFIndex::GetTypes(ConstString name, DIEArray &offsets) {
m_fallback.GetTypes(name, offsets);
for (const DebugNames::Entry &entry :
m_debug_names_up->equal_range(name.GetStringRef())) {
if (isType(entry.tag()))
Append(entry, offsets);
}
}
void DebugNamesDWARFIndex::GetTypes(const DWARFDeclContext &context,
DIEArray &offsets) {
m_fallback.GetTypes(context, offsets);
for (const DebugNames::Entry &entry :
m_debug_names_up->equal_range(context[0].name)) {
if (entry.tag() == context[0].tag)
Append(entry, offsets);
}
}
void DebugNamesDWARFIndex::GetNamespaces(ConstString name, DIEArray &offsets) {
m_fallback.GetNamespaces(name, offsets);
for (const DebugNames::Entry &entry :
m_debug_names_up->equal_range(name.GetStringRef())) {
if (entry.tag() == DW_TAG_namespace)
Append(entry, offsets);
}
}
void DebugNamesDWARFIndex::GetFunctions(
ConstString name, DWARFDebugInfo &info,
const CompilerDeclContext &parent_decl_ctx, uint32_t name_type_mask,
std::vector<DWARFDIE> &dies) {
std::vector<DWARFDIE> v;
m_fallback.GetFunctions(name, info, parent_decl_ctx, name_type_mask, v);
for (const DebugNames::Entry &entry :
m_debug_names_up->equal_range(name.GetStringRef())) {
Tag tag = entry.tag();
if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine)
continue;
if (DIERef ref = ToDIERef(entry))
ProcessFunctionDIE(name.GetStringRef(), ref, info, parent_decl_ctx,
name_type_mask, v);
}
std::set<DWARFDebugInfoEntry *> seen;
for (DWARFDIE die : v)
if (seen.insert(die.GetDIE()).second)
dies.push_back(die);
}
void DebugNamesDWARFIndex::GetFunctions(const RegularExpression &regex,
DIEArray &offsets) {
m_fallback.GetFunctions(regex, offsets);
for (const DebugNames::NameIndex &ni: *m_debug_names_up) {
for (DebugNames::NameTableEntry nte: ni) {
if (!regex.Execute(nte.getString()))
continue;
uint32_t entry_offset = nte.getEntryOffset();
llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
Tag tag = entry_or->tag();
if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine)
continue;
Append(*entry_or, offsets);
}
MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
}
}
}
void DebugNamesDWARFIndex::Dump(Stream &s) {
m_fallback.Dump(s);
std::string data;
llvm::raw_string_ostream os(data);
m_debug_names_up->dump(os);
s.PutCString(os.str());
}