jankratochvil created this revision.
Herald added subscribers: JDevlieghere, mgorny.
This is the kitchen sink. It also covers separate DWZ common files.
All DWZ patches are also applied in: git clone -b dwz
git://git.jankratochvil.net/lldb
https://reviews.llvm.org/D40474
Files:
include/lldb/Utility/ConstString.h
include/lldb/Utility/FileSpec.h
source/Plugins/SymbolFile/DWARF/CMakeLists.txt
source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp
source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h
source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h
source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
source/Plugins/SymbolFile/DWARF/DWARFFileOffset.cpp
source/Plugins/SymbolFile/DWARF/DWARFFileOffset.h
source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
source/Plugins/SymbolFile/DWARF/DWARFFormValue.h
source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
Index: source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
===================================================================
--- source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -19,6 +19,7 @@
#include <unordered_map>
#include <vector>
#include <forward_list>
+#include <unordered_set>
// Other libraries and framework includes
#include "llvm/ADT/DenseMap.h"
@@ -308,6 +309,12 @@
virtual DWARFCompileUnit *GetBaseCompileUnit();
DWARFCompileUnitData *NewCompileUnitData();
+ SymbolFileDWARF *GetDWZSymbolFile() const {
+ if (!m_dwz_common_file)
+ return nullptr;
+ return m_dwz_common_file->SymbolFile();
+ }
+ bool GetIsDWZ() const { return m_is_dwz; }
protected:
typedef llvm::DenseMap<const DWARFDebugInfoEntry *, lldb_private::Type *>
@@ -473,6 +480,45 @@
SymbolFileDWARFDwp *GetDwpSymbolFile();
+ void InitializeDWZ();
+
+ class DWZCommonFile {
+ public:
+ // C++14: Use heterogenous lookup.
+ DWZCommonFile(const lldb_private::FileSpec &filespec_ref);
+ DWZCommonFile(std::unique_ptr<SymbolFileDWARF> &&symbol_file,
+ lldb::ObjectFileSP &&obj_file, lldb::ModuleSP &&module);
+ SymbolFileDWARF *SymbolFile() const { return m_symbol_file.get(); }
+
+ bool operator==(const DWZCommonFile &rhs) const {
+ return m_filespec_ref == rhs.m_filespec_ref;
+ }
+ bool operator!=(const DWZCommonFile &rhs) const { return !(*this == rhs); }
+ class Hasher {
+ public:
+ size_t operator()(const DWZCommonFile &key) const {
+ return lldb_private::FileSpec::Hasher()(key.m_filespec_ref);
+ }
+ };
+
+ // C++14: atomic_size_t
+ size_t m_use_count = 0;
+
+ private:
+ std::unique_ptr<SymbolFileDWARF> m_symbol_file;
+ lldb::ObjectFileSP m_obj_file;
+ lldb::ModuleSP m_module;
+ const lldb_private::FileSpec &m_filespec_ref;
+
+ DISALLOW_COPY_AND_ASSIGN(DWZCommonFile);
+ };
+ DWZCommonFile *m_dwz_common_file = nullptr;
+ void DWZCommonFileClear();
+ static std::unordered_set<DWZCommonFile, DWZCommonFile::Hasher>
+ m_filespec_to_dwzcommonfile;
+ // C++14: static std::shared_timed_mutex m_filespec_to_dwzcommonfile_mutex;
+ static std::recursive_mutex m_filespec_to_dwzcommonfile_mutex;
+ bool m_is_dwz = false;
std::forward_list<DWARFCompileUnitData> m_compile_unit_data_list;
lldb::ModuleWP m_debug_map_module_wp;
Index: source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
===================================================================
--- source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -409,7 +409,9 @@
m_supports_DW_AT_APPLE_objc_complete_type(eLazyBoolCalculate), m_ranges(),
m_unique_ast_type_map() {}
-SymbolFileDWARF::~SymbolFileDWARF() {}
+SymbolFileDWARF::~SymbolFileDWARF() {
+ DWZCommonFileClear();
+}
static const ConstString &GetDWARFMachOSegmentName() {
static ConstString g_dwarf_section_name("__DWARF");
@@ -425,6 +427,7 @@
}
TypeSystem *SymbolFileDWARF::GetTypeSystemForLanguage(LanguageType language) {
+ lldbassert(!GetIsDWZ());
SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile();
TypeSystem *type_system;
if (debug_map_symfile) {
@@ -489,6 +492,8 @@
else
m_apple_objc_ap.reset();
}
+
+ InitializeDWZ();
}
bool SymbolFileDWARF::SupportedVersion(uint16_t version) {
@@ -4395,3 +4400,140 @@
m_compile_unit_data_list.emplace_front(this);
return &m_compile_unit_data_list.front();
}
+
+std::unordered_set<SymbolFileDWARF::DWZCommonFile,
+ SymbolFileDWARF::DWZCommonFile::Hasher>
+ SymbolFileDWARF::m_filespec_to_dwzcommonfile;
+std::recursive_mutex SymbolFileDWARF::m_filespec_to_dwzcommonfile_mutex;
+
+void SymbolFileDWARF::InitializeDWZ() {
+ const DWARFDataExtractor §ion_extractor(get_gnu_debugaltlink());
+ if (section_extractor.GetByteSize() == 0)
+ return; // .gnu_debugaltlink does not exist
+ if (GetIsDWZ()) {
+ GetObjectFile()->GetModule()->ReportWarning(
+ "Error reading DWZ common file - it does contain .gnu_debugaltlink");
+ return;
+ }
+ lldb::offset_t offset = 0;
+ const char *link_cstr(section_extractor.GetCStr(&offset));
+ if (!link_cstr) {
+ GetObjectFile()->GetModule()->ReportWarning(
+ "Cannot get DWZ common file - missing section .gnu_debugaltlink");
+ return;
+ }
+ lldb::offset_t uuid_bytes_size = section_extractor.BytesLeft(offset);
+ const void *uuid_bytes(section_extractor.GetData(&offset,uuid_bytes_size));
+ if (!uuid_bytes) {
+ GetObjectFile()->GetModule()->ReportWarning(
+ "Cannot get DWZ common file - missing build-id"
+ " in section .gnu_debugaltlink with string \"%s\"",
+ link_cstr);
+ return;
+ }
+ lldb_private::UUID link_uuid;
+ if (!link_uuid.SetBytes(uuid_bytes,uuid_bytes_size)) {
+ GetObjectFile()->GetModule()->ReportWarning(
+ "Cannot get DWZ common file - invalid build-id size %" PRIu64
+ " in section .gnu_debugaltlink with string \"%s\"",
+ uuid_bytes_size, link_cstr);
+ return;
+ }
+ // For objfile "/usr/lib/debug/usr/bin/true.debug"
+ // link_cstr is "../../.dwz/coreutils-8.25-17.fc25.x86_64".
+ ModuleSpec dwz_module_spec;
+ FileSpec &dwz_fspec = dwz_module_spec.GetFileSpec();
+ dwz_fspec = FileSpec(link_cstr, false /* resolve_path */);
+ dwz_fspec.PrependPathComponent(
+ GetObjectFile()->GetFileSpec().CopyByRemovingLastPathComponent());
+ // C++14: Use heterogenous lookup.
+ DWZCommonFile dwz_fspec_lookup(dwz_fspec);
+ {
+ // C++14: std::shared_lock<std::shared_timed_mutex>
+ std::lock_guard<std::recursive_mutex>
+ guard(m_filespec_to_dwzcommonfile_mutex);
+ const auto it = m_filespec_to_dwzcommonfile.find(dwz_fspec_lookup);
+ if (it != m_filespec_to_dwzcommonfile.end()) {
+ m_dwz_common_file = const_cast<DWZCommonFile *>(&*it);
+ ++m_dwz_common_file->m_use_count;
+ return;
+ }
+ }
+ dwz_module_spec.GetArchitecture() =
+ GetObjectFile()->GetModule()->GetArchitecture();
+ ModuleSP dwz_module = std::make_shared<Module>(dwz_module_spec);
+ DataBufferSP dwz_file_data_sp;
+ lldb::offset_t dwz_file_data_offset = 0;
+ lldb::ObjectFileSP dwz_obj_file = ObjectFile::FindPlugin(
+ dwz_module, &dwz_fspec, 0, dwz_fspec.GetByteSize(),
+ dwz_file_data_sp, dwz_file_data_offset);
+ if (!dwz_obj_file) {
+ GetObjectFile()->GetModule()->ReportWarning(
+ "Cannot get DWZ common file - file \"%s\" cannot be opened",
+ dwz_fspec.GetCString());
+ return;
+ }
+ lldbassert(dwz_obj_file->GetFileSpec() == dwz_fspec);
+ lldb_private::UUID dwz_uuid;
+ if (!dwz_obj_file->GetUUID(&dwz_uuid)) {
+ GetObjectFile()->GetModule()->ReportWarning(
+ "Cannot get DWZ common file - file \"%s\" does not have build-id",
+ dwz_fspec.GetCString());
+ return;
+ }
+ if (link_uuid != dwz_uuid) {
+ GetObjectFile()->GetModule()->ReportWarning(
+ "Cannot get DWZ common file - expected build-id %s but file \"%s\""
+ " has build-id %s",
+ link_uuid.GetAsString().c_str(), dwz_fspec.GetCString(),
+ dwz_uuid.GetAsString().c_str());
+ return;
+ }
+ auto dwz_symbol_file =
+ llvm::make_unique<SymbolFileDWARF>(dwz_obj_file.get());
+ dwz_symbol_file->m_is_dwz = true;
+ dwz_symbol_file->InitializeObject();
+ // Call private DWARFDebugInfo::ParseCompileUnitHeadersIfNeeded() as
+ // otherwise DWARFCompileUnit::GetAbbreviations() would have no data.
+ dwz_symbol_file->DebugInfo()->GetNumCompileUnits();
+ {
+ // C++14: std::lock_guard<std::shared_timed_mutex>
+ std::lock_guard<std::recursive_mutex>
+ guard(m_filespec_to_dwzcommonfile_mutex);
+ const auto it = m_filespec_to_dwzcommonfile.find(dwz_fspec_lookup);
+ if (it != m_filespec_to_dwzcommonfile.end())
+ m_dwz_common_file = const_cast<DWZCommonFile *>(&*it);
+ else {
+ const auto insertpair = m_filespec_to_dwzcommonfile.emplace(
+ std::move(dwz_symbol_file), std::move(dwz_obj_file),
+ std::move(dwz_module));
+ lldbassert(insertpair.second);
+ m_dwz_common_file = const_cast<DWZCommonFile *>(&*insertpair.first);
+ lldbassert(*m_dwz_common_file == dwz_fspec_lookup);
+ }
+ ++m_dwz_common_file->m_use_count;
+ }
+}
+
+void SymbolFileDWARF::DWZCommonFileClear() {
+ if (!m_dwz_common_file)
+ return;
+ // C++14: std::lock_guard<std::shared_timed_mutex>
+ std::lock_guard<std::recursive_mutex>
+ guard(m_filespec_to_dwzcommonfile_mutex);
+ lldbassert(m_dwz_common_file->m_use_count);
+ if (--m_dwz_common_file->m_use_count)
+ return;
+ size_t erased = m_filespec_to_dwzcommonfile.erase(*m_dwz_common_file);
+ lldbassert(erased == 1);
+}
+
+SymbolFileDWARF::DWZCommonFile::DWZCommonFile(
+ const lldb_private::FileSpec &filespec_ref)
+ : m_filespec_ref(filespec_ref) {}
+
+SymbolFileDWARF::DWZCommonFile::DWZCommonFile(
+ std::unique_ptr<SymbolFileDWARF> &&symbol_file,
+ lldb::ObjectFileSP &&obj_file, lldb::ModuleSP &&module)
+ : m_symbol_file(std::move(symbol_file)), m_obj_file(std::move(obj_file)),
+ m_module(std::move(module)), m_filespec_ref(m_obj_file->GetFileSpec()) {}
Index: source/Plugins/SymbolFile/DWARF/DWARFFormValue.h
===================================================================
--- source/Plugins/SymbolFile/DWARF/DWARFFormValue.h
+++ source/Plugins/SymbolFile/DWARF/DWARFFormValue.h
@@ -14,6 +14,7 @@
#include <stddef.h> // for NULL
class DWARFCompileUnit;
+class DWARFFileOffset;
class DWARFFormValue {
public:
@@ -65,7 +66,7 @@
bool ExtractValue(const lldb_private::DWARFDataExtractor &data,
lldb::offset_t *file_offset_ptr);
const uint8_t *BlockData() const;
- uint64_t ReferenceInFile() const;
+ DWARFFileOffset ReferenceInFile() const;
uint64_t Reference() const;
uint64_t Reference(dw_offset_t offset) const;
bool Boolean() const { return m_value.value.uval != 0; }
Index: source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
===================================================================
--- source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
+++ source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
@@ -11,9 +11,12 @@
#include "lldb/Core/dwarf.h"
#include "lldb/Utility/Stream.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Core/Module.h"
#include "DWARFCompileUnit.h"
#include "DWARFFormValue.h"
+#include "DWARFDebugInfo.h"
class DWARFCompileUnit;
@@ -218,6 +221,7 @@
m_value.value.sval = data.GetSLEB128(file_offset_ptr);
break;
case DW_FORM_strp:
+ case DW_FORM_GNU_strp_alt:
assert(m_cu);
m_value.value.uval = data.GetMaxU64(
file_offset_ptr, DWARFCompileUnit::IsDWARF64(m_cu) ? 8 : 4);
@@ -250,6 +254,11 @@
case DW_FORM_ref_udata:
m_value.value.uval = data.GetULEB128(file_offset_ptr);
break;
+ case DW_FORM_GNU_ref_alt:
+ assert(m_cu);
+ ref_addr_size = m_cu->IsDWARF64() ? 8 : 4;
+ m_value.value.uval = data.GetMaxU64(file_offset_ptr, ref_addr_size);
+ break;
case DW_FORM_indirect:
m_form = data.GetULEB128(file_offset_ptr);
indirect = true;
@@ -345,6 +354,13 @@
*file_offset_ptr += ref_addr_size;
return true;
+ case DW_FORM_GNU_ref_alt:
+ assert(cu); // CU must be valid for DW_FORM_GNU_ref_alt objects or we will get
+ // this wrong
+ ref_addr_size = cu->IsDWARF64() ? 8 : 4;
+ *file_offset_ptr += ref_addr_size;
+ return true;
+
// 0 bytes values (implied from DW_FORM)
case DW_FORM_flag_present:
return true;
@@ -365,6 +381,7 @@
// 32 bit for DWARF 32, 64 for DWARF 64
case DW_FORM_sec_offset:
case DW_FORM_strp:
+ case DW_FORM_GNU_strp_alt:
assert(cu);
*file_offset_ptr += (cu->IsDWARF64() ? 8 : 4);
return true;
@@ -506,6 +523,13 @@
case DW_FORM_ref_udata:
cu_relative_offset = true;
break;
+ case DW_FORM_GNU_ref_alt: {
+ assert(m_cu); // CU must be valid for DW_FORM_GNU_ref_alt objects or we will
+ // get this wrong
+ s.Address(uvalue, 4 * 2); // 4 for DWARF32, 8 for DWARF64, but we don't
+ // support DWARF64 yet
+ break;
+ }
// All DW_FORM_indirect attributes should be resolved prior to calling this
// function
@@ -546,6 +570,16 @@
symbol_file->get_debug_str_offsets_data().GetMaxU64(&offset,
index_size);
return symbol_file->get_debug_str_data().PeekCStr(str_offset);
+ } else if (m_form == DW_FORM_GNU_strp_alt) {
+ SymbolFileDWARF *dwz_symbol_file = symbol_file->GetDWZSymbolFile();
+ if (!dwz_symbol_file) {
+ symbol_file->GetObjectFile()->GetModule()->ReportError(
+ "String reference to DWZ offset 0x%8.8" PRIx64
+ " is in a file without associated DWZ common file",
+ m_value.value.uval);
+ return nullptr;
+ }
+ return dwz_symbol_file->get_debug_str_data().PeekCStr(m_value.value.uval);
}
return nullptr;
}
@@ -568,28 +602,33 @@
return symbol_file->get_debug_addr_data().GetMaxU64(&offset, index_size);
}
-uint64_t DWARFFormValue::ReferenceInFile() const {
+DWARFFileOffset DWARFFormValue::ReferenceInFile() const {
uint64_t die_file_offset = m_value.value.uval;
+ assert(m_cu);
+ bool is_dwz = m_cu->GetSymbolFileDWARF()->GetIsDWZ();;
switch (m_form) {
case DW_FORM_ref1:
case DW_FORM_ref2:
case DW_FORM_ref4:
case DW_FORM_ref8:
case DW_FORM_ref_udata:
- assert(m_cu); // CU must be valid for DW_FORM_ref forms that are compile
- // unit relative or we will get this wrong
die_file_offset += m_cu->GetFileOffset();
break;
+ case DW_FORM_GNU_ref_alt: // DWZ
+ is_dwz = true;
+ break;
+
+ case DW_FORM_ref_addr:
default:
break;
}
- return die_file_offset;
+ return DWARFFileOffset(die_file_offset, is_dwz);
}
uint64_t DWARFFormValue::Reference() const {
- uint64_t file = ReferenceInFile();
+ DWARFFileOffset file = ReferenceInFile();
return m_cu->FileOffsetToUniqOffset(file);
}
@@ -713,6 +752,7 @@
case DW_FORM_ref4:
case DW_FORM_ref8:
case DW_FORM_ref_udata: {
+ case DW_FORM_GNU_ref_alt: // DWZ
uint64_t a = a_value.Reference();
uint64_t b = b_value.Reference();
if (a < b)
@@ -761,6 +801,8 @@
case DW_FORM_ref_sig8:
case DW_FORM_GNU_str_index:
case DW_FORM_GNU_addr_index:
+ case DW_FORM_GNU_ref_alt:
+ case DW_FORM_GNU_strp_alt:
return true;
default:
break;
Index: source/Plugins/SymbolFile/DWARF/DWARFFileOffset.h
===================================================================
--- /dev/null
+++ source/Plugins/SymbolFile/DWARF/DWARFFileOffset.h
@@ -0,0 +1,53 @@
+
+//===-- DWARFFileOffset.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFFileOffset_h_
+#define SymbolFileDWARF_DWARFFileOffset_h_
+
+#include "lldb/Core/dwarf.h"
+#include "lldb/Utility/LLDBAssert.h"
+
+class DWARFCompileUnitData;
+class DWARFCompileUnit;
+
+class DWARFFileOffset {
+public:
+ DWARFFileOffset() : m_file_offset(DW_INVALID_OFFSET) {}
+ DWARFFileOffset(dw_offset_t file_offset, bool is_dwz)
+ : m_file_offset(file_offset), m_is_dwz(is_dwz) {}
+ DWARFFileOffset(DWARFCompileUnitData *cudata);
+ DWARFFileOffset(DWARFCompileUnit *cu);
+ dw_offset_t GetFileOffset() const {
+ lldbassert(m_file_offset != DW_INVALID_OFFSET);
+ return m_file_offset;
+ }
+ bool GetIsDWZ() const {
+ lldbassert(m_file_offset != DW_INVALID_OFFSET);
+ return m_is_dwz;
+ }
+ explicit operator bool() const { return m_file_offset != DW_INVALID_OFFSET; }
+
+ friend class Less;
+ struct Less {
+ bool operator()(const DWARFFileOffset &a, const DWARFFileOffset &b) const {
+ if (a.m_is_dwz != b.m_is_dwz)
+ return a.m_is_dwz < b.m_is_dwz;
+ if (a.m_file_offset != b.m_file_offset)
+ return a.m_file_offset < b.m_file_offset;
+ return false;
+ }
+ };
+
+protected:
+ dw_offset_t m_file_offset;
+ bool m_is_dwz;
+};
+
+#endif // SymbolFileDWARF_DWARFFileOffset_h_
Index: source/Plugins/SymbolFile/DWARF/DWARFFileOffset.cpp
===================================================================
--- /dev/null
+++ source/Plugins/SymbolFile/DWARF/DWARFFileOffset.cpp
@@ -0,0 +1,18 @@
+//===-- DWARFFileOffset.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFFileOffset.h"
+#include "DWARFCompileUnit.h"
+
+DWARFFileOffset::DWARFFileOffset(DWARFCompileUnitData *cudata)
+ : m_file_offset(cudata->m_file_offset),
+ m_is_dwz(cudata->m_dwarf2Data->GetIsDWZ()) {}
+
+DWARFFileOffset::DWARFFileOffset(DWARFCompileUnit *cu)
+ : DWARFFileOffset(cu->m_data) {}
Index: source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
===================================================================
--- source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
+++ source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
@@ -112,6 +112,9 @@
else
form_size = cu->IsDWARF64() ? 8 : 4;
break;
+ case DW_FORM_GNU_ref_alt:
+ form_size = cu->IsDWARF64() ? 8 : 4;
+ break;
// 0 sized form
case DW_FORM_flag_present:
@@ -159,6 +162,7 @@
break;
case DW_FORM_strp:
+ case DW_FORM_GNU_strp_alt:
case DW_FORM_sec_offset:
if (cu->IsDWARF64())
debug_info_data.GetU64(&file_offset);
@@ -277,6 +281,9 @@
else
form_size = cu->IsDWARF64() ? 8 : 4;
break;
+ case DW_FORM_GNU_ref_alt:
+ form_size = cu->IsDWARF64() ? 8 : 4;
+ break;
// 0 sized form
case DW_FORM_flag_present:
@@ -324,6 +331,7 @@
break;
case DW_FORM_strp:
+ case DW_FORM_GNU_strp_alt:
case DW_FORM_sec_offset:
if (cu->IsDWARF64())
debug_info_data.GetU64(&file_offset);
Index: source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h
===================================================================
--- source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h
+++ source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h
@@ -61,21 +61,33 @@
DWARFDebugAranges &GetCompileUnitAranges();
+ void InsertCUGetUniqOffset(std::shared_ptr<DWARFCompileUnit> &&cu_sp);
+
protected:
+ typedef std::shared_ptr<DWARFCompileUnit> DWARFCompileUnitSP;
+
static bool OffsetLessThanCompileUnitOffset(dw_offset_t offset,
const DWARFCompileUnitSP &cu_sp);
typedef std::vector<DWARFCompileUnitSP> CompileUnitColl;
+ DWARFDebugInfo *DWZRedirect(dw_offset_t &offset);
+ DWARFCompileUnit *GetCompileUnitInFile(dw_offset_t cu_offset,
+ uint32_t *idx_ptr);
+ DWARFCompileUnit *GetCompileUnitContainingDIEOffsetInFile(
+ dw_offset_t die_offset);
+
//----------------------------------------------------------------------
// Member variables
//----------------------------------------------------------------------
SymbolFileDWARF *m_dwarf2Data;
CompileUnitColl m_compile_units;
std::unique_ptr<DWARFDebugAranges>
m_cu_aranges_ap; // A quick address to compile unit table
- // Protect m_compile_units.
+ // Last offset after existing files for remapping DW_TAG_partial_unit's.
+ dw_offset_t m_dwz_uniq_last = DW_INVALID_OFFSET;
+ // Protect m_compile_units and m_dwz_uniq_last.
// C++14: mutable std::shared_timed_mutex m_dwz_uniq_mutex;
mutable std::recursive_mutex m_dwz_uniq_mutex;
Index: source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
===================================================================
--- source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
+++ source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
@@ -43,6 +43,25 @@
std::lock_guard<std::recursive_mutex> guard(m_dwz_uniq_mutex);
m_dwarf2Data = dwarf2Data;
m_compile_units.clear();
+ SymbolFileDWARF *main_symbol_file = m_dwarf2Data;
+ const DWARFDataExtractor &main_debug_info_data =
+ main_symbol_file->get_debug_info_data();
+ m_dwz_uniq_last = main_debug_info_data.GetByteSize();
+ SymbolFileDWARF *dwz_symbol_file = main_symbol_file->GetDWZSymbolFile();
+ if (dwz_symbol_file) {
+ const DWARFDataExtractor &dwz_debug_info_data =
+ dwz_symbol_file->get_debug_info_data();
+ m_dwz_uniq_last += dwz_debug_info_data.GetByteSize();
+ }
+}
+
+void DWARFDebugInfo::InsertCUGetUniqOffset(DWARFCompileUnitSP &&cu_sp) {
+ lldbassert(!m_dwarf2Data->GetIsDWZ());
+ // C++14: std::lock_guard<std::shared_timed_mutex> guard(m_dwz_uniq_mutex);
+ std::lock_guard<std::recursive_mutex> guard(m_dwz_uniq_mutex);
+ cu_sp->SetOffset(m_dwz_uniq_last);
+ m_dwz_uniq_last += cu_sp->Size() + cu_sp->GetDebugInfoSize();
+ m_compile_units.push_back(std::move(cu_sp));
}
DWARFDebugAranges &DWARFDebugInfo::GetCompileUnitAranges() {
@@ -160,8 +179,26 @@
return offset < cu_sp->GetOffset();
}
+DWARFDebugInfo *DWARFDebugInfo::DWZRedirect(dw_offset_t &offset) {
+ lldbassert(!m_dwarf2Data->GetIsDWZ());
+ if (!m_dwarf2Data->GetDWZSymbolFile())
+ return this;
+ SymbolFileDWARF *dwz_symbol_file = m_dwarf2Data->GetDWZSymbolFile();
+ const DWARFDataExtractor &dwz_debug_info_data =
+ dwz_symbol_file->get_debug_info_data();
+ auto dwz_debug_info_size = dwz_debug_info_data.GetByteSize();
+ if (offset < dwz_debug_info_size)
+ return dwz_symbol_file->DebugInfo();
+ return this;
+}
+
DWARFCompileUnit *DWARFDebugInfo::GetCompileUnit(dw_offset_t cu_offset,
uint32_t *idx_ptr) {
+ return DWZRedirect(cu_offset)->GetCompileUnitInFile(cu_offset, idx_ptr);
+}
+
+DWARFCompileUnit *DWARFDebugInfo::GetCompileUnitInFile(dw_offset_t cu_offset,
+ uint32_t *idx_ptr) {
// C++14: std::shared_lock<std::shared_timed_mutex> guard(m_dwz_uniq_mutex);
std::lock_guard<std::recursive_mutex> guard(m_dwz_uniq_mutex);
DWARFCompileUnitSP cu_sp;
@@ -199,14 +236,21 @@
if (die_ref.cu_offset == DW_INVALID_OFFSET
// FIXME: Workaround default cu_offset = 0 in DIERef ctor.
// Why does GetCompileUnit exist at all?
- || (die_ref.cu_offset == 0 /* && m_dwarf2Data->GetDWZSymbolFile() */ ))
+ || (die_ref.cu_offset == 0 && m_dwarf2Data->GetDWZSymbolFile()))
return GetCompileUnitContainingDIEOffset(die_ref.die_offset);
else
return GetCompileUnit(die_ref.cu_offset);
}
DWARFCompileUnit *
DWARFDebugInfo::GetCompileUnitContainingDIEOffset(dw_offset_t die_offset) {
+ return DWZRedirect(die_offset)->GetCompileUnitContainingDIEOffsetInFile(
+ die_offset);
+}
+
+DWARFCompileUnit *
+DWARFDebugInfo::GetCompileUnitContainingDIEOffsetInFile(
+ dw_offset_t die_offset) {
ParseCompileUnitHeadersIfNeeded();
// C++14: std::shared_lock<std::shared_timed_mutex> guard(m_dwz_uniq_mutex);
@@ -267,6 +311,7 @@
void DWARFDebugInfo::Parse(SymbolFileDWARF *dwarf2Data, Callback callback,
void *userData) {
if (dwarf2Data) {
+ lldbassert(!dwarf2Data->GetIsDWZ());
lldb::offset_t file_offset = 0;
uint32_t depth = 0;
DWARFDebugInfoEntry die;
Index: source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h
===================================================================
--- source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h
+++ source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h
@@ -12,6 +12,7 @@
#include "DWARFDIE.h"
#include "DWARFDebugInfoEntry.h"
+#include "DWARFFileOffset.h"
#include "lldb/lldb-enumerations.h"
#include "lldb/Utility/LLDBAssert.h"
@@ -73,16 +74,28 @@
std::mutex m_extractdies_mutex;
bool m_die_array_finished;
+ std::map<DWARFFileOffset, DWARFCompileUnit *, DWARFFileOffset::Less>
+ m_dwz_file_to_cu;
+
+ // All DW_TAG_partial_unit's extracted for Index-ing this DW_TAG_compile_unit.
+ std::forward_list<DWARFCompileUnit *> m_extracted_pu;
+
+ // Is this object used by more than one DWARFCompileUnit?
+ bool m_any_partial_unit = false;
+
private:
static uint8_t g_default_addr_size;
DISALLOW_COPY_AND_ASSIGN(DWARFCompileUnitData);
};
class DWARFCompileUnit : public DWARFCompileUnitDecls {
public:
+ friend class DWARFFileOffset;
+
static DWARFCompileUnitSP Extract(SymbolFileDWARF *dwarf2Data,
lldb::offset_t *offset_ptr);
+ DWARFCompileUnit(DWARFCompileUnitData *data, DWARFCompileUnit *main_cu);
~DWARFCompileUnit();
enum class ExtractDIEsIfNeededKind {
@@ -100,6 +113,7 @@
void Dump(lldb_private::Stream *s) const;
// Offset of the initial length field.
dw_offset_t GetOffset() const { return m_offset; }
+ void SetOffset(dw_offset_t offset);
lldb::user_id_t GetID() const;
// Size in bytes of the initial length + compile unit header.
uint32_t Size() const { return m_data->m_is_dwarf64 ? 23 : 11; }
@@ -214,25 +228,24 @@
dw_offset_t GetBaseObjOffset() const { return m_data->m_base_obj_offset; }
// DW_TAG_compile_unit with DW_TAG_imported_unit for this DW_TAG_partial_unit.
- DWARFCompileUnit *GetMainCU() const {
- return const_cast<DWARFCompileUnit *>(this);
- }
+ DWARFCompileUnit *GetMainCU() const { return m_main_cu; }
dw_offset_t GetFileOffset() const { return m_data->m_file_offset; }
- dw_offset_t FileOffsetToUniqOffset(dw_offset_t file) const {
- return ThisCUFileOffsetToUniq(file);
- }
- static dw_offset_t ThisCUFileOffsetToUniq_nocheck(dw_offset_t file) {
- return file;
+ dw_offset_t FileOffsetToUniqOffset(DWARFFileOffset file) const;
+ dw_offset_t ThisCUFileOffsetToUniq_nocheck(dw_offset_t file) const {
+ return file + (GetOffset() - GetFileOffset());
}
dw_offset_t ThisCUFileOffsetToUniq(dw_offset_t file) const {
dw_offset_t uniq = ThisCUFileOffsetToUniq_nocheck(file);
lldbassert(ContainsDIEOffset(uniq));
return uniq;
}
dw_offset_t ThisCUUniqToFileOffset(dw_offset_t uniq) const {
lldbassert(ContainsDIEOffset(uniq));
- return uniq;
+ return uniq - (GetOffset() - GetFileOffset());
+ }
+ bool ContainsFileOffset(dw_offset_t file) const {
+ return ContainsDIEOffset(ThisCUFileOffsetToUniq_nocheck(file));
}
dw_offset_t GetNextCompileUnitFileOffset() const {
return ThisCUUniqToFileOffset(GetNextCompileUnitOffset() - 1) + 1;
@@ -249,10 +262,17 @@
NameToDIE &func_selectors, NameToDIE &objc_class_selectors,
NameToDIE &globals, NameToDIE &types, NameToDIE &namespaces);
+ DWARFCompileUnit *InsertFileOffsetGetNewCU(DWARFFileOffset file);
+ DWARFCompileUnit *FileOffsetToCU(DWARFFileOffset file);
+ DWARFCompileUnit *FileOffsetToCULookup(DWARFFileOffset file);
+
DWARFCompileUnitData *m_data;
+ // DW_TAG_compile_unit with DW_TAG_imported_unit for this DW_TAG_partial_unit.
+ DWARFCompileUnit *m_main_cu;
+
// Offset of the initial length field.
- dw_offset_t m_offset;
+ dw_offset_t m_offset = DW_INVALID_OFFSET;
private:
DWARFCompileUnit(SymbolFileDWARF *dwarf2Data);
Index: source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp
===================================================================
--- source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp
+++ source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp
@@ -42,7 +42,14 @@
: m_dwarf2Data(dwarf2Data) {}
DWARFCompileUnit::DWARFCompileUnit(SymbolFileDWARF *dwarf2Data)
- : m_data(dwarf2Data->NewCompileUnitData()) {}
+ : m_data(dwarf2Data->NewCompileUnitData()), m_main_cu(this) {}
+
+DWARFCompileUnit::DWARFCompileUnit(
+ DWARFCompileUnitData *data, DWARFCompileUnit *main_cu)
+ : m_data(data), m_main_cu(main_cu) {
+ m_data->m_any_partial_unit = true;
+ lldbassert(!m_main_cu->m_data->m_dwarf2Data->GetIsDWZ());
+}
DWARFCompileUnit::~DWARFCompileUnit() {}
@@ -58,6 +65,13 @@
m_data->m_file_offset = *file_offset_ptr;
cu_sp->m_offset = m_data->m_file_offset;
+ // All CUs in a base symbol file are shifted after its DWZ file (if exists).
+ SymbolFileDWARF *dwz_symbol_file = dwarf2Data->GetDWZSymbolFile();
+ if (dwz_symbol_file) {
+ const DWARFDataExtractor &dwz_debug_info_data =
+ dwz_symbol_file->get_debug_info_data();
+ cu_sp->m_offset += dwz_debug_info_data.GetByteSize();
+ }
if (debug_info.ValidOffset(*file_offset_ptr)) {
dw_offset_t abbr_offset;
@@ -106,6 +120,11 @@
m_data->m_die_array.swap(tmp_array);
if (keep_compile_unit_die)
m_data->m_die_array.push_back(tmp_array.front());
+
+ while (!m_data->m_extracted_pu.empty()) {
+ m_data->m_extracted_pu.front()->ClearDIEs(keep_compile_unit_die);
+ m_data->m_extracted_pu.pop_front();
+ }
}
if (m_data->m_dwo_symbol_file)
@@ -209,6 +228,9 @@
base_addr = die.GetAttributeValueAsAddress(m_data->m_dwarf2Data, this,
DW_AT_entry_pc, 0);
SetBaseAddress(base_addr);
+ lldbassert(!(die.TagOrig() == DW_TAG_partial_unit
+ && m_main_cu == this
+ && kind == ExtractDIEsIfNeededKind::AllDies));
if (kind == ExtractDIEsIfNeededKind::CuDieOnly)
return 1;
if (kind == ExtractDIEsIfNeededKind::AllDiesButCuDieOnlyForPartialUnits
@@ -713,6 +735,7 @@
case DW_TAG_union_type:
case DW_TAG_unspecified_type:
case DW_TAG_variable:
+ case DW_TAG_imported_unit:
break;
default:
@@ -728,7 +751,7 @@
bool has_location_or_const_value = false;
bool is_global_or_static_variable = false;
- DWARFFormValue specification_die_form;
+ DWARFFormValue specification_die_form, import_die_form;
const size_t num_attributes =
die.GetAttributes(dwarf_cu, fixed_form_sizes, attributes);
if (num_attributes > 0) {
@@ -831,6 +854,11 @@
if (attributes.ExtractFormValueAtIndex(i, form_value))
specification_die_form = form_value;
break;
+
+ case DW_AT_import:
+ if (attributes.ExtractFormValueAtIndex(i, form_value))
+ import_die_form = form_value;
+ break;
}
}
}
@@ -992,6 +1020,49 @@
}
break;
+ case DW_TAG_imported_unit:
+ if (import_die_form.IsValid()) {
+ // DWZ is using DW_TAG_imported_unit only at the top level of CUs.
+ // Therefore GetParent() of any top level DIE in partial unit is always
+ // DW_TAG_compile_unit (possibly after multiple import levels).
+ const DWARFDebugInfoEntry *parent_die = die.GetParent();
+ if (!parent_die || parent_die->Tag() != DW_TAG_compile_unit) {
+ dwarf_cu->GetSymbolFileDWARF()->GetObjectFile()->GetModule()
+ ->ReportError(
+ "CU 0x%8.8" PRIx32 " DIE 0x%8.8" PRIx32
+ " DW_TAG_imported_unit does not have DW_TAG_compile_unit"
+ " as its parent",
+ dwarf_cu->GetOffset(), die.GetOffset(dwarf_cu));
+ break;
+ }
+ DWARFFileOffset import_file = import_die_form.ReferenceInFile();
+ DWARFCompileUnit *main_cu = dwarf_cu->m_main_cu;
+ DWARFCompileUnit *import_cu = main_cu->FileOffsetToCU(import_file);
+ if (!import_cu)
+ break;
+ dw_offset_t import_cu_firstdie_file =
+ import_cu->ThisCUUniqToFileOffset(import_cu->GetFirstDIEOffset());
+ if (import_file.GetFileOffset() != import_cu_firstdie_file) {
+ dwarf_cu->GetSymbolFileDWARF()->GetObjectFile()->GetModule()
+ ->ReportError(
+ "CU 0x%8.8" PRIx32 " DIE 0x%8.8" PRIx32
+ " DW_TAG_imported_unit of DIE 0x%16.16" PRIx32
+ " is not the target CU first DIE 0x%8.8" PRIx32,
+ dwarf_cu->GetOffset(), die.GetOffset(dwarf_cu),
+ import_file.GetFileOffset(), import_cu_firstdie_file);
+ break;
+ }
+ if (import_cu->ExtractDIEsIfNeeded(ExtractDIEsIfNeededKind::AllDies)
+ > 1) {
+ std::lock_guard<std::mutex>
+ guard(main_cu->m_data->m_extractdies_mutex);
+ main_cu->m_data->m_extracted_pu.push_front(import_cu);
+ }
+ import_cu->Index(func_basenames, func_fullnames, func_methods,
+ func_selectors, objc_class_selectors, globals, types, namespaces);
+ }
+ break;
+
default:
continue;
}
@@ -1168,3 +1239,101 @@
lldb::ByteOrder DWARFCompileUnit::GetByteOrder() const {
return m_data->m_dwarf2Data->GetObjectFile()->GetByteOrder();
}
+
+DWARFCompileUnit *DWARFCompileUnit::InsertFileOffsetGetNewCU(
+ DWARFFileOffset file) {
+ lldbassert(m_main_cu == this);
+ lldbassert(file.GetIsDWZ() || !ContainsFileOffset(file.GetFileOffset()));
+ SymbolFileDWARF *main_symbol_file = m_data->m_dwarf2Data;
+ lldbassert(!main_symbol_file->GetIsDWZ());
+ dw_offset_t file_as_uniq = file.GetFileOffset();
+ SymbolFileDWARF *dwz_symbol_file = main_symbol_file->GetDWZSymbolFile();
+ if (!file.GetIsDWZ() && dwz_symbol_file) {
+ // All CUs in a base symbol file are shifted after its DWZ file (if exists).
+ const DWARFDataExtractor &dwz_debug_info_data =
+ dwz_symbol_file->get_debug_info_data();
+ file_as_uniq += dwz_debug_info_data.GetByteSize();
+ }
+ DWARFDebugInfo *main_debuginfo = main_symbol_file->DebugInfo();
+ DWARFCompileUnit *file_cu =
+ main_debuginfo->GetCompileUnitContainingDIEOffset(file_as_uniq);
+ if (!file_cu) {
+ main_symbol_file->GetObjectFile()->GetModule()->ReportError(
+ "There is no CU for DIE file offset 0x%8.8" PRIx32,
+ file.GetFileOffset());
+ return nullptr;
+ }
+ lldbassert(file_cu->m_main_cu == file_cu);
+ auto cu_sp = std::make_shared<DWARFCompileUnit>(file_cu->m_data, this);
+ lldbassert(cu_sp->m_data->m_file_offset != DW_INVALID_OFFSET);
+ DWARFCompileUnit *cu = cu_sp.get();
+ main_debuginfo->InsertCUGetUniqOffset(std::move(cu_sp));
+ DWARFFileOffset file_start = DWARFFileOffset(file_cu);
+ lldbassert(file_start.GetIsDWZ() == file.GetIsDWZ());
+ lldbassert(file_start.GetFileOffset() < file.GetFileOffset());
+ auto insertpair = m_data->m_dwz_file_to_cu.emplace(file_start, cu);
+ lldbassert(insertpair.second);
+ return cu;
+}
+
+DWARFCompileUnit *DWARFCompileUnit::FileOffsetToCULookup(DWARFFileOffset file) {
+ lldbassert(m_main_cu == this);
+ SymbolFileDWARF *main_symbol_file = m_data->m_dwarf2Data;
+ lldbassert(!main_symbol_file->GetIsDWZ());
+ if (!file.GetIsDWZ() && ContainsFileOffset(file.GetFileOffset()))
+ return this;
+ SymbolFileDWARF *file_symbol_file = main_symbol_file;
+ if (file.GetIsDWZ()) {
+ file_symbol_file = main_symbol_file->GetDWZSymbolFile();
+ if (!file_symbol_file) {
+ main_symbol_file->GetObjectFile()->GetModule()->ReportError(
+ "File reference 0x%8.8" PRIx32 " (DWZ file = 1)"
+ " is in a file without associated DWZ common file",
+ file.GetFileOffset());
+ return nullptr;
+ }
+ }
+ const DWARFDataExtractor &file_debug_info_data =
+ file_symbol_file->get_debug_info_data();
+ if (file.GetFileOffset() >= file_debug_info_data.GetByteSize()) {
+ main_symbol_file->GetObjectFile()->GetModule()->ReportError(
+ "File reference 0x%8.8" PRIx32 " (DWZ file = %d)"
+ " does not belong to the file of size 0x%8.8" PRIx64,
+ file.GetFileOffset(), file.GetIsDWZ(),
+ file_debug_info_data.GetByteSize());
+ return nullptr;
+ }
+ auto it = m_data->m_dwz_file_to_cu.upper_bound(file);
+ if (it == m_data->m_dwz_file_to_cu.begin())
+ return nullptr;
+ --it;
+ DWARFCompileUnit *cu = it->second;
+ if (cu->m_data->m_dwarf2Data->GetIsDWZ() != file.GetIsDWZ()
+ || !cu->ContainsFileOffset(file.GetFileOffset()))
+ return nullptr;
+ return cu;
+}
+
+DWARFCompileUnit *DWARFCompileUnit::FileOffsetToCU(DWARFFileOffset file) {
+ DWARFCompileUnit *cu = FileOffsetToCULookup(file);
+ if (!cu) {
+ cu = InsertFileOffsetGetNewCU(file);
+ assert(!cu || cu == FileOffsetToCULookup(file));
+ }
+ return cu;
+}
+
+dw_offset_t DWARFCompileUnit::FileOffsetToUniqOffset(
+ DWARFFileOffset file) const {
+ DWARFCompileUnit *cu = m_main_cu->FileOffsetToCU(file);
+ if (!cu) {
+ // InsertFileOffsetGetNewCU already did ReportError.
+ return file.GetFileOffset();
+ }
+ return cu->ThisCUFileOffsetToUniq(file.GetFileOffset());
+}
+
+void DWARFCompileUnit::SetOffset(dw_offset_t offset) {
+ lldbassert(m_offset == DW_INVALID_OFFSET);
+ m_offset = offset;
+}
Index: source/Plugins/SymbolFile/DWARF/CMakeLists.txt
===================================================================
--- source/Plugins/SymbolFile/DWARF/CMakeLists.txt
+++ source/Plugins/SymbolFile/DWARF/CMakeLists.txt
@@ -24,6 +24,7 @@
DWARFDefines.cpp
DWARFDIE.cpp
DWARFDIECollection.cpp
+ DWARFFileOffset.cpp
DWARFFormValue.cpp
HashedNameToDIE.cpp
LogChannelDWARF.cpp
Index: include/lldb/Utility/FileSpec.h
===================================================================
--- include/lldb/Utility/FileSpec.h
+++ include/lldb/Utility/FileSpec.h
@@ -574,6 +574,14 @@
llvm::sys::fs::file_type file_type, const FileSpec &spec)>
DirectoryCallback;
+ class Hasher {
+ public:
+ size_t operator()(const FileSpec &key) const {
+ return (ConstString::Hasher()(key.m_directory) << 16)
+ ^ ConstString::Hasher()(key.m_filename) ^ key.m_is_resolved;
+ }
+ };
+
protected:
//------------------------------------------------------------------
// Member variables
Index: include/lldb/Utility/ConstString.h
===================================================================
--- include/lldb/Utility/ConstString.h
+++ include/lldb/Utility/ConstString.h
@@ -466,6 +466,18 @@
//------------------------------------------------------------------
static size_t StaticMemorySize();
+ class Hasher {
+ public:
+ size_t operator()(const ConstString &key) const {
+ // https://stackoverflow.com/questions/7666509/hash-function-for-string
+ // C++17: std::string_view
+ size_t hash = 5381;
+ for (const char *p = key.m_string; *p; ++p)
+ hash = hash * 33 + static_cast<uint8_t>(*p);
+ return hash;
+ }
+ };
+
protected:
//------------------------------------------------------------------
// Member variables
_______________________________________________
lldb-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits