jankratochvil updated this revision to Diff 144639.
https://reviews.llvm.org/D40474
Files:
include/lldb/Utility/ConstString.h
include/lldb/Utility/FileSpec.h
source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h
source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h
source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp
source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h
source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h
source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
source/Plugins/SymbolFile/DWARF/DWARFUnit.h
source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
source/Utility/DataEncoder.cpp
source/Utility/DataExtractor.cpp
Index: source/Utility/DataExtractor.cpp
===================================================================
--- source/Utility/DataExtractor.cpp
+++ source/Utility/DataExtractor.cpp
@@ -232,7 +232,8 @@
if (data != nullptr) {
const uint8_t *data_bytes = data->GetBytes();
if (data_bytes != nullptr) {
- assert(m_start >= data_bytes);
+ // For DWARFDataExtractor::OffsetData we need to return negative value.
+ // assert(m_start >= data_bytes);
return m_start - data_bytes;
}
}
Index: source/Utility/DataEncoder.cpp
===================================================================
--- source/Utility/DataEncoder.cpp
+++ source/Utility/DataEncoder.cpp
@@ -81,7 +81,8 @@
if (data != nullptr) {
const uint8_t *data_bytes = data->GetBytes();
if (data_bytes != nullptr) {
- assert(m_start >= data_bytes);
+ // For DWARFDataExtractor::OffsetData we need to return negative value.
+ // assert(m_start >= data_bytes);
return m_start - data_bytes;
}
}
Index: source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
===================================================================
--- source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -18,10 +18,12 @@
#include <set>
#include <unordered_map>
#include <vector>
+#include <unordered_set>
// Other libraries and framework includes
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/Threading.h"
+#include "llvm/Support/RWMutex.h"
#include "lldb/Utility/Flags.h"
@@ -312,6 +314,13 @@
// the method returns a pointer to the base compile unit.
virtual DWARFUnit *GetBaseCompileUnit();
+ 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 *>
DIEToTypePtr;
@@ -473,6 +482,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);
+ }
+ };
+
+ 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 DWZCommonFileSet(DWZCommonFile *dwz_common_file);
+ void DWZCommonFileClear();
+ static std::unordered_set<DWZCommonFile, DWZCommonFile::Hasher>
+ m_filespec_to_dwzcommonfile;
+ static llvm::sys::RWMutex m_filespec_to_dwzcommonfile_mutex;
+ bool m_is_dwz = false;
+
lldb::ModuleWP m_debug_map_module_wp;
SymbolFileDWARFDebugMap *m_debug_map_symfile;
Index: source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
===================================================================
--- source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -411,7 +411,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");
@@ -427,6 +429,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) {
@@ -595,6 +600,13 @@
DWARFDataSegment &data_segment) {
llvm::call_once(data_segment.m_flag, [this, sect_type, &data_segment] {
this->LoadSectionData(sect_type, std::ref(data_segment.m_data));
+ if (sect_type == eSectionTypeDWARFDebugInfo && m_dwz_common_file) {
+ SymbolFileDWARF *dwz_symbol_file = m_dwz_common_file->SymbolFile();
+ const DWARFDataExtractor &dwz_debug_info_data =
+ dwz_symbol_file->get_debug_info_data();
+ lldbassert(dwz_debug_info_data.GetByteSize());
+ data_segment.m_data.OffsetData(dwz_debug_info_data.GetByteSize());
+ }
});
return data_segment.m_data;
}
@@ -2057,6 +2069,8 @@
if (dwarf_cu) {
// dwarf_cu->ExtractDIEsIfNeeded(false) will return zero if the
// DIEs for a compile unit have already been parsed.
+ // While DW_TAG_partial_unit will not be indexed directly each such
+ // unit will be used by some other unit of this SymbolFileDWARF.
if (dwarf_cu->ExtractDIEsIfNeeded(false) > 1)
clear_cu_dies[cu_idx] = true;
}
@@ -4389,3 +4403,159 @@
});
return m_dwp_symfile.get();
}
+
+std::unordered_set<SymbolFileDWARF::DWZCommonFile,
+ SymbolFileDWARF::DWZCommonFile::Hasher>
+ SymbolFileDWARF::m_filespec_to_dwzcommonfile;
+llvm::sys::RWMutex 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);
+ {
+ llvm::sys::ScopedReader lock(m_filespec_to_dwzcommonfile_mutex);
+ const auto it = m_filespec_to_dwzcommonfile.find(dwz_fspec_lookup);
+ if (it != m_filespec_to_dwzcommonfile.end()) {
+ DWZCommonFileSet(const_cast<DWZCommonFile *>(&*it));
+ 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();
+ {
+ llvm::sys::ScopedWriter lock(m_filespec_to_dwzcommonfile_mutex);
+ const auto it = m_filespec_to_dwzcommonfile.find(dwz_fspec_lookup);
+ if (it != m_filespec_to_dwzcommonfile.end())
+ DWZCommonFileSet(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);
+ DWZCommonFileSet(const_cast<DWZCommonFile *>(&*insertpair.first));
+ lldbassert(*m_dwz_common_file == dwz_fspec_lookup);
+ }
+ }
+}
+
+void SymbolFileDWARF::DWZCommonFileSet(DWZCommonFile *dwz_common_file) {
+ if (m_dwz_common_file == dwz_common_file)
+ return;
+ DWZCommonFileClear();
+ m_dwz_common_file = dwz_common_file;
+ ++m_dwz_common_file->m_use_count;
+
+ // GetCachedSectionData calls OffsetData as m_dwarf_data is not yet fetched.
+}
+
+void SymbolFileDWARF::DWZCommonFileClear() {
+ if (!m_dwz_common_file)
+ return;
+ SymbolFileDWARF *dwz_symbol_file = m_dwz_common_file->SymbolFile();
+
+ DWARFDebugInfo *dwz_debuginfo = dwz_symbol_file->DebugInfo();
+ if (dwz_debuginfo) {
+ const size_t dwz_num_cus = dwz_debuginfo->GetNumCompileUnits();
+ for (size_t dwz_cu_idx = 0; dwz_cu_idx < dwz_num_cus; ++dwz_cu_idx) {
+ DWARFUnit *dwz_cu = dwz_debuginfo->GetCompileUnitAtIndex(dwz_cu_idx);
+ if (dwz_cu)
+ dwz_cu->DWZDeleteSymbolFile(this);
+ }
+ }
+
+ const DWARFDataExtractor &dwz_debug_info_data =
+ dwz_symbol_file->get_debug_info_data();
+ lldbassert(dwz_debug_info_data.GetByteSize());
+ m_dwarf_data.OffsetData(-dwz_debug_info_data.GetByteSize());
+
+ llvm::sys::ScopedWriter lock(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/DWARFUnit.h
===================================================================
--- source/Plugins/SymbolFile/DWARF/DWARFUnit.h
+++ source/Plugins/SymbolFile/DWARF/DWARFUnit.h
@@ -15,6 +15,8 @@
#include "lldb/lldb-enumerations.h"
#include "llvm/Support/RWMutex.h"
+#include <forward_list>
+
class DWARFUnit;
class DWARFCompileUnit;
class NameToDIE;
@@ -134,9 +136,10 @@
dw_offset_t GetBaseObjOffset() const;
// DW_TAG_compile_unit with DW_TAG_imported_unit for this DW_TAG_partial_unit.
- DWARFUnit *GetMainCU() const {
- return const_cast<DWARFUnit *>(this);
- }
+ DWARFUnit *GetMainCU() { return m_main_cu; }
+ const DWARFUnit *GetMainCU() const { return m_main_cu; }
+ void SetMainCU(DWARFUnit *new_main_cu);
+ void DWZDeleteSymbolFile(SymbolFileDWARF *symbol_file);
protected:
DWARFUnit(SymbolFileDWARF *dwarf);
@@ -167,6 +170,15 @@
// in the main object file
dw_offset_t m_base_obj_offset = DW_INVALID_OFFSET;
llvm::sys::RWMutex m_extractdies_mutex;
+ // All DW_TAG_partial_unit's extracted for Index-ing this DW_TAG_compile_unit.
+ std::forward_list<DWARFUnit *> m_extracted_pu;
+ // DW_TAG_compile_unit with DW_TAG_imported_unit for this DW_TAG_partial_unit.
+ std::atomic<DWARFUnit *> m_main_cu;
+ // It is used for restoring valid m_main_cu if its current SymbolFileDWARF
+ // gets removed. Then choose any DWARFUnit from any other file which also
+ // DW_TAG_imported_unit this DW_TAG_partial_unit.
+ std::unordered_map<SymbolFileDWARF *, DWARFUnit *> m_main_cu_map;
+ llvm::sys::RWMutex m_main_cu_map_mutex;
static void
IndexPrivate(DWARFUnit *dwarf_cu, const lldb::LanguageType cu_language,
Index: source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
===================================================================
--- source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
+++ source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
@@ -31,7 +31,8 @@
extern int g_verbose;
-DWARFUnit::DWARFUnit(SymbolFileDWARF *dwarf) : m_dwarf(dwarf) {}
+DWARFUnit::DWARFUnit(SymbolFileDWARF *dwarf)
+ : m_dwarf(dwarf), m_main_cu(this) {}
DWARFUnit::~DWARFUnit() {}
@@ -333,6 +334,11 @@
m_die_array.swap(tmp_array);
if (keep_compile_unit_die)
m_die_array.push_back(tmp_array.front());
+
+ while (!m_extracted_pu.empty()) {
+ m_extracted_pu.front()->ClearDIEs(keep_compile_unit_die);
+ m_extracted_pu.pop_front();
+ }
}
if (m_dwo_symbol_file)
@@ -350,6 +356,10 @@
// First get the compile unit DIE only and check if it has a DW_AT_ranges
const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly();
+ // DWZ partial units never contain PC.
+ if (die && die->Tag() == DW_TAG_partial_unit)
+ return;
+
const dw_offset_t cu_offset = GetOffset();
if (die) {
DWARFRangeList ranges;
@@ -496,7 +506,10 @@
// Don't specify the compile unit offset as we don't know it because the
// DIE belongs to
// a different compile unit in the same symbol file.
- return GetMainCU()->m_dwarf->DebugInfo()->GetDIEForDIEOffset(die_offset);
+ DWARFDIE die =
+ GetMainCU()->m_dwarf->DebugInfo()->GetDIEForDIEOffset(die_offset);
+ die.GetCU()->SetMainCU(GetMainCU());
+ return die;
}
}
m_dwarf->GetObjectFile()->GetModule()->ReportError(
@@ -677,6 +690,18 @@
"DWARFUnit associated with .dwo or .dwp "
"should not be indexed directly");
+ // Are we called for DW_TAG_compile_unit (contrary to DW_TAG_partial_unit)?
+ if (GetMainCU() == this) {
+ // DWZ DW_TAG_partial_unit will get indexed by DW_AT_import
+ // from its DW_TAG_compile_unit (possibly transitively).
+ // GetUnitDIEPtrOnly() is too expensive.
+ if (GetSymbolFileDWARF()->GetIsDWZ())
+ return;
+ const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly();
+ if (die && die->Tag() == DW_TAG_partial_unit)
+ return;
+ }
+
Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS));
if (log) {
@@ -734,6 +759,7 @@
case DW_TAG_union_type:
case DW_TAG_unspecified_type:
case DW_TAG_variable:
+ case DW_TAG_imported_unit:
break;
default:
@@ -749,7 +775,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) {
@@ -841,6 +867,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;
}
}
}
@@ -999,12 +1030,102 @@
}
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
+ && parent_die->Tag() != DW_TAG_partial_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());
+ break;
+ }
+ dw_offset_t import_offset = import_die_form.Reference();
+ DWARFUnit *main_cu = dwarf_cu->GetMainCU();
+ DWARFDebugInfo *main_debuginfo =
+ main_cu->GetSymbolFileDWARF()->DebugInfo();
+ DWARFUnit *import_cu =
+ main_debuginfo->GetCompileUnitContainingDIEOffset(import_offset);
+ if (!import_cu)
+ break;
+ dw_offset_t import_cu_firstdie_offset = import_cu->GetFirstDIEOffset();
+ if (import_offset != import_cu_firstdie_offset) {
+ 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(),
+ import_offset, import_cu_firstdie_offset);
+ break;
+ }
+ import_cu->SetMainCU(main_cu);
+ if (import_cu->ExtractDIEsIfNeeded(false) > 1) {
+ llvm::sys::ScopedWriter lock(main_cu->m_extractdies_mutex);
+ main_cu->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;
}
}
}
+void DWARFUnit::SetMainCU(DWARFUnit *new_main_cu) {
+ if (new_main_cu == this)
+ return;
+ if (m_main_cu == new_main_cu)
+ return;
+ if (m_main_cu != this
+ && (*m_main_cu).GetSymbolFileDWARF() == new_main_cu->GetSymbolFileDWARF())
+ return;
+ const DWARFDebugInfoEntry *die = GetUnitDIEPtrOnly();
+ if (!die || die->Tag() != DW_TAG_partial_unit)
+ return;
+ bool found;
+ {
+ llvm::sys::ScopedReader lock(m_main_cu_map_mutex);
+ found = m_main_cu_map.find(new_main_cu->GetSymbolFileDWARF())
+ != m_main_cu_map.cend();
+ }
+ if (found)
+ lldbassert(m_main_cu != this);
+ else {
+ llvm::sys::ScopedWriter lock(m_main_cu_map_mutex);
+ DWARFUnit *&ref =
+ m_main_cu_map[new_main_cu->GetSymbolFileDWARF()];
+ if (ref)
+ lldbassert(m_main_cu != this);
+ else {
+ ref = new_main_cu;
+ if (m_main_cu == this)
+ m_main_cu = new_main_cu;
+ }
+ }
+}
+
+void DWARFUnit::DWZDeleteSymbolFile(SymbolFileDWARF *symbol_file) {
+ llvm::sys::ScopedWriter lock(m_main_cu_map_mutex);
+ if (!m_main_cu_map.erase(symbol_file))
+ return;
+ if ((*m_main_cu).GetSymbolFileDWARF() != symbol_file)
+ return;
+ if (!m_main_cu_map.empty())
+ m_main_cu = m_main_cu_map.cbegin()->second;
+ else
+ m_main_cu = this;
+}
+
const DWARFDebugAranges &DWARFUnit::GetFunctionAranges() {
if (m_func_aranges_ap.get() == NULL) {
m_func_aranges_ap.reset(new DWARFDebugAranges());
Index: source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
===================================================================
--- source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
+++ source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
@@ -10,10 +10,14 @@
#include <assert.h>
#include "lldb/Core/dwarf.h"
+#include "lldb/Utility/LLDBAssert.h"
#include "lldb/Utility/Stream.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Core/Module.h"
#include "DWARFUnit.h"
#include "DWARFFormValue.h"
+#include "DWARFDebugInfo.h"
class DWARFUnit;
@@ -218,6 +222,7 @@
m_value.value.sval = data.GetSLEB128(offset_ptr);
break;
case DW_FORM_strp:
+ case DW_FORM_GNU_strp_alt:
assert(m_cu);
m_value.value.uval =
data.GetMaxU64(offset_ptr, DWARFUnit::IsDWARF64(m_cu) ? 8 : 4);
@@ -250,6 +255,11 @@
case DW_FORM_ref_udata:
m_value.value.uval = data.GetULEB128(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(offset_ptr, ref_addr_size);
+ break;
case DW_FORM_indirect:
m_form = data.GetULEB128(offset_ptr);
indirect = true;
@@ -344,6 +354,13 @@
*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;
+ *offset_ptr += ref_addr_size;
+ return true;
+
// 0 bytes values (implied from DW_FORM)
case DW_FORM_flag_present:
return true;
@@ -364,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);
*offset_ptr += (cu->IsDWARF64() ? 8 : 4);
return true;
@@ -505,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
@@ -545,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;
}
@@ -569,21 +604,67 @@
uint64_t DWARFFormValue::Reference() const {
uint64_t die_offset = m_value.value.uval;
+ assert(m_cu);
+ SymbolFileDWARF *cu_symbol_file = m_cu->GetSymbolFileDWARF();
+ bool is_dwz = cu_symbol_file->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_offset += m_cu->GetOffset();
+ // The offset adjustment is already appropriate inside this CU.
+ return die_offset;
+
+ case DW_FORM_GNU_ref_alt:
+ if (is_dwz)
+ cu_symbol_file->GetObjectFile()->GetModule()->ReportError(
+ "DW_FORM_GNU_ref_alt to DWZ offset 0x%8.8" PRIx64
+ " is in a DWZ common file itself",
+ die_offset);
+ is_dwz = true;
break;
+ case DW_FORM_ref_addr:
default:
break;
}
+ if (!is_dwz) {
+ lldbassert(!cu_symbol_file->GetIsDWZ());
+ SymbolFileDWARF *dwz_symbol_file = cu_symbol_file->GetDWZSymbolFile();
+ if (dwz_symbol_file) {
+ // All CUs in a base symbol file are shifted after its DWZ file.
+ const DWARFDataExtractor &dwz_debug_info_data =
+ dwz_symbol_file->get_debug_info_data();
+ die_offset += dwz_debug_info_data.GetByteSize();
+ }
+ }
+
+ if (!m_cu->ContainsDIEOffset(die_offset)) {
+ SymbolFileDWARF *target_symbol_file = cu_symbol_file;
+ if (is_dwz && !target_symbol_file->GetIsDWZ()) {
+ target_symbol_file = cu_symbol_file->GetDWZSymbolFile();
+ if (!target_symbol_file) {
+ cu_symbol_file->GetObjectFile()->GetModule()->ReportError(
+ "There is Reference to DWZ offset 0x%8.8" PRIx64
+ " but the DWZ common file is missing",
+ die_offset);
+ target_symbol_file = cu_symbol_file;
+ }
+ }
+ lldbassert(is_dwz == target_symbol_file->GetIsDWZ());
+ DWARFDebugInfo *target_debuginfo = target_symbol_file->DebugInfo();
+ // FIXME: This is expensive for files containing no DWZ.
+ // But there is no way to easily find in advance if this file has been
+ // DWZ-processed (in the case of DWARF <=4).
+ DWARFUnit *target_cu =
+ target_debuginfo->GetCompileUnitContainingDIEOffsetInFile(die_offset);
+ if (target_cu)
+ target_cu->SetMainCU(const_cast<DWARFUnit *>(m_cu->GetMainCU()));
+ }
+
return die_offset;
}
@@ -707,6 +788,7 @@
case DW_FORM_ref4:
case DW_FORM_ref8:
case DW_FORM_ref_udata: {
+ case DW_FORM_GNU_ref_alt:
uint64_t a = a_value.Reference();
uint64_t b = b_value.Reference();
if (a < b)
@@ -755,6 +837,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/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(&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(&offset);
Index: source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h
===================================================================
--- source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h
+++ source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h
@@ -40,6 +40,8 @@
DWARFUnit *GetCompileUnitAtIndex(uint32_t idx);
DWARFUnit *GetCompileUnit(dw_offset_t cu_offset, uint32_t *idx_ptr = NULL);
DWARFUnit *GetCompileUnitContainingDIEOffset(dw_offset_t die_offset);
+ // Used only by DWARFFormValue::Reference().
+ DWARFUnit *GetCompileUnitContainingDIEOffsetInFile(dw_offset_t die_offset);
DWARFUnit *GetCompileUnit(const DIERef &die_ref);
DWARFDIE GetDIEForDIEOffset(dw_offset_t die_offset);
DWARFDIE GetDIE(const DIERef &die_ref);
@@ -66,6 +68,9 @@
typedef std::vector<DWARFUnitSP> CompileUnitColl;
+ DWARFDebugInfo *DWZRedirect(dw_offset_t offset);
+ DWARFUnit *GetCompileUnitInFile(dw_offset_t cu_offset, uint32_t *idx_ptr);
+
//----------------------------------------------------------------------
// Member variables
//----------------------------------------------------------------------
Index: source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
===================================================================
--- source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
+++ source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
@@ -14,6 +14,7 @@
#include "lldb/Host/PosixApi.h"
#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Utility/LLDBAssert.h"
#include "lldb/Utility/RegularExpression.h"
#include "lldb/Utility/Stream.h"
#include "lldb/Core/Module.h"
@@ -57,7 +58,16 @@
"DWARFDebugInfo::GetCompileUnitAranges() for \"%s\" from "
".debug_aranges",
m_dwarf2Data->GetObjectFile()->GetFileSpec().GetPath().c_str());
- m_cu_aranges_ap->Extract(debug_aranges_data);
+ dw_offset_t dwz_offset = 0;
+ lldbassert(!m_dwarf2Data->GetIsDWZ());
+ SymbolFileDWARF *dwz_symbol_file = m_dwarf2Data->GetDWZSymbolFile();
+ if (dwz_symbol_file) {
+ const DWARFDataExtractor &dwz_debug_info_data =
+ dwz_symbol_file->get_debug_info_data();
+ auto dwz_debug_info_size = dwz_debug_info_data.GetByteSize();
+ dwz_offset += dwz_debug_info_size;
+ }
+ m_cu_aranges_ap->Extract(debug_aranges_data, dwz_offset);
}
// Make a list of all CUs represented by the arange data in the file.
@@ -100,6 +110,14 @@
if (m_compile_units.empty()) {
if (m_dwarf2Data != NULL) {
lldb::offset_t offset = 0;
+ // All CUs in a base symbol file are shifted after its DWZ file (if exists).
+ SymbolFileDWARF *dwz_symbol_file = m_dwarf2Data->GetDWZSymbolFile();
+ if (dwz_symbol_file) {
+ const DWARFDataExtractor &dwz_debug_info_data =
+ dwz_symbol_file->get_debug_info_data();
+ offset += dwz_debug_info_data.GetByteSize();
+ }
+
DWARFUnitSP cu_sp;
while ((cu_sp = DWARFCompileUnit::Extract(m_dwarf2Data, &offset))) {
m_compile_units.push_back(cu_sp);
@@ -140,8 +158,26 @@
return offset < cu_sp->GetOffset();
}
+DWARFDebugInfo *DWARFDebugInfo::DWZRedirect(dw_offset_t offset) {
+ lldbassert(!m_dwarf2Data->GetIsDWZ());
+ SymbolFileDWARF *dwz_symbol_file = m_dwarf2Data->GetDWZSymbolFile();
+ if (!dwz_symbol_file)
+ return this;
+ 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;
+}
+
DWARFUnit *DWARFDebugInfo::GetCompileUnit(dw_offset_t cu_offset,
- uint32_t *idx_ptr) {
+ uint32_t *idx_ptr) {
+ return DWZRedirect(cu_offset)->GetCompileUnitInFile(cu_offset, idx_ptr);
+}
+
+DWARFUnit *DWARFDebugInfo::GetCompileUnitInFile(dw_offset_t cu_offset,
+ uint32_t *idx_ptr) {
DWARFUnitSP cu_sp;
uint32_t cu_idx = DW_INVALID_INDEX;
if (cu_offset != DW_INVALID_OFFSET) {
@@ -185,6 +221,13 @@
DWARFUnit *
DWARFDebugInfo::GetCompileUnitContainingDIEOffset(dw_offset_t die_offset) {
+ return DWZRedirect(die_offset)->GetCompileUnitContainingDIEOffsetInFile(
+ die_offset);
+}
+
+DWARFUnit *
+DWARFDebugInfo::GetCompileUnitContainingDIEOffsetInFile(
+ dw_offset_t die_offset) {
ParseCompileUnitHeadersIfNeeded();
DWARFUnitSP cu_sp;
@@ -245,7 +288,16 @@
void DWARFDebugInfo::Parse(SymbolFileDWARF *dwarf2Data, Callback callback,
void *userData) {
if (dwarf2Data) {
+ lldbassert(!dwarf2Data->GetIsDWZ());
lldb::offset_t offset = 0;
+ // 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();
+ offset += dwz_debug_info_data.GetByteSize();
+ }
+
uint32_t depth = 0;
DWARFDebugInfoEntry die;
Index: source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h
===================================================================
--- source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h
+++ source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h
@@ -30,7 +30,8 @@
void Clear() { m_aranges.Clear(); }
- bool Extract(const lldb_private::DWARFDataExtractor &debug_aranges_data);
+ bool Extract(const lldb_private::DWARFDataExtractor &debug_aranges_data,
+ dw_offset_t dwz_offset);
bool Generate(SymbolFileDWARF *dwarf2Data);
Index: source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp
===================================================================
--- source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp
+++ source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp
@@ -48,16 +48,18 @@
//----------------------------------------------------------------------
// Extract
//----------------------------------------------------------------------
-bool DWARFDebugAranges::Extract(const DWARFDataExtractor &debug_aranges_data) {
+bool DWARFDebugAranges::Extract(
+ const DWARFDataExtractor &debug_aranges_data, dw_offset_t dwz_offset) {
if (debug_aranges_data.ValidOffset(0)) {
lldb::offset_t offset = 0;
DWARFDebugArangeSet set;
Range range;
while (set.Extract(debug_aranges_data, &offset)) {
const uint32_t num_descriptors = set.NumDescriptors();
if (num_descriptors > 0) {
- const dw_offset_t cu_offset = set.GetCompileUnitDIEOffset();
+ const dw_offset_t cu_offset = set.GetCompileUnitDIEOffset()
+ + dwz_offset;
for (uint32_t i = 0; i < num_descriptors; ++i) {
const DWARFDebugArangeSet::Descriptor &descriptor =
Index: source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h
===================================================================
--- source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h
+++ source/Plugins/SymbolFile/DWARF/DWARFDataExtractor.h
@@ -32,6 +32,28 @@
bool IsDWARF64() const { return m_is_dwarf64; }
+ //------------------------------------------------------------------
+ /// Slide the data in the buffer so that access to the data will
+ /// start at offset \a offset.
+ ///
+ /// This is currently used to provide access to the .debug_types
+ /// section and pretend it starts at at offset of the size of the
+ /// .debug_info section. This allows a minimally invasive change to
+ /// add support for .debug_types by allowing all DIEs to have unique
+ /// offsets and thus allowing no code to change in the DWARF parser.
+ /// Modifying the offsets in the .debug_types doesn't affect
+ /// anything because since all info in the .debug_types is type unit
+ /// relative and no types within a type unit can refer to any DIEs
+ /// outside of the type unit without using DW_AT_signature. It also
+ /// sets us up to move to DWARF5 where there is no .debug_types
+ /// section as compile units and type units are in the .debug_info.
+ //------------------------------------------------------------------
+ void OffsetData(lldb::offset_t offset)
+ {
+ if (GetByteSize())
+ m_start -= offset;
+ }
+
protected:
mutable bool m_is_dwarf64;
};
Index: source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h
===================================================================
--- source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h
+++ source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h
@@ -13,8 +13,6 @@
#include "DWARFUnit.h"
class DWARFCompileUnit : public DWARFUnit {
- friend class DWARFUnit;
-
public:
static DWARFUnitSP Extract(SymbolFileDWARF *dwarf2Data,
lldb::offset_t *offset_ptr);
Index: include/lldb/Utility/FileSpec.h
===================================================================
--- include/lldb/Utility/FileSpec.h
+++ include/lldb/Utility/FileSpec.h
@@ -567,6 +567,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