jankratochvil updated this revision to Diff 138860.

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/DWARFCompileUnitDWZ.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/DWARFPartialUnit.cpp
  source/Plugins/SymbolFile/DWARF/DWARFPartialUnit.h
  source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
  source/Plugins/SymbolFile/DWARF/DWARFUnit.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
@@ -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,44 @@
 
   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 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
@@ -410,7 +410,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");
@@ -426,6 +428,7 @@
 }
 
 TypeSystem *SymbolFileDWARF::GetTypeSystemForLanguage(LanguageType language) {
+  lldbassert(!GetIsDWZ());
   SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile();
   TypeSystem *type_system;
   if (debug_map_symfile) {
@@ -488,6 +491,8 @@
     else
       m_apple_objc_ap.reset();
   }
+
+  InitializeDWZ();
 }
 
 bool SymbolFileDWARF::SupportedVersion(uint16_t version) {
@@ -2056,6 +2061,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;
       }
@@ -4390,3 +4397,134 @@
   });
   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 &section_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()) {
+      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();
+  {
+    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())
+      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;
+  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
@@ -46,6 +46,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;
@@ -144,17 +145,16 @@
     lldbassert(ContainsDIEOffset(uniq));
     return uniq;
   }
-  dw_offset_t FileOffsetToUniqOffset(dw_offset_t file) const;
+  dw_offset_t FileOffsetToUniqOffset(DWARFFileOffset file) const;
   dw_offset_t ThisCUUniqToFileOffset(dw_offset_t uniq) const;
   bool ContainsFileOffset(dw_offset_t file) const {
     return ContainsDIEOffset(ThisCUFileOffsetToUniq_nocheck(file));
   }
   dw_offset_t GetNextCompileUnitFileOffset() const;
 
   // DW_TAG_compile_unit with DW_TAG_imported_unit for this DW_TAG_partial_unit.
-  DWARFUnit *GetMainCU() const {
-    return const_cast<DWARFUnit *>(this);
-  }
+  virtual DWARFUnit *GetMainCU() = 0;
+  virtual const DWARFUnit *GetMainCU() const = 0;
 
 protected:
   virtual DWARFCompileUnit &Data() = 0;
@@ -171,7 +171,7 @@
                NameToDIE &globals, NameToDIE &types, NameToDIE &namespaces);
 
   // Offset of the initial length field.
-  dw_offset_t m_offset;
+  dw_offset_t m_offset = DW_INVALID_OFFSET;
 
 private:
   const DWARFDebugInfoEntry *GetCompileUnitDIEPtrOnly();
Index: source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
===================================================================
--- source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
+++ source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
@@ -14,6 +14,7 @@
 #include "lldb/Symbol/ObjectFile.h"
 
 #include "DWARFCompileUnit.h"
+#include "DWARFCompileUnitDWZ.h"
 #include "DWARFDebugInfo.h"
 #include "LogChannelDWARF.h"
 #include "SymbolFileDWARFDwo.h"
@@ -280,8 +281,8 @@
   return Data().GetFileOffset();
 }
 
-dw_offset_t DWARFUnit::FileOffsetToUniqOffset(dw_offset_t file) const {
-  return static_cast<const DWARFCompileUnit *>(this)
+dw_offset_t DWARFUnit::FileOffsetToUniqOffset(DWARFFileOffset file) const {
+  return static_cast<const DWARFCompileUnit *>(GetMainCU())
       ->MainCU_FileOffsetToUniqOffset(file);
 }
 
@@ -303,6 +304,11 @@
   return Data().DIEPtr();
 }
 
+void DWARFUnit::SetOffset(dw_offset_t offset) {
+  lldbassert(m_offset == DW_INVALID_OFFSET);
+  m_offset = offset;
+}
+
 void DWARFUnit::Index(NameToDIE &func_basenames,
                              NameToDIE &func_fullnames, NameToDIE &func_methods,
                              NameToDIE &func_selectors,
@@ -313,6 +319,15 @@
          "DWARFUnit associated with .dwo or .dwp "
          "should not be indexed directly");
 
+  // Are we called for DWARFCompileUnit (contrary to DWARFPartialUnit)?
+  if (GetMainCU() == this) {
+    // DWZ DW_TAG_partial_unit will get indexed by DW_AT_import
+    // from its DW_TAG_compile_unit (possibly transitively).
+    const DWARFDebugInfoEntry *die = GetCompileUnitDIEPtrOnly();
+    if (die && die->Tag() == DW_TAG_partial_unit)
+      return;
+  }
+
   Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS));
 
   if (log) {
@@ -325,7 +340,7 @@
   const LanguageType cu_language = GetLanguageType();
   DWARFFormValue::FixedFormSizes fixed_form_sizes =
       DWARFFormValue::GetFixedFormSizesForAddressSize(GetAddressByteSize(),
-                                                      IsDWARF64());
+                                                      Data().m_is_dwarf64);
 
   IndexPrivate(this, cu_language, fixed_form_sizes, GetOffset(), func_basenames,
                func_fullnames, func_methods, func_selectors,
@@ -372,6 +387,7 @@
     case DW_TAG_union_type:
     case DW_TAG_unspecified_type:
     case DW_TAG_variable:
+    case DW_TAG_imported_unit:
       break;
 
     default:
@@ -387,7 +403,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) {
@@ -491,6 +507,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;
         }
       }
     }
@@ -652,6 +673,51 @@
       }
       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(dwarf_cu));
+          break;
+        }
+        DWARFFileOffset import_file = import_die_form.ReferenceInFile();
+        DWARFCompileUnit *main_cu =
+            static_cast<DWARFCompileUnit *>(dwarf_cu->GetMainCU());
+        DWARFUnit *import_cu = main_cu->MainCU_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(false) > 1) {
+          std::lock_guard<std::mutex>
+              guard(main_cu->m_extractdies_mutex);
+          lldbassert(!!main_cu->m_dwz_up);
+          main_cu->m_dwz_up->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;
     }
Index: source/Plugins/SymbolFile/DWARF/DWARFPartialUnit.h
===================================================================
--- /dev/null
+++ source/Plugins/SymbolFile/DWARF/DWARFPartialUnit.h
@@ -0,0 +1,38 @@
+//===-- DWARFPartialUnit.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_DWARFPartialUnit_h_
+#define SymbolFileDWARF_DWARFPartialUnit_h_
+
+#include "DWARFUnit.h"
+#include "DWARFCompileUnit.h"
+
+class DWARFPartialUnit;
+
+typedef std::shared_ptr<DWARFPartialUnit> DWARFPartialUnitSP;
+
+class DWARFPartialUnit : public DWARFUnit {
+public:
+  DWARFPartialUnit(DWARFCompileUnit *cu, DWARFCompileUnit *main_cu);
+
+  // DW_TAG_compile_unit with DW_TAG_imported_unit for this DW_TAG_partial_unit.
+  virtual DWARFUnit *GetMainCU() override { return m_main_cu; }
+  virtual const DWARFUnit *GetMainCU() const override { return m_main_cu; }
+
+protected:
+  virtual DWARFCompileUnit &Data() override { return *m_cu; }
+  virtual const DWARFCompileUnit &Data() const override { return *m_cu; }
+
+private:
+  DWARFCompileUnit *m_cu, *m_main_cu;
+
+  DISALLOW_COPY_AND_ASSIGN(DWARFPartialUnit);
+};
+
+#endif // SymbolFileDWARF_DWARFPartialUnit_h_
Index: source/Plugins/SymbolFile/DWARF/DWARFPartialUnit.cpp
===================================================================
--- /dev/null
+++ source/Plugins/SymbolFile/DWARF/DWARFPartialUnit.cpp
@@ -0,0 +1,16 @@
+//===-- DWARFPartialUnit.cpp ------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFPartialUnit.h"
+
+DWARFPartialUnit::DWARFPartialUnit(
+    DWARFCompileUnit *cu, DWARFCompileUnit *main_cu)
+    : m_cu(cu), m_main_cu(main_cu) {
+  lldbassert(!m_main_cu->m_dwarf2Data->GetIsDWZ());
+}
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 DWARFUnit;
+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,13 @@
 
 #include "lldb/Core/dwarf.h"
 #include "lldb/Utility/Stream.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Core/Module.h"
 
 #include "DWARFUnit.h"
+#include "DWARFFileOffset.h"
 #include "DWARFFormValue.h"
+#include "DWARFDebugInfo.h"
 
 class DWARFUnit;
 
@@ -218,6 +222,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, DWARFUnit::IsDWARF64(m_cu) ? 8 : 4);
@@ -250,6 +255,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 +355,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 +382,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 +524,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 +571,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 +603,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 +753,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 +802,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,51 @@
+
+//===-- 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 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(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,15 @@
+//===-- 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(DWARFCompileUnit *cu)
+    : m_file_offset(cu->GetFileOffset()),
+    m_is_dwz(cu->m_dwarf2Data->GetIsDWZ()) {}
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);
@@ -278,6 +282,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:
@@ -325,6 +332,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
@@ -15,6 +15,7 @@
 
 #include "DWARFUnit.h"
 #include "DWARFDIE.h"
+#include "DWARFPartialUnit.h"
 #include "SymbolFileDWARF.h"
 #include "lldb/Core/STLUtils.h"
 #include "lldb/lldb-private.h"
@@ -61,12 +62,20 @@
 
   DWARFDebugAranges &GetCompileUnitAranges();
 
+  void InsertPUGetUniqOffset(DWARFPartialUnitSP pu_sp);
+
 protected:
+  typedef std::shared_ptr<DWARFCompileUnit> DWARFCompileUnitSP;
+
   static bool OffsetLessThanCompileUnitOffset(dw_offset_t offset,
                                               const DWARFUnitSP &cu_sp);
 
   typedef std::vector<DWARFUnitSP> CompileUnitColl;
 
+  DWARFDebugInfo *DWZRedirect(dw_offset_t &offset);
+  DWARFUnit *GetCompileUnitInFile(dw_offset_t cu_offset, uint32_t *idx_ptr);
+  DWARFUnit *GetCompileUnitContainingDIEOffsetInFile(dw_offset_t die_offset);
+
   //----------------------------------------------------------------------
   // Member variables
   //----------------------------------------------------------------------
@@ -76,7 +85,10 @@
       m_cu_aranges_ap; // A quick address to compile unit table
 
   std::atomic_size_t m_compile_units_size_atomic { 0 };
+  // Protect also m_dwz_uniq_last.
   mutable llvm::sys::RWMutex m_compile_units_mutex;
+  // Last offset after existing files for remapping DW_TAG_partial_unit's.
+  dw_offset_t m_dwz_uniq_last = DW_INVALID_OFFSET;
 
 private:
   // All parsing needs to be done partially any managed by this class as
Index: source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
===================================================================
--- source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
+++ source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
@@ -44,6 +44,25 @@
   m_compile_units_size_atomic = 0;
   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::InsertPUGetUniqOffset(DWARFPartialUnitSP pu_sp) {
+  lldbassert(!m_dwarf2Data->GetIsDWZ());
+  llvm::sys::ScopedWriter lock(m_compile_units_mutex);
+  pu_sp->SetOffset(m_dwz_uniq_last);
+  m_dwz_uniq_last += pu_sp->Size() + pu_sp->GetDebugInfoSize();
+  m_compile_units.push_back(std::move(pu_sp));
+  ++m_compile_units_size_atomic;
 }
 
 DWARFDebugAranges &DWARFDebugInfo::GetCompileUnitAranges() {
@@ -60,6 +79,14 @@
             ".debug_aranges",
             m_dwarf2Data->GetObjectFile()->GetFileSpec().GetPath().c_str());
       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);
     }
 
@@ -150,8 +177,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) {
+  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) {
@@ -196,6 +241,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();
   llvm::sys::ScopedReader lock(m_compile_units_mutex);
 
@@ -257,6 +309,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/DWARFCompileUnitDWZ.h
===================================================================
--- /dev/null
+++ source/Plugins/SymbolFile/DWARF/DWARFCompileUnitDWZ.h
@@ -0,0 +1,40 @@
+//===-- DWARFCompileUnitDWZ.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_DWARFCompileUnitDWZ_h_
+#define SymbolFileDWARF_DWARFCompileUnitDWZ_h_
+
+#include <forward_list>
+#include <map>
+
+#include "DWARFFileOffset.h"
+
+class DWARFFileOffset;
+class DWARFPartialUnit;
+class DWARFUnit;
+
+class DWARFCompileUnitDWZ {
+  friend class DWARFUnit;
+  friend class DWARFCompileUnit;
+
+public:
+  DWARFCompileUnitDWZ() {}
+
+protected:
+  std::map<DWARFFileOffset, DWARFPartialUnit *, 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<DWARFUnit *> m_extracted_pu;
+
+private:
+  DISALLOW_COPY_AND_ASSIGN(DWARFCompileUnitDWZ);
+};
+
+#endif // SymbolFileDWARF_DWARFCompileUnitDWZ_h_
Index: source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h
===================================================================
--- source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h
+++ source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h
@@ -11,10 +11,15 @@
 #define SymbolFileDWARF_DWARFCompileUnit_h_
 
 #include "DWARFUnit.h"
-#include "lldb/Utility/LLDBAssert.h"
+#include "DWARFFileOffset.h"
+
+class DWARFCompileUnitDWZ;
+class DWARFPartialUnit;
 
 class DWARFCompileUnit : public DWARFUnit {
   friend class DWARFUnit;
+  friend class DWARFPartialUnit;
+  friend class DWARFFileOffset;
 
 public:
   static DWARFUnitSP Extract(SymbolFileDWARF *dwarf2Data,
@@ -75,14 +80,16 @@
 
   bool GetIsOptimized();
 
+  // DW_TAG_compile_unit with DW_TAG_imported_unit for this DW_TAG_partial_unit.
+  virtual DWARFUnit *GetMainCU() override { return this; }
+  virtual const DWARFUnit *GetMainCU() const override { return this; }
+
 protected:
   virtual DWARFCompileUnit &Data() override { return *this; }
   virtual const DWARFCompileUnit &Data() const override { return *this; }
 
   dw_offset_t GetFileOffset() const;
-  dw_offset_t MainCU_FileOffsetToUniqOffset(dw_offset_t file) const {
-    return file;
-  }
+  dw_offset_t MainCU_FileOffsetToUniqOffset(DWARFFileOffset file) const;
   dw_offset_t GetNextCompileUnitFileOffset() const {
     return ThisCUUniqToFileOffset(GetNextCompileUnitOffset() - 1) + 1;
   }
@@ -117,11 +124,14 @@
   // If this is a dwo compile unit this is the offset of the base compile unit
   // in the main object file
   dw_offset_t m_base_obj_offset = DW_INVALID_OFFSET;
+  std::unique_ptr<DWARFCompileUnitDWZ> m_dwz_up;
 
   std::mutex m_extractdies_mutex;
 
   void ParseProducerInfo();
 
+  DWARFUnit *MainCU_FileOffsetToCU(DWARFFileOffset file);
+
 private:
   DWARFCompileUnit(SymbolFileDWARF *dwarf2Data);
 
Index: source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp
===================================================================
--- source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp
+++ source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp
@@ -20,6 +20,7 @@
 #include "lldb/Utility/StreamString.h"
 #include "lldb/Utility/Timer.h"
 
+#include "DWARFCompileUnitDWZ.h"
 #include "DWARFDIECollection.h"
 #include "DWARFDebugAbbrev.h"
 #include "DWARFDebugAranges.h"
@@ -51,6 +52,13 @@
   const DWARFDataExtractor &debug_info = dwarf2Data->get_debug_info_data();
 
   cu_sp->m_offset = *file_offset_ptr;
+  // 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;
@@ -101,6 +109,11 @@
       m_die_array.push_back(tmp_array.front());
       ++m_die_array_size_atomic;
     }
+
+    while (m_dwz_up && !m_dwz_up->m_extracted_pu.empty()) {
+      m_dwz_up->m_extracted_pu.front()->ClearDIEs(keep_compile_unit_die);
+      m_dwz_up->m_extracted_pu.pop_front();
+    }
   }
 
   if (m_dwo_symbol_file)
@@ -378,6 +391,10 @@
   // First get the compile unit DIE only and check if it has a DW_AT_ranges
   const DWARFDebugInfoEntry *die = GetCompileUnitDIEPtrOnly();
 
+  // 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;
@@ -643,7 +660,13 @@
 }
 
 dw_offset_t DWARFCompileUnit::GetFileOffset() const {
-  return GetOffset();
+  // 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)
+    return GetOffset();
+  const DWARFDataExtractor &dwz_debug_info_data =
+      dwz_symbol_file->get_debug_info_data();
+  return GetOffset() - dwz_debug_info_data.GetByteSize();
 }
 
 TypeSystem *DWARFCompileUnit::GetTypeSystem() {
@@ -667,3 +690,83 @@
   m_ranges_base = ranges_base;
   m_base_obj_offset = base_obj_offset;
 }
+
+DWARFUnit *DWARFCompileUnit::MainCU_FileOffsetToCU(DWARFFileOffset file) {
+  lldbassert(GetMainCU() == this);
+  if (!file.GetIsDWZ() && ContainsFileOffset(file.GetFileOffset()))
+    return this;
+  SymbolFileDWARF *main_symbol_file = m_dwarf2Data;
+  lldbassert(!main_symbol_file->GetIsDWZ());
+  SymbolFileDWARF *file_symbol_file = main_symbol_file;
+  SymbolFileDWARF *dwz_symbol_file = main_symbol_file->GetDWZSymbolFile();
+  if (file.GetIsDWZ()) {
+    file_symbol_file = dwz_symbol_file;
+    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;
+  }
+  if (m_dwz_up) {
+    auto it = m_dwz_up->m_dwz_file_to_cu.upper_bound(file);
+    if (it != m_dwz_up->m_dwz_file_to_cu.begin()) {
+      --it;
+      DWARFPartialUnit *pu = it->second;
+      if (pu->GetSymbolFileDWARF()->GetIsDWZ() == file.GetIsDWZ()
+	  && pu->ContainsFileOffset(file.GetFileOffset()))
+	return pu;
+    }
+  }
+  dw_offset_t file_as_uniq = file.GetFileOffset();
+  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();
+  DWARFUnit *file_u =
+      main_debuginfo->GetCompileUnitContainingDIEOffset(file_as_uniq);
+  if (!file_u) {
+    main_symbol_file->GetObjectFile()->GetModule()->ReportError(
+       "There is no CU for DIE file offset 0x%8.8" PRIx32,
+       file.GetFileOffset());
+    return nullptr;
+  }
+  lldbassert(file_u->GetMainCU() == file_u);
+  DWARFCompileUnit *file_cu = static_cast<DWARFCompileUnit *>(file_u);
+  auto pu_sp = std::make_shared<DWARFPartialUnit>(file_cu, this);
+  DWARFPartialUnit *pu = pu_sp.get();
+  main_debuginfo->InsertPUGetUniqOffset(std::move(pu_sp));
+  DWARFFileOffset file_start = DWARFFileOffset(file_cu);
+  lldbassert(file_start.GetIsDWZ() == file.GetIsDWZ());
+  lldbassert(file_start.GetFileOffset() < file.GetFileOffset());
+  if (!m_dwz_up)
+    m_dwz_up = llvm::make_unique<DWARFCompileUnitDWZ>();
+  auto insertpair = m_dwz_up->m_dwz_file_to_cu.emplace(file_start, pu);
+  lldbassert(insertpair.second);
+  return pu;
+}
+
+dw_offset_t DWARFCompileUnit::MainCU_FileOffsetToUniqOffset(
+    DWARFFileOffset file) const {
+  DWARFUnit *cu =
+      const_cast<DWARFCompileUnit *>(this)->MainCU_FileOffsetToCU(file);
+  if (!cu) {
+    // MainCU_FileOffsetToCU already did ReportError.
+    return file.GetFileOffset();
+  }
+  return cu->ThisCUFileOffsetToUniq(file.GetFileOffset());
+}
Index: source/Plugins/SymbolFile/DWARF/CMakeLists.txt
===================================================================
--- source/Plugins/SymbolFile/DWARF/CMakeLists.txt
+++ source/Plugins/SymbolFile/DWARF/CMakeLists.txt
@@ -22,7 +22,9 @@
   DWARFDefines.cpp
   DWARFDIE.cpp
   DWARFDIECollection.cpp
+  DWARFFileOffset.cpp
   DWARFFormValue.cpp
+  DWARFPartialUnit.cpp
   DWARFUnit.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
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to